VSCode Language Server Protocol client implementation for extension integration with language servers
—
Transport configuration and message handling for different communication channels between client and server.
Configuration for various transport mechanisms in Node.js environments.
/**
* Available transport mechanisms for Node.js
*/
enum TransportKind {
/** Standard input/output streams */
stdio,
/** Inter-process communication */
ipc,
/** Named pipes */
pipe,
/** TCP sockets */
socket
}
/**
* Transport configuration union type
*/
type Transport = SocketTransport | { kind: TransportKind.stdio | TransportKind.ipc | TransportKind.pipe };
/**
* Socket transport configuration
*/
interface SocketTransport {
/** Transport type identifier */
kind: TransportKind.socket;
/** Port number for socket connection */
port: number;
}Usage Examples:
Standard I/O transport:
const serverOptions: ServerOptions = {
command: 'language-server',
transport: TransportKind.stdio
};Socket transport:
const serverOptions: ServerOptions = {
command: 'language-server',
transport: { kind: TransportKind.socket, port: 8080 }
};IPC transport:
const serverOptions: ServerOptions = {
module: './server.js',
transport: TransportKind.ipc
};Configuration for running language servers as external executables.
/**
* Configuration for executable language servers
*/
interface Executable {
/** Command to execute (e.g., 'node', 'python', 'java') */
command: string;
/** Command line arguments passed to the executable */
args?: string[];
/** Transport mechanism for communication */
transport?: Transport;
/** Additional execution options */
options?: ExecutableOptions;
}
/**
* Options for executable processes
*/
interface ExecutableOptions {
/** Current working directory for the process */
cwd?: string;
/** Environment variables for the process */
env?: NodeJS.ProcessEnv;
/** Whether to detach the process */
detached?: boolean;
/** Shell to use for command execution */
shell?: boolean | string;
}Usage Examples:
Simple executable:
const executable: Executable = {
command: 'my-language-server',
args: ['--stdio', '--log-level', 'info']
};Executable with custom environment:
const executable: Executable = {
command: 'java',
args: ['-jar', 'language-server.jar'],
options: {
cwd: '/path/to/server',
env: {
...process.env,
JAVA_OPTS: '-Xmx512m'
}
}
};Configuration for language servers implemented as Node.js modules.
/**
* Configuration for Node.js module language servers
*/
interface NodeModule {
/** Path to the Node.js module (relative or absolute) */
module: string;
/** Arguments passed to the module */
args?: string[];
/** Transport mechanism for communication */
transport?: Transport;
/** Node.js runtime executable path (defaults to 'node') */
runtime?: string;
/** Fork options for the child process */
options?: ForkOptions;
}
/**
* Options for forking Node.js processes
*/
interface ForkOptions {
/** Current working directory */
cwd?: string;
/** Environment variables */
env?: NodeJS.ProcessEnv;
/** Additional execution arguments for Node.js runtime */
execArgv?: string[];
/** Whether to use silent mode */
silent?: boolean;
/** File descriptors for stdio */
stdio?: string | string[];
/** Whether to detach the process */
detached?: boolean;
/** User ID to run the process as */
uid?: number;
/** Group ID to run the process as */
gid?: number;
}Usage Examples:
Basic Node module:
const nodeModule: NodeModule = {
module: './dist/server.js',
transport: TransportKind.ipc
};Node module with custom runtime:
const nodeModule: NodeModule = {
module: 'typescript-language-server',
args: ['--stdio'],
runtime: '/usr/local/bin/node',
options: {
env: { ...process.env, TS_NODE_PROJECT: './tsconfig.json' }
}
};Direct stream configuration for custom transport scenarios.
/**
* Stream-based communication configuration
*/
interface StreamInfo {
/** Writable stream for sending messages to server */
writer: NodeJS.WritableStream;
/** Readable stream for receiving messages from server */
reader: NodeJS.ReadableStream;
/** Whether the streams are detached from client lifecycle */
detached?: boolean;
}
/**
* Child process information with metadata
*/
interface ChildProcessInfo {
/** The spawned child process */
process: ChildProcess;
/** Whether the process is detached from client lifecycle */
detached?: boolean;
}Usage Examples:
Custom stream setup:
import { spawn } from 'child_process';
const serverProcess = spawn('my-server', ['--pipe']);
const streamInfo: StreamInfo = {
reader: serverProcess.stdout,
writer: serverProcess.stdin,
detached: false
};Low-level message transport interfaces for custom communication.
/**
* Message transport configuration
*/
interface MessageTransports {
/** Message reader for receiving from server */
reader: MessageReader;
/** Message writer for sending to server */
writer: MessageWriter;
/** Whether the transport is detached from client lifecycle */
detached?: boolean;
}
/**
* Interface for reading LSP messages
*/
interface MessageReader {
/** Event fired when a message is received */
readonly onError: Event<Error>;
/** Event fired when the reader is closed */
readonly onClose: Event<void>;
/** Event fired when a partial message is received */
readonly onPartialMessage: Event<PartialMessageInfo>;
/** Start listening for messages */
listen(callback: DataCallback): Disposable;
/** Dispose the reader */
dispose(): void;
}
/**
* Interface for writing LSP messages
*/
interface MessageWriter {
/** Event fired when an error occurs during writing */
readonly onError: Event<[Error, Message | undefined, number | undefined]>;
/** Event fired when the writer is closed */
readonly onClose: Event<void>;
/** Write a message */
write(msg: Message): Promise<void>;
/** End the writer */
end(): void;
/** Dispose the writer */
dispose(): void;
}Browser-specific transport using Web Workers.
/**
* Browser message reader using Web Worker communication
*/
class BrowserMessageReader implements MessageReader {
constructor(worker: Worker);
readonly onError: Event<Error>;
readonly onClose: Event<void>;
readonly onPartialMessage: Event<PartialMessageInfo>;
listen(callback: DataCallback): Disposable;
dispose(): void;
}
/**
* Browser message writer using Web Worker communication
*/
class BrowserMessageWriter implements MessageWriter {
constructor(worker: Worker);
readonly onError: Event<[Error, Message | undefined, number | undefined]>;
readonly onClose: Event<void>;
write(msg: Message): Promise<void>;
end(): void;
dispose(): void;
}Usage Examples:
Browser client with Web Worker:
import { LanguageClient, BrowserMessageReader, BrowserMessageWriter } from "vscode-languageclient/browser";
const worker = new Worker('./language-server-worker.js');
const client = new LanguageClient(
'browser-client',
'Browser Language Client',
clientOptions,
worker
);Utility functions for creating transport instances.
/**
* Create client pipe transport for named pipe communication
*/
function createClientPipeTransport(pipeName: string, encoding?: string): Promise<MessageTransports>;
/**
* Generate a random pipe name for IPC
*/
function generateRandomPipeName(): string;
/**
* Create client socket transport for TCP communication
*/
function createClientSocketTransport(port: number, encoding?: string): Promise<MessageTransports>;
/**
* Stream message reader for Node.js streams
*/
class StreamMessageReader implements MessageReader {
constructor(readable: NodeJS.ReadableStream, encoding?: string);
}
/**
* Stream message writer for Node.js streams
*/
class StreamMessageWriter implements MessageWriter {
constructor(writable: NodeJS.WritableStream, encoding?: string);
}
/**
* IPC message reader for inter-process communication
*/
class IPCMessageReader implements MessageReader {
constructor(process: NodeJS.Process | ChildProcess);
}
/**
* IPC message writer for inter-process communication
*/
class IPCMessageWriter implements MessageWriter {
constructor(process: NodeJS.Process | ChildProcess);
}Usage Examples:
Custom pipe transport:
const pipeName = generateRandomPipeName();
const transport = await createClientPipeTransport(pipeName);
const client = new LanguageClient(
'pipe-client',
'Pipe Language Client',
() => Promise.resolve(transport),
clientOptions
);Socket transport:
const transport = await createClientSocketTransport(8080);
const client = new LanguageClient(
'socket-client',
'Socket Language Client',
() => Promise.resolve(transport),
clientOptions
);Install with Tessl CLI
npx tessl i tessl/npm-vscode-languageclient