Language Server Protocol implementation for Node.js providing comprehensive LSP server capabilities including text synchronization, diagnostics, code completion, and workspace symbol searching
—
Text document lifecycle management and synchronization between client and server. The document management system handles document open, change, save, and close events with automatic synchronization.
A manager for simple text documents that automatically synchronizes document state between client and server.
/**
* A manager for simple text documents. Requires at minimum that the server
* registered for document open/close and change events.
*/
class TextDocuments<T extends { uri: DocumentUri }> {
/**
* Create a new text document manager
* @param configuration Configuration for creating and updating documents
*/
constructor(configuration: TextDocumentsConfiguration<T>);
/** Event fired when a text document managed by this manager has been opened */
readonly onDidOpen: Event<TextDocumentChangeEvent<T>>;
/** Event fired when a text document managed by this manager has been closed */
readonly onDidClose: Event<TextDocumentChangeEvent<T>>;
/** Event fired when a text document managed by this manager has changed */
readonly onDidChangeContent: Event<TextDocumentChangeEvent<T>>;
/** Event fired when a text document managed by this manager has been saved */
readonly onDidSave: Event<TextDocumentChangeEvent<T>>;
/** Event fired when a text document managed by this manager will be saved */
readonly onWillSave: Event<TextDocumentWillSaveEvent<T>>;
/**
* Returns the document for the given URI. Returns undefined if the document
* is not managed by this instance.
*/
get(uri: DocumentUri): T | undefined;
/** Returns all documents managed by this instance */
all(): T[];
/** Returns the URIs of all documents managed by this instance */
keys(): DocumentUri[];
/**
* Listens for low level notification on the given connection to update
* the text documents managed by this instance.
*/
listen(connection: TextDocumentConnection): void;
}Usage Examples:
import { TextDocuments, createConnection } from "vscode-languageserver";
import { TextDocument } from "vscode-languageserver-textdocument";
// Create connection and documents manager
const connection = createConnection();
const documents = new TextDocuments(TextDocument);
// Listen for document events
documents.onDidOpen(event => {
console.log(`Document opened: ${event.document.uri}`);
validateDocument(event.document);
});
documents.onDidChangeContent(change => {
console.log(`Document changed: ${change.document.uri}`);
validateDocument(change.document);
});
documents.onDidSave(event => {
console.log(`Document saved: ${event.document.uri}`);
});
documents.onDidClose(event => {
console.log(`Document closed: ${event.document.uri}`);
});
// Connect documents to the connection
documents.listen(connection);
// Access documents
const document = documents.get("file:///path/to/file.txt");
const allDocuments = documents.all();Configuration interface for creating and updating text documents.
/**
* Configuration interface for text document creation and updates
*/
interface TextDocumentsConfiguration<T extends { uri: DocumentUri }> {
/**
* Creates a new text document
* @param uri The document's URI
* @param languageId The document's language id
* @param version The document's version
* @param content The document's content
*/
create(uri: DocumentUri, languageId: string, version: number, content: string): T;
/**
* Updates an existing text document
* @param document The document to update
* @param changes The changes to apply
* @param version The new version number
*/
update(document: T, changes: TextDocumentContentChangeEvent[], version: number): T;
}Event interfaces for document lifecycle notifications.
/**
* Event to signal changes to a text document
*/
interface TextDocumentChangeEvent<T> {
/** The document that has changed */
document: T;
}
/**
* Event to signal that a document will be saved
*/
interface TextDocumentWillSaveEvent<T> {
/** The document that will be saved */
document: T;
/** The reason why save was triggered */
reason: TextDocumentSaveReason;
}
/**
* Represents reasons why a text document is saved
*/
enum TextDocumentSaveReason {
/** Manually triggered, e.g. by the user pressing save, by starting debugging, or by an API call */
Manual = 1,
/** Automatic after a delay */
AfterDelay = 2,
/** When the editor lost focus */
FocusOut = 3
}Interface for connecting to text document notifications.
/**
* Interface for receiving text document notifications
*/
interface TextDocumentConnection {
/** Register handler for document open notifications */
onDidOpenTextDocument(handler: NotificationHandler<DidOpenTextDocumentParams>): Disposable;
/** Register handler for document change notifications */
onDidChangeTextDocument(handler: NotificationHandler<DidChangeTextDocumentParams>): Disposable;
/** Register handler for document close notifications */
onDidCloseTextDocument(handler: NotificationHandler<DidCloseTextDocumentParams>): Disposable;
/** Register handler for document will save notifications */
onWillSaveTextDocument(handler: NotificationHandler<WillSaveTextDocumentParams>): Disposable;
/** Register handler for document will save wait until requests */
onWillSaveTextDocumentWaitUntil(
handler: RequestHandler<WillSaveTextDocumentParams, TextEdit[] | undefined | null, void>
): Disposable;
/** Register handler for document save notifications */
onDidSaveTextDocument(handler: NotificationHandler<DidSaveTextDocumentParams>): Disposable;
}Detailed change information for document updates.
/**
* Event for text document content changes
*/
interface TextDocumentContentChangeEvent {
/** The range of the document that changed */
range?: Range;
/** The optional length of the range that got replaced */
rangeLength?: number;
/** The new text for the provided range or the whole document */
text: string;
}
/**
* Parameters for document open notifications
*/
interface DidOpenTextDocumentParams {
/** The document that was opened */
textDocument: TextDocumentItem;
}
/**
* Parameters for document change notifications
*/
interface DidChangeTextDocumentParams {
/** The document that did change */
textDocument: VersionedTextDocumentIdentifier;
/** The actual content changes */
contentChanges: TextDocumentContentChangeEvent[];
}
/**
* Parameters for document close notifications
*/
interface DidCloseTextDocumentParams {
/** The document that was closed */
textDocument: TextDocumentIdentifier;
}
/**
* Parameters for document save notifications
*/
interface DidSaveTextDocumentParams {
/** The document that was saved */
textDocument: TextDocumentIdentifier;
/** Optional the content when saved. Depends on the includeText value when save registration was requested */
text?: string;
}
/**
* Parameters for document will save notifications
*/
interface WillSaveTextDocumentParams {
/** The document that will be saved */
textDocument: TextDocumentIdentifier;
/** The reason why save was triggered */
reason: TextDocumentSaveReason;
}Direct document synchronization through the connection interface.
// Via connection.languages interface
interface Languages {
/** Handle document open notifications */
onDidOpenTextDocument(handler: NotificationHandler<DidOpenTextDocumentParams>): Disposable;
/** Handle document change notifications */
onDidChangeTextDocument(handler: NotificationHandler<DidChangeTextDocumentParams>): Disposable;
/** Handle document close notifications */
onDidCloseTextDocument(handler: NotificationHandler<DidCloseTextDocumentParams>): Disposable;
/** Handle document will save notifications */
onWillSaveTextDocument(handler: NotificationHandler<WillSaveTextDocumentParams>): Disposable;
/** Handle document will save wait until requests */
onWillSaveTextDocumentWaitUntil(
handler: RequestHandler<WillSaveTextDocumentParams, TextEdit[] | undefined | null, void>
): Disposable;
/** Handle document save notifications */
onDidSaveTextDocument(handler: NotificationHandler<DidSaveTextDocumentParams>): Disposable;
}Direct Usage Example:
import { createConnection } from "vscode-languageserver";
const connection = createConnection();
// Handle document events directly through connection
connection.onDidOpenTextDocument(params => {
console.log(`Document opened: ${params.textDocument.uri}`);
});
connection.onDidChangeTextDocument(params => {
console.log(`Document changed: ${params.textDocument.uri}`);
console.log(`Changes: ${params.contentChanges.length}`);
});
connection.onWillSaveTextDocumentWaitUntil(params => {
// Return text edits to apply before saving
return [
{
range: { start: { line: 0, character: 0 }, end: { line: 0, character: 0 } },
newText: "// Auto-generated header\n"
}
];
});type DocumentUri = string;
interface TextDocumentItem {
/** The text document's URI */
uri: DocumentUri;
/** The text document's language identifier */
languageId: string;
/** The version number of this document */
version: number;
/** The content of the opened text document */
text: string;
}
interface TextDocumentIdentifier {
/** The text document's URI */
uri: DocumentUri;
}
interface VersionedTextDocumentIdentifier extends TextDocumentIdentifier {
/** The version number of this document */
version: number;
}
interface Position {
/** Line position in a document (zero-based) */
line: number;
/** Character offset on a line in a document (zero-based) */
character: number;
}
interface Range {
/** The range's start position */
start: Position;
/** The range's end position */
end: Position;
}
interface TextEdit {
/** The range of the text document to be manipulated */
range: Range;
/** The string to be inserted. For delete operations use an empty string */
newText: string;
}
type Event<T> = (listener: (e: T) => any, thisArg?: any) => Disposable;
type NotificationHandler<P> = (params: P) => void;
type RequestHandler<P, R, E> = (
params: P,
token: CancellationToken,
workDoneProgress: WorkDoneProgressReporter,
partialResultProgress: ResultProgressReporter<Partial<R>>
) => HandlerResult<R, E>;Install with Tessl CLI
npx tessl i tessl/npm-vscode-languageserver