Urgent.News

What's breaking now, across thousands of outlets.

Tech

Why building a Rust LSP is hard

Building a Rust Language Server (LSP) is a complex endeavor fraught with challenges. Matklad, a renowned expert in Rust tooling, once penned insightful posts on the subject, but the last update to those posts was in 2023. The author of this article, unlike Matklad, is building an experimental Rust LSP called Rust Glancer, and has encountered numerous hurdles along the way.

This article aims to provide a technical yet architectural overview of the process, focusing on the unique challenges faced when building an LSP for Rust.

The LSP protocol is composed of two essential components: the LSP server and the state to be served. While the former may seem like a solved problem, with tools like tower-lsp-server available, the latter presents a far more intricate challenge. The protocol starts with a client sending an "initialize" request, which requires the LSP server to initialize itself before responding to any queries.

However, the server begins with no knowledge of the project and must index the codebase before it can provide any meaningful responses. The question arises: should the server block until the indexing is complete, or should it start responding immediately with incomplete information?

The author identifies a fundamental difference between compilers and LSPs. Compilers have a binary definition of completion: the binary is either compiled or not. LSPs, on the other hand, can provide useful results almost immediately. The goal is to minimize the amount of work required to make processing queries possible. In practice, both rust-analyzer and Rust Glancer validate the provided configuration and respond, scheduling workspace discovery to begin after the response.

Rust Glancer remains passive until the first query arrives, while rust-analyzer schedules workspace discovery to start after the response.

Once communication begins, the real work begins as the LSP server receives actual queries. The most common queries are "textDocument/didOpen," "textDocument/inlayHint," and "textDocument/documentSymbol." However, the complexity increases as the LSP protocol assumes it is the source of truth, while the reality is that analysis of a single file in isolation is often insufficient.

In practice, the LSP server must access the filesystem to ensure consistent state and cancel in-flight queries when invalidated. The author introduces the concept of a virtual file system (VFS) and source generations to address these challenges, allowing the LSP server to maintain a consistent internal state and avoid race conditions.

Written by urgent.news from Lobsters's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.

Read the original at rust-glancer.github.io →

More in Tech

More from Wednesday 16 September →