Skip to content

Language service #396

Closed
Closed
@minestarks

Description

@minestarks

This issue tracks the implementation of the language service and editor features for Q#. Editor features are things like autocomplete, go-to-definition and hover. The language service is the component that uses the compiler internals to keep track of the current state of the program, update the program in response to document updates, and answer questions about it in response to requests from the editor.

Components involved

  1. Language service: this is a Rust crate that contains the actual "smarts" of the language service, including the implementation of each individual feature such as completion, hover, etc.
  2. JS bindings: this is a trivial WASM wrapper over the language service to expose it as a JavaScript class. It follows a similar pattern to the existing WASM wrapper for the interpreter (the run() method etc)
  3. npm package: This is the same package used by the playground that incorporates the Q# compiler. A new interface will be added to provide access to the language service methods, with the option to host the language service in a separate web worker (just like the interpreter today).
  4. VS Code extension: Implementation of the VS Code extensibility APIs. These APIs generally map directly to language service methods.
  5. Playground: Similar to VS Code, the language service methods just need to be wired up to the Monaco editor extension points in the playground.
  6. Python bindings: Very similar to the WASM/JS bindings mentioned above - a trivial wrapper over the language server crate to expose it as a Python class. Also similar to the Python interpreter wrapper that currently exists today in the pip package.
  7. Python LSP server: (for JupyterLab support) A standalone LSP (Language Server Protocol) server implemented in Python. While Python may not be the most obvious choice for an LSP server implementation (Node.js libraries maintained by VS Code would have been a more natural fit), it was chosen to make the installation simple (user can just pip install the extension instead of having to separately install Node.js) for a JupyterLab user.
  8. Jupyterlab extension: (for JupyterLab support) Includes the LSP server module and registers it with JupyterLab.
%%{init: { "flowchart": { "nodeSpacing": 3 } } }%%
flowchart TD

subgraph JS
  playground[Playground]
  vscode[VS Code extension]
  website[Website]
  npm[npm package]
end

subgraph Python
  jupyterlab[JupyterLab extension]
  lsp[LSP server]
end

subgraph Rust
  wasm["JS bindings (WASM)"]
  pip[Python bindings]
  interpreter[Interpreter]
  ls[Language service]
  compiler[Compiler]
end

playground
vscode
website
jupyterlab

playground-->npm
vscode-->npm
website-->npm
jupyterlab-->lsp

npm-->wasm
lsp-->pip
wasm-->interpreter
wasm-->ls
pip-->ls

interpreter-->compiler
ls-->compiler
Loading

Implementation plan

This list shows the proposed order of implementation, based on complexity (simpler features like hover are prioritized above more complicated ones like completions) and feature priority (VS Code extension being the highest priority deliverable).

The links are to LSP documentation. Even if we don't implement a true LSP server, we'll follow the LSP spec while designing the interface as it closely resembles the extensibility model used by many editors (VS Code, Monaco, JupyterLab, etc).

  • Scaffolding:
  • P1 features. These will be implemented with support for only the file currently opened in the editor. The whole Q# program gets recompiled with every document edit (i.e. no performance optimizations):
  • Notebook cell support. Notebook cells use a variant of Q# that allows top-level items and expressions.
    • Use the "fragment" compiler rather than the "regular" compiler to construct a program.
    • There may be a compiler dependency here (investigate)
  • P2 features. Some of these features bring new complexity as they can return text edits back to the client.
    • Format document
    • Format range, format on type - Ability to format the subset of a document, as well the applicable range in response to a trigger character (e.g. })
    • Find all references - essentially reverse go-to-definition. (LS: Find All References #830 )
    • Symbol rename - determine if a rename is valid in the current location, use find-all-references to locate references to symbol, return text edits for rename
    • Quick fixes Contrast with refactorings, which are designated as a P3 feature below. Code fixes are associated with diagnostics (e.g. "unused identifier") reported by the compiler/linter and provide text edits that would "fix" that diagnostic.
      • Compiler dependency: Lint-level diagnostics for desired quick fixes.
  • Support for closed files (only necessary when we support file references (modules, imports etc) and/or projects):
    • VS Code Web compatible File I/O using vscode's WASI implementation, mapping of utf-16 line/column offsets
    • File watching - updating compilation in response to workspace changes (e.g. git branch switch)
  • LSP server to enable support for other editors
    • Python LSP server and JupyterLab support (blocked on jupyterlab-lsp supporting the latest version of JupyterLab).
  • Performance optimizations, as appropriate. These come with tradeoffs, so we should only implement them if we're observing actual performance problems.
    • Debouncing/batching - strategies to reduce the number of recompilations by introducing a slight delay before recompiling the document on each keystroke/file update. This may introduce a slight delay to completions and error squiggles.
    • Cancellation - cancel an outstanding recompilation when a document is updated. May require web workers or some other threading mechanism.
    • Background checking - ability for language service requests to run concurrently with checking. Requires web workers for WASM.
  • P3 features:
  • Even more expensive performance optimizations (hopefully avoided):
    • Background program update - ability to work with an immutable snapshot of the program as updates are being made in the background (in response to keystrokes or file updates). Requires web workers for WASM.
    • Compiler dependency: Partial recompilation - ability to recompile only parts of a program as the document gets updated.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions