Language Server Protocol implementation for Node.js providing comprehensive LSP server capabilities including text synchronization, diagnostics, code completion, and workspace symbol searching
—
Notebook document synchronization and management for Jupyter notebooks and other notebook formats. Supports both notebook-level and cell-level text document management with comprehensive lifecycle tracking.
A manager for notebook documents that handles both notebook-level events and individual cell text documents.
/**
* A manager for notebook documents that tracks both notebooks and their cell text documents
*/
class NotebookDocuments<T extends { uri: DocumentUri }> {
/**
* Create a new notebook documents manager
* @param configurationOrTextDocuments Either a text documents configuration or an existing TextDocuments instance
*/
constructor(configurationOrTextDocuments: TextDocumentsConfiguration<T> | TextDocuments<T>);
/** Event fired when a notebook document has been opened */
readonly onDidOpen: Event<NotebookDocument>;
/** Event fired when a notebook document has changed */
readonly onDidChange: Event<NotebookDocumentChangeEvent>;
/** Event fired when a notebook document has been saved */
readonly onDidSave: Event<NotebookDocument>;
/** Event fired when a notebook document has been closed */
readonly onDidClose: Event<NotebookDocument>;
/**
* Returns the text document for the given cell URI
* @param cellUri The URI of the notebook cell
*/
getCellTextDocument(cellUri: DocumentUri): T | undefined;
/**
* Returns the notebook document for the given notebook URI
* @param notebookUri The URI of the notebook document
*/
getNotebookDocument(notebookUri: DocumentUri): NotebookDocument | undefined;
/**
* Returns the notebook cell for the given cell URI
* @param cellUri The URI of the notebook cell
*/
getNotebookCell(cellUri: DocumentUri): NotebookCell | undefined;
/**
* Listens for notebook synchronization notifications and cell text document changes
* @param connection The connection to listen on
*/
listen(connection: Connection): void;
}Usage Example:
import { NotebookDocuments, createConnection } from "vscode-languageserver";
import { TextDocument } from "vscode-languageserver-textdocument";
// Create connection and notebook documents manager
const connection = createConnection();
const notebooks = new NotebookDocuments(TextDocument);
// Listen for notebook events
notebooks.onDidOpen(notebook => {
console.log(`Notebook opened: ${notebook.uri}`);
console.log(`Cells: ${notebook.cells.length}`);
});
notebooks.onDidChange(event => {
console.log(`Notebook changed: ${event.notebook.uri}`);
event.contentChanges.forEach(change => {
console.log(`Changed cells: ${change.cells?.length || 0}`);
});
});
notebooks.onDidSave(notebook => {
console.log(`Notebook saved: ${notebook.uri}`);
});
notebooks.onDidClose(notebook => {
console.log(`Notebook closed: ${notebook.uri}`);
});
// Connect notebooks to the connection
notebooks.listen(connection);
// Access notebook and cell documents
const notebook = notebooks.getNotebookDocument("file:///path/to/notebook.ipynb");
const cell = notebooks.getNotebookCell("vscode-notebook-cell:/path/to/notebook.ipynb#cell1");
const cellDocument = notebooks.getCellTextDocument("vscode-notebook-cell:/path/to/notebook.ipynb#cell1");Feature interface for handling notebook synchronization events directly through the connection.
/**
* Notebook synchronization feature for handling notebook lifecycle events
*/
interface NotebookSyncFeatureShape {
synchronization: {
/** Register handler for notebook open notifications */
onDidOpenNotebookDocument(handler: NotificationHandler1<DidOpenNotebookDocumentParams>): Disposable;
/** Register handler for notebook change notifications */
onDidChangeNotebookDocument(handler: NotificationHandler1<DidChangeNotebookDocumentParams>): Disposable;
/** Register handler for notebook save notifications */
onDidSaveNotebookDocument(handler: NotificationHandler1<DidSaveNotebookDocumentParams>): Disposable;
/** Register handler for notebook close notifications */
onDidCloseNotebookDocument(handler: NotificationHandler1<DidCloseNotebookDocumentParams>): Disposable;
};
}Direct Usage Example:
// Access via connection.notebooks.synchronization
connection.notebooks.synchronization.onDidOpenNotebookDocument(params => {
console.log(`Notebook opened: ${params.notebookDocument.uri}`);
params.cellTextDocuments.forEach(cell => {
console.log(`Cell: ${cell.uri} (${cell.languageId})`);
});
});
connection.notebooks.synchronization.onDidChangeNotebookDocument(params => {
console.log(`Notebook changed: ${params.notebookDocument.uri}`);
params.change.cells?.structure?.array?.forEach(change => {
console.log(`Cell operation: ${change.start} +${change.deleteCount} ${change.cells?.length || 0}`);
});
});Core interfaces for notebook documents and cells.
/**
* A notebook document represents a collection of cells
*/
interface NotebookDocument {
/** The notebook document's URI */
uri: DocumentUri;
/** The type of the notebook */
notebookType: string;
/** The version number of this document */
version: number;
/** Additional metadata stored with the notebook */
metadata?: LSPObject;
/** The cells of a notebook */
cells: NotebookCell[];
}
/**
* A notebook cell represents a single cell in a notebook
*/
interface NotebookCell {
/** The cell's kind */
kind: NotebookCellKind;
/** The URI of the cell's text document content */
document: DocumentUri;
/** Additional metadata stored with the cell */
metadata?: LSPObject;
/** Additional execution summary information if supported by the client */
executionSummary?: ExecutionSummary;
}
/**
* The kind of a notebook cell
*/
enum NotebookCellKind {
/** A markup cell is formatted source that is used for display */
Markup = 1,
/** A code cell is source code */
Code = 2
}
/**
* Execution summary for a notebook cell
*/
interface ExecutionSummary {
/** A strict monotonically increasing value indicating the execution order of a cell inside a notebook */
executionOrder?: number;
/** Whether the execution was successful or not if known by the client */
success?: boolean;
}Detailed change information for notebook updates.
/**
* Parameters for notebook open notifications
*/
interface DidOpenNotebookDocumentParams {
/** The notebook document that got opened */
notebookDocument: NotebookDocument;
/** The text documents that represent the content of a notebook cell */
cellTextDocuments: TextDocumentItem[];
}
/**
* Parameters for notebook change notifications
*/
interface DidChangeNotebookDocumentParams {
/** The notebook document that did change */
notebookDocument: VersionedNotebookDocumentIdentifier;
/** The actual changes to the notebook document */
change: NotebookDocumentChangeEvent;
}
/**
* Parameters for notebook save notifications
*/
interface DidSaveNotebookDocumentParams {
/** The notebook document that got saved */
notebookDocument: NotebookDocumentIdentifier;
}
/**
* Parameters for notebook close notifications
*/
interface DidCloseNotebookDocumentParams {
/** The notebook document that got closed */
notebookDocument: NotebookDocumentIdentifier;
/** The text documents that represent the content of a notebook cell that got closed */
cellTextDocuments: TextDocumentIdentifier[];
}
/**
* A change event for a notebook document
*/
interface NotebookDocumentChangeEvent {
/** The changed metadata if any */
metadata?: LSPObject;
/** Changes to cells */
cells?: {
/** Changes to the cell structure to add or remove cells */
structure?: {
/** The change to the number of cells in the document */
array: NotebookCellArrayChange;
/** Additional opened cell text documents */
didOpen?: TextDocumentItem[];
/** Additional closed cell text documents */
didClose?: TextDocumentIdentifier[];
};
/** Changes to notebook cells */
data?: NotebookCell[];
/** Changes to the text content of notebook cells */
textContent?: {
document: VersionedTextDocumentIdentifier;
changes: TextDocumentContentChangeEvent[];
}[];
};
}
/**
* A change describing how to move a notebook cell array from state S to S'
*/
interface NotebookCellArrayChange {
/** The start offset of the cell that changed */
start: number;
/** The deleted cells */
deleteCount: number;
/** The new cells, if any */
cells?: NotebookCell[];
}Identification interfaces for notebook documents.
/**
* A literal to identify a notebook document in the client
*/
interface NotebookDocumentIdentifier {
/** The notebook document's URI */
uri: DocumentUri;
}
/**
* A versioned notebook document identifier
*/
interface VersionedNotebookDocumentIdentifier extends NotebookDocumentIdentifier {
/** The version number of this notebook document */
version: number;
}Notebook cells are backed by text documents, allowing for seamless integration with existing text document features.
// Notebook cells can be accessed as regular text documents
const cellDocument = notebooks.getCellTextDocument("vscode-notebook-cell:/path/to/notebook.ipynb#cell1");
// Use with existing text document features
connection.onHover((params) => {
// Check if this is a notebook cell URI
if (params.textDocument.uri.startsWith("vscode-notebook-cell:")) {
const cellDocument = notebooks.getCellTextDocument(params.textDocument.uri);
const cell = notebooks.getNotebookCell(params.textDocument.uri);
if (cellDocument && cell) {
// Provide hover information for notebook cell
return {
contents: `Notebook cell (${cell.kind === NotebookCellKind.Code ? 'Code' : 'Markdown'})`
};
}
}
return null;
});type DocumentUri = string;
type LSPObject = { [key: string]: any };
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 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;
}
type NotificationHandler1<P> = (params: P) => void;
type Event<T> = (listener: (e: T) => any, thisArg?: any) => Disposable;
interface Disposable {
dispose(): void;
}Install with Tessl CLI
npx tessl i tessl/npm-vscode-languageserver