LSP Text Document Implementation
The `vscode-languageserver-textdocument` package provides a lightweight and immutable in-memory representation of a text document, specifically designed for use within Node.js-based Language Server Protocol (LSP) servers. It abstracts away the complexities of file system interactions, offering a consistent model for document content, versioning, and change tracking. This is a foundational utility within the larger `vscode-languageserver-node` monorepo, which is actively maintained by Microsoft. While the monorepo sees frequent `next` releases (e.g., `10.0.0-next.x` for server components), `vscode-languageserver-textdocument` itself is currently stable at version `1.0.12`, indicating a mature and less frequently changing API for its core document management functions. It is written in TypeScript and ships with comprehensive type definitions, making it well-suited for TypeScript-first development environments. Its primary differentiator is its focus on being a simple, efficient, and reliable document model optimized for LSP server operations like diagnostics, completions, and refactoring.
Common errors
-
TypeError: TextDocument.create is not a function
cause Attempting to call `create` on a CommonJS `require` import where `TextDocument` might not be the default export or incorrectly destructured.fixEnsure you are using ESM named imports: `import { TextDocument } from 'vscode-languageserver-textdocument';` if your environment supports it. If strictly in CJS, try `const TextDocument = require('vscode-languageserver-textdocument').TextDocument;` or `const { TextDocument } = require('vscode-languageserver-textdocument');` if the package provides CJS interop. -
Cannot read properties of undefined (reading 'getText')
cause This typically occurs when a `TextDocument` variable is `undefined` or `null` because document creation failed, or it was not properly initialized before attempting to access its methods.fixVerify that `TextDocument.create` successfully returned a document instance and that your logic correctly handles the lifecycle of document objects, ensuring they are always valid when accessed. Check for missing input parameters to `create` or incorrect logic flow.
Warnings
- breaking Version 1.0.3 and later target ES2020. This might introduce breaking changes for environments not supporting ES2020 features, potentially requiring updated Node.js versions or additional transpilation steps in your build process.
- gotcha TextDocument instances are immutable. Methods like `TextDocument.applyEdits` do not modify the original document but return a *new* `TextDocument` instance with the changes applied. Failing to reassign or use the new instance will lead to working with stale document content.
- gotcha This package is part of the `vscode-languageserver-node` monorepo. While `vscode-languageserver-textdocument` is relatively stable, the broader monorepo often publishes `next` versions for its server and client packages. Be mindful of version compatibility when integrating with other `@vscode/languageserver-*` packages, as their `next` releases might introduce changes that could affect broader server logic, even if not directly breaking `textdocument`'s API.
Install
-
npm install vscode-languageserver-textdocument -
yarn add vscode-languageserver-textdocument -
pnpm add vscode-languageserver-textdocument
Imports
- TextDocument
const { TextDocument } = require('vscode-languageserver-textdocument');import { TextDocument } from 'vscode-languageserver-textdocument'; - TextDocument.create
import * as TextDocumentModule from 'vscode-languageserver-textdocument'; const doc = TextDocumentModule.create(uri, languageId, version, text);
import { TextDocument } from 'vscode-languageserver-textdocument'; const doc = TextDocument.create(uri, languageId, version, text); - TextDocument.applyEdits
import { TextDocument } from 'vscode-languageserver-textdocument'; oldDoc.applyEdits(changes); // TextDocument instances are immutableimport { TextDocument } from 'vscode-languageserver-textdocument'; const newDoc = TextDocument.applyEdits(oldDoc, changes);
Quickstart
import { TextDocument } from 'vscode-languageserver-textdocument';
import { Position, Range, TextEdit } from 'vscode-languageserver-types';
// 1. Create an initial document
const uri = 'file:///path/to/example.ts';
const languageId = 'typescript';
const version = 1;
const initialText = 'console.log("Hello");\nconst x = 10;';
let document = TextDocument.create(uri, languageId, version, initialText);
console.log(`Initial Document (v${document.version}):\n${document.getText()}`);
console.log(`Line Count: ${document.lineCount}`);
// 2. Simulate an edit: Change 'Hello' to 'World'
const changeRange: Range = {
start: Position.create(0, 13),
end: Position.create(0, 18)
};
const newText = 'World';
const edits: TextEdit[] = [
TextEdit.replace(changeRange, newText)
];
// 3. Apply the edits to get a new document instance
const newVersion = document.version + 1;
const updatedDocument = TextDocument.applyEdits(document, edits);
// Important: The original document is unchanged
console.log(`\nOriginal Document (still v${document.version}):\n${document.getText()}`);
// The updated document reflects the changes
console.log(`\nUpdated Document (v${updatedDocument.version}):\n${updatedDocument.getText()}`);
// Example of getting position from offset and vice-versa
const offset = updatedDocument.offsetAt(Position.create(1, 6)); // 'x' in 'const x = 10;'
const position = updatedDocument.positionAt(offset);
console.log(`\nOffset of 'x': ${offset}, Position: { line: ${position.line}, character: ${position.character} }`);