Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Language service #396

Closed
25 of 37 tasks
minestarks opened this issue Jun 13, 2023 · 4 comments
Closed
25 of 37 tasks

Language service #396

minestarks opened this issue Jun 13, 2023 · 4 comments
Labels
enhancement New feature or request language server

Comments

@minestarks
Copy link
Member

minestarks commented Jun 13, 2023

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.
@minestarks minestarks added enhancement New feature or request needs triage labels Jun 13, 2023
@minestarks
Copy link
Member Author

Draft PR wiring up basic implementation of P1 features in VS Code and the playground: #364

minestarks added a commit that referenced this issue Jun 22, 2023
This adds a wrapper over `LanguageService` in the `wasm` crate to expose
it as a JavaScript class. See: #396

The existing WASM methods `check_code()` and `get_completions()` are
made redundant now that we have the language service, so I'm removing
them and adding a shim where they're used in the npm package.

Exactly how we're going to expose the language service in the npm
package is still being discussed, so I thought I'd get the more
straightforward WASM changes checked in first.
minestarks added a commit that referenced this issue Jun 27, 2023
- Add a `QSharpLanguageService` class in the npm package that wraps the
WASM language service.
- Refactor all the web worker proxy logic from `ICompiler` to make it a
generic utility that can turn any object into a web worker proxy. This
is implemented in
[`worker-proxy.ts`](https://github.com/microsoft/qsharp/pull/426/files#diff-d6a9e927974cf2eec1b1ea6996ddc0c25a0209b8c2d741a14fdc2764641d295e).
- Expose `getLanguageService()` and `getLanguageServiceWorker()` which
use the above.

You can reference #364 to see how this will eventually come together in
VS Code and the playground.

Tracking issue: #396
minestarks added a commit that referenced this issue Jun 28, 2023
Depends on #426

Wire up diagnostics, completions, go-to-definition and hover for VS Code
and Playground.

Tracking issue: #396
@sezna
Copy link
Contributor

sezna commented Jan 18, 2024

@minestarks -- is #1038 going to unblock LSP support, or are there other changes required?

Also, perhaps we could file some separate issues for some of these features and use this issue to track them?

@minestarks
Copy link
Member Author

@minestarks -- is #1038 going to unblock LSP support, or are there other changes required?

@sezna well, we'd have to implement an LSP server... but if you're asking if anything in the core language service crate needs to change, I don't think so. I had a prototype for this a few months ago using the https://github.com/python-lsp/python-lsp-jsonrpc package which was working in JupyterLab. I think it's just a matter of wiring pieces together.

Also, perhaps we could file some separate issues for some of these features and use this issue to track them?

Yes this issue is quite big, I don't mind breaking off a few items. I didn't want to create issues for things that aren't even on our radar, but for near-term stuff (e.g. formatting) and for stuff we want a dedicated discussion thread for, it makes sense.

@minestarks
Copy link
Member Author

Closing as completed. The unchecked items in the original description are currently out of scope.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request language server
Projects
None yet
Development

No branches or pull requests

4 participants