

Taking the Language Server Protocol one step further
source link: https://garnix.io/blog/taking-lsp-one-step-further
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Taking the Language Server Protocol one step further
Until relatively recently, choosing an editor meant choosing a big bundle: a default set of keybindings, a UI, a community, an editing philosophy, and an ecosystem of language-specific support. Different editors developed their own language-specific support (like jump-to-definition, auto-completion, display type information, formatting) in parallel. In fact, a selling point of many these editors was how advanced their support for different languages was (think PyCharm for Python or Eclipse/IntelliJ for Java).
Then Microsoft introduced Language Server Protocol. With it, editors can be combined with different LSP servers; the responsibility for language-specific logic stands on the latter's shoulders.
This dramatically reduced the amount of duplicated effort, and was widely seen as a good thing.
It turns out, however, that the configuration parameters aren't just "editor × language," but instead
"editor × language × project." Almost any larger project will have a .vscode
folder (and potentially also a .vim
, .emacs
, etc.) which sets the configuration
for that project. Things like the version of software, what linter to use,
whether tsserver
or deno
should be run on .ts
files, etc. are all project-specific
parameters. But currently, there is no way to configure that per-project rather
than per-(project and editor).
Put differently, we successfully made an n
×
m
problem be n
+
m
; but the problem
was actually n
×
m
×
o
!
A proposed alternative
To solve this lingering issue, we could introduce an LSP proxy that intercepts requests from an editor, spins up the appropriate language server, and forwards the requests to it. There can be one configuration checked into the project repository declaring which language servers should be used for which files in the project, and with which parameters.
That configuration file might look something like this:
maps:
- path: ["garn.ts"]
command: deno lsp
config:
enable: true
suggest:
imports:
hosts:
- "https://deno.land"
- "https://crux.land"
- "https://x.nest.land"
- path: ["*.ts"]
command: typescript-language-server --stdio
- path: ["*.md"]
command: vale-ls
The proxy server only needs to parse the requests in order to figure out which file it relates to, and use that information (together with the project configuration) to decide which LSP to proxy to. (I tried my hand at a very quick prototype with hard-coded params here.)
That's an improvement. But the developers still have to install the subservers themselves. We could however imagine combining this with docker image support, or Nix, or garn. E.g.:
maps:
- path: ["garn.ts"]
command: docker run --rm -it denoland/deno lsp
- path: ["*.ts"]
command: nix-shell -p nodePackages.typescript-language-server --command "typescript-language-server --stdio"
Conclusion
By using an LSP proxy, we can seamlessly interface with existing language servers, but allow for specifying project-specific configurations. This goes even further in fostering a more open and diverse ecosystem of editors, since the network effect of having project-specific configuration is shared by all (not just VSCode users!).
</div
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK