Search code examples
visual-studio-codevscode-extensionslanguage-server-protocol

VSCode: obtain editor content in Language Server


I'm trying to develop a Language Server to a new language in VS Code and I'm using the Microsoft sample as reference (https://github.com/microsoft/vscode-extension-samples/tree/master/lsp-sample).

In their sample the autocompletion is done in this chunk of code:

connection.onCompletion(
    (_textDocumentPosition: TextDocumentPositionParams): CompletionItem[] => {
        // The pass parameter contains the position of the text document in
        // which code complete got requested. For the example we ignore this
        // info and always provide the same completion items. 
        return [
            {
                label: 'TypeScript',
                kind: CompletionItemKind.Text,
                data: 1
            },
            {
                label: 'JavaScript',
                kind: CompletionItemKind.Text,
                data: 2
            }
        ];
    }
);

As the comment says, it's a dumb autocompletion system, since it always provides the same suggestions.

I can see that there's an input parameter of type TextDocumentPositionParams and this type has the following interface:

export interface TextDocumentPositionParams {
    /**
     * The text document.
     */
    textDocument: TextDocumentIdentifier;
    /**
     * The position inside the text document.
     */
    position: Position;
}

It has the cursor position and a TextDocumentIdentifier but the last only has a uri property.

I want to create an intelligent autocomplete system, based on the type of the object of the word in the cursor position.

This sample is very limited and I'm kinda lost here. I guess I could read the file in the uri property and based on the cursor position I could figure out which items I should suggest. But how about when the file is not saved? If I read the file I would read the data that is on disk, and not what is currently shown in the editor.

What's the best approach to do that?


Solution

  • The Language Server Protocol supports text synchronization, see TextDocumentSyncOptions in ServerCapabilities and the corresponding methods (textDocument/didChange, didChange, didClose...). A Language Server will usually keep a copy of all open documents in memory.

    The sample you linked actually makes use of this, but the synchronization itself is abstracted away into the TextDocuments class from vscode-languageserver. As a result server.ts doesn't have to do much more than this:

    let documents: TextDocuments = new TextDocuments();
    [...]
    documents.listen(connection);
    

    You can then simply use documents.get(uri).getText() to obtain the text shown in the editor.