From 825fd7c990e12569886127f7f7ca953b5516d327 Mon Sep 17 00:00:00 2001 From: Jane Lewis Date: Mon, 25 Mar 2024 23:08:37 -0700 Subject: [PATCH] High-level project overview and contributing guide for `ruff server` (#10565) ## Summary This PR adds an overview and roadmap to the `README.md` for the `ruff_server` crate along with a rudimentary `CONTRIBUTING.md` that explains some of the technical decisions behind the project and basic information about local testing. --- crates/ruff_server/CONTRIBUTING.md | 32 ++++++++++++++++++++++++++++++ crates/ruff_server/README.md | 9 +++++++++ 2 files changed, 41 insertions(+) create mode 100644 crates/ruff_server/CONTRIBUTING.md diff --git a/crates/ruff_server/CONTRIBUTING.md b/crates/ruff_server/CONTRIBUTING.md new file mode 100644 index 0000000000000..8b1c5481ecaff --- /dev/null +++ b/crates/ruff_server/CONTRIBUTING.md @@ -0,0 +1,32 @@ +## Contributing to the Ruff Language Server + +This is a mostly free-form guide with resources to help you get started with contributing to `ruff server`. + +### Project Architecture + +`ruff_server` uses a [lock-free data model](https://github.com/astral-sh/ruff/blob/a28776e3aa76c18dcc1f1ad36a48aa189040860d/crates/ruff_server/src/session.rs#L17-L26) to represent its state. The server runs in a [continuous event loop](https://github.com/astral-sh/ruff/blob/a28776e3aa76c18dcc1f1ad36a48aa189040860d/crates/ruff_server/src/server.rs#L146-L173) by listening to incoming messages +over `stdin` and dispatches [tasks](https://github.com/astral-sh/ruff/blob/a28776e3aa76c18dcc1f1ad36a48aa189040860d/crates/ruff_server/src/server/schedule/task.rs#L29-L40) based on the type of message. A 'task' can either be 'local' or 'background' - the former kind has +exclusive mutable access to the state and execute immediately, blocking the event loop until their completion. The latter kind, background +tasks, run immediately on a thread pool with an immutable snapshot of the state, and do _not_ block the event loop unless the thread pool +queue is full, in which case the server will block on available queue space. + +[Snapshots of the server state](https://github.com/astral-sh/ruff/blob/a28776e3aa76c18dcc1f1ad36a48aa189040860d/crates/ruff_server/src/session.rs#L28-L35) use atomic reference-counted pointers (`Arc`) to prevent unnecessary cloning of large text files. If the contents +of the text file need to be updated, the state will create a new `Arc` to store it. This allows a local task to run at the same time as multiple background tasks +without changing the state the background tasks are working with. This only applies to background tasks started _before_ the local task though, as a local task blocks +the handling of further messages (and therefore, dispatching future tasks) until its completion. + +`ruff_server` uses the `lsp-server` and `lsp-types` crates in favor of a more involved framework like `tower-lsp` because of the flexibility that the former gives us +in our implementation. A goal for this project was to take an architectural approach similar to `rust-analyzer`, with locally running tasks that access the state exclusively, +along with background tasks that reference a snapshot of the state. `tower-lsp` would have given us less control over execution order, which may have required us to use locks +or other thread synchronization methods to ensure data integrity. In fact, the `tower-lsp` scheduler has [existing issues](https://github.com/ebkalderon/tower-lsp/issues/284) around +data races and out-of-order handler execution. Our approach avoids this issue by dis-allowing `async` in tasks and using a scheduler focused on data mutability and access. + +### Testing + +Most editors with LSP support (VS Code is a notable exception) can work with a language server by providing a server command in their respective configurations. Guides for configuring specific editors to use Ruff will be available soon. + +If you want to test any changes you've made to `ruff server`, you can simply modify the editor configuration to use your debug binary. Unless you've already installed this debug build in your `PATH` (in which case you can just keep using `ruff server --preview` as the server command) the server command should be the path to your locally-built ruff executable (usually `/target/debug/ruff`) along with the arguments `server` and `--preview`. Make sure to (re)build the server with `cargo build -p ruff`! + +#### Testing In VS Code + +At the moment, the [pre-release version](https://github.com/astral-sh/ruff-vscode/tree/pre-release) of Ruff's new VS Code extension only has the option to use the bundled Ruff binary. Configuration to use a custom Ruff executable path will be ready soon. diff --git a/crates/ruff_server/README.md b/crates/ruff_server/README.md index 4123a253af865..4ea5110781788 100644 --- a/crates/ruff_server/README.md +++ b/crates/ruff_server/README.md @@ -1 +1,10 @@ ## The Ruff Language Server + +Welcome! `ruff server` is a language server that powers editor integrations with Ruff. The job of the language server is to +listen for requests from the client, (in this case, the code editor of your choice) and call into Ruff's linter and formatter +crates to create real-time diagnostics or formatted code, which is then sent back to the client. It also tracks configuration +files in your editor's workspace, and will refresh its in-memory configuration whenever those files are modified. + +### Contributing + +If you're interested in contributing to `ruff server` - well, first of all, thank you! Second of all, you might find the [**contribution guide**](CONTRIBUTING.md) to be a useful resource. Finally, don't hesitate to reach out on our [**Discord**](https://discord.com/invite/astral-sh) if you have questions.