Language Server Protocol

repository·gh-pages·Indexed 11 days ago

https://github.com/microsoft/language-server-protocol

A standardized communication protocol using JSON-RPC that enables inter-process communication between development tools (clients) and language-specific intelligence (servers). The documentation covers the Base Protocol specification, LSIF (Language Server Index Format) graph-based data modeling, and core LSP lifecycle events such as document synchronization and 'Go to Definition' requests.

Tokens
112.4K
Snippets
326
Records
441
Agent score
94%

What's inside LSP

  1. What is the Language Server Index Format (LSIF)?

    gh-pages

    LSIF is a standard format used by language servers or programming tools to dump their workspace knowledge into a file. This dump allows consumers to answer Language Server Protocol (LSP) requests for that workspace without needing to run the actual language server.

    Key Characteristics:

    • LSP-Aligned: Data is modeled closely to LSP to allow serving it through LSP without transformation.
    • Result-Oriented: It stores the results of LSP requests (e.g., definitions, references, hovers) rather than defining symbol semantics or a symbol database.
    • JSON-Based: The output format is based on JSON.
    • Graph-Based: The data is structured as a graph where vertices represent documents, ranges, or results, and edges represent LSP methods or relationships like contains or next.
  2. What is the Language Server Protocol (LSP)?

    gh-pages

    The Language Server Protocol (LSP) is a standardized communication protocol that enables inter-process communication between development tools (clients) and language-specific intelligence (servers).

    Instead of implementing language features like autocomplete, 'goto definition', or hover documentation separately for every IDE or editor, a single Language Server can be written to provide these smarts. This server can then be reused across multiple development tools that all speak the same LSP standard.

  3. Identify new features in LSP version 3.17

    gh-pages

    LSP version 3.17 introduced several major features. When implementing or consuming the protocol, look for the since version 3.17 text or the @since 3.17.0 JSDoc annotation to identify these features.

    Major new features in 3.17 include:

    • Type hierarchy
    • Inline values
    • Inlay hints
    • Notebook document support
    • Meta model (a model describing the 3.17 LSP version)
  4. LSIF 0.5.0 Changes and New Features

    gh-pages

    Version 0.5.0 of the LSIF specification introduces several features to support larger, multi-project systems and better data sharding:

    • Logical Project Grouping: Added a Group vertex to support grouping related projects.
    • Moniker Uniqueness: Added a unique property to the Moniker to indicate how unique a moniker is.
    • Generic Attachment: Replaced the nextMoniker edge with a more generic attach edge, leveraging the new unique property on monikers.
    • Polymorphic Bindings: Introduced referenceLinks to allow tools to annotate an item edge. This captures polymorphic binds (like overridden methods in OOP) that occur at runtime but may be statically different.
    • Data Sharding: Added a shard property to items edges to facilitate better output chunking (previously known as the document property in early 0.5 drafts).
  5. Implement Snippet Syntax in completions

    gh-pages

    Completion items can support snippets by setting insertTextFormat to InsertTextFormat.Snippet. Snippets use a specific syntax to control cursors and text insertion:

    • Tab stops: Use $1, $2 for cursor locations. $0 is the final position.
    • Placeholders: Use ${1:foo} to provide a default value that is selected for easy editing. Supports nesting: ${1:another ${2:placeholder}}.
    • Choice: Use ${1|one,two,three|} to provide a dropdown of options.
    • Variables: Use $name or ${name:default}. Supported variables include:
      • TM_SELECTED_TEXT: Currently selected text.
      • TM_CURRENT_LINE: Contents of the current line.
      • TM_CURRENT_WORD: Word under cursor.
      • TM_LINE_INDEX: 0-indexed line number.
      • TM_LINE_NUMBER: 1-indexed line number.
      • TM_FILENAME: Filename.
      • TM_FILENAME_BASE: Filename without extension.
      • TM_DIRECTORY: Directory of the document.
      • TM_FILEPATH: Full file path.
    • Variable Transforms: Modify variables using regex. Example: ${TM_FILENAME/(.*)\..+$/$1/} extracts the filename without the extension.
    ${TM_FILENAME/(.*)\..+$/$1/}
      |           |         | |
      |           |         | |-> no options
      |           |         | |
      |           |         |-> references the contents of the first
      |           |             capture group
      |           |           |
      |           |           |-> regex to capture everything before
      |           |           |   the final `.suffix`
      |           |           |
      |-> resolves to the filename
  6. Report Partial Results using $/progress

    gh-pages

    Since version 3.15.0, servers can stream partial results to the client using the $/progress notification.

    1. Client Signaling: The client must include a partialResultToken in the request parameters to accept partial results.
    2. Server Reporting: The server sends $/progress notifications where the value payload matches the final result type (e.g., SymbolInformation[]).
    3. Final Response: When the server is finished, the final response to the original request must have an empty result value to avoid confusion between a final result and a partial result.

    Error Handling: If the request is cancelled (RequestCancelled), the client may use the partial results but should note they are incomplete. For all other errors, partial results should be discarded.

    {
      "textDocument": { "uri": "file:///folder/file.ts" },
      "position": { "line": 9, "character": 5 },
      "workDoneToken": "1d546990-40a3-4b77-b134-46622995f6ae",
      "partialResultToken": "5f6f349e-4f81-4a3b-afff-ee04bff96804"
    }
  7. Work with text document positions and offsets

    gh-pages

    The protocol is designed for textual documents. Positions are expressed using zero-based line and character offsets based on a UTF-16 string representation.

    Important details:

    • UTF-16 Offsets: A character like 𐐀 occupies two code units, so the character offset increments by 2.
    • End-of-Line (EOL): The protocol supports \n, \r\n, and \r. Positions are agnostic to the specific EOL sequence used.
    • Positioning: A Position represents the gap between characters (like an insertion cursor). Special values like -1 are not supported.
    export const EOL: string[] = ['\n', '\r\n', '\r'];
    
    interface Position {
    	/**
    	 * Line position in a document (zero-based).
    	 */
    	line: number;
    
    	/**
    	 * Character offset on a line in a document (zero-based). Assuming that the line is
    	 * represented as a string, the `character` value represents the gap between the
    	 * `character` and `character + 1`.
    	 *
    	 * If the character value is greater than the line length it defaults back to the
    	 * line length.
    	 */
    	character: number;
    }
  8. Configure WorkspaceEdit Resource Operations and Failure Handling

    gh-pages

    When a client performs a WorkspaceEdit, it specifies which resource operations it supports and how it handles failures.

    ResourceOperationKind defines the types of file/folder manipulations supported:

    • create: Creating new files and folders.
    • rename: Renaming existing files and folders.
    • delete: Deleting existing files and folders.

    FailureHandlingKind defines the strategy used if applying a workspace edit fails:

    • abort: The operation is aborted; changes made before the failure remain.
    • transactional: All operations succeed or none are applied.
    • textOnlyTransactional: Textual changes are transactional, but resource changes (create/rename/delete) use the abort strategy.
    • undo: The client attempts to undo already executed operations (no guarantee of success).
    export type ResourceOperationKind = 'create' | 'rename' | 'delete';
    
    export type FailureHandlingKind = 'abort' | 'transactional' | 'undo' | 'textOnlyTransactional';
  9. Choose between cellContent and notebook synchronization modes

    gh-pages

    When implementing notebook support, you must choose between two synchronization modes:

    • cellContent mode: Only the text content of individual cells is synchronized using standard textDocument/did* notifications. The server does not receive the notebook structure or the relationship between cells. This is easier to implement as it reuses existing text document logic.
    • notebook mode: The entire notebook document, its cell structure, and cell text content are synchronized together. Cell text is NOT synchronized via standard textDocument/did* notifications; instead, it uses special notebookDocument/did* notifications. This ensures that cell structure and content arrive in a single, consistent atomic update, allowing the server to reason about the whole notebook (e.g., for cross-cell variable references).

    To request a specific mode, the server defines notebookDocumentSync in its capabilities.

  10. Model `textDocument/documentSymbol` requests in LSIF

    gh-pages

    The textDocument/documentSymbol request provides an outline of the document. LSIF supports two modeling approaches:

    1. Literal approach: Storing symbol information directly as literals in the result.
    2. Range-based approach: Extending the range vertex with a tag property and referencing these range vertices in the symbol result. This is preferred for hierarchical data.

    In the range-based approach, the DocumentSymbolResult can contain RangeBasedDocumentSymbol objects which use ids to point to range vertices.

    export interface RangeBasedDocumentSymbol {
      id: RangeId
      children?: RangeBasedDocumentSymbol[];
    }
    
    export interface DocumentSymbolResult extends V {
      label: 'documentSymbolResult';
      result: lsp.DocumentSymbol[] | RangeBasedDocumentSymbol[];
    }
  11. Understand Client Capabilities in the Initialize Request

    gh-pages

    When a client sends an initialize request, it includes a capabilities object to inform the server of what features the client supports. This allows the server to adjust its behavior or only provide features the client can handle.

    Key client capability groups include:

    • workspaceFolders: Support for workspace folders.
    • configuration: Support for workspace/configuration requests.
    • fileOperations: Support for file-related requests/notifications (e.g., didCreate, willRename, didDelete).
    • window: Support for progress notifications (workDoneProgress), showing messages (showMessage), or showing documents (showDocument).
    • textDocument: Document-specific capabilities.
    • general: Support for regularExpressions or markdown parsing.
  12. Message Ordering for Requests and Responses

    gh-pages

    Responses to requests should generally be sent in the same order as the requests were received.

    However, a server may use a parallel execution strategy and return responses in a different order, provided that the reordering does not affect the correctness of the responses.

    Example of allowed reordering: Reordering responses for testing/configureFramework and testing/configureProject is allowed if they do not affect each other. Example of disallowed reordering: A server should not reorder testing/testCreated and testing/executeTest, as test creation must logically precede execution.