Small LSP language server for elm. To use, install rust and
cargo +nightly install --git https://github.com/lue-bird/elm-language-server-rsThen point your editor to elm-language-server-rs, see also specific setups.
Works with elm-format and elm-test, install them if you haven't already.
You can also set their paths in the language server settings:
elm-language-server-rs.elmPath: string: compiler executable, default"elm"elm-language-server-rs.elmTestPath: string: test runner executable, default"elm-test"elm-language-server-rs.elmFormatPath: "builtin" | string: formatter executable, default"elm-format"."builtin"is a fast rust formatter that is mostly but not fully compatible
- fast (e.g. rename must be instant no matter the project size)
- reliable (e.g. work well with code that only partially parses)
- getting to know the language server protocol :)
- support for elm version <= 0.18 or inline GLSL blocks
- type inference
- directly integrating
elm-testrunning - codelens, workspace symbols, code folding, linked editing
elm.jsonhelp
- add support for
elm-review(depends on how easy it is, which I assume it isn't) - show all module exposes when hovering
(..)(only if I have time and there is interest) - add code actions like "expose (including variants)", "inline", "inline all uses" (leaning towards no as it is fairly complicated, though it is very useful for sure)
- show function parameter names (leaning towards no, as they are often confusing if they are curried, reveal non-exposed variant patterns, have more parameters than the type suggests, are undescriptive etc)
- currently, an exposed member will still be suggested even when a local module-declared reference/local binding with the same name exists. Likewise, a local module-declared reference will still be suggested even when a local binding with the same name exists. (somewhat easily fixable but I don't really see the harm in directly showing this shadowing in your face)
- add support for using elm-dev as the compiler to speed up compile times and retrieve type info (I assume integrating it is hard and to me it seems kind of bloated with MCP bs etc, currently leaning towards no)
- your idea 👀
- It is possible that an elm module belongs to multiple projects when source directory paths overlap between projects. This throws a wrench in pretty much all existing code (likely internal document source desync and a more limited lsp feature range in one of the containing projects). This situation is, I assume, fixable by special-casing their storage and handling but it would require a lot of work
feel free to contribute, as I only use vscodium
- download https://github.com/lue-bird/elm-language-server-rs/blob/main/vscode/elm-language-server-rs-0.0.1.vsix
- open the command bar at the top and select:
>Extensions: Install from VSIX
- clone this repo
- open
vscode/ - run
npm run packageto create the.vsix - open the command bar at the top and select:
>Extensions: Install from VSIX
There is no built-in language server bridge as far as I know but you can install an extension like vscode-generic-lsp-proxy that will work for any language server.
Then add a .vscode/lsp-proxy.json like
[
{
"languageId": "elm",
"command": "elm-language-server-rs",
"fileExtensions": [
".json",
".elm"
]
}
]write to ~/.config/helix/languages.toml:
[language-server.elm-language-server-rs]
command = "elm-language-server-rs"
[[language]]
name = "elm"
scope = "source.elm"
injection-regex = "elm"
roots = ["elm.json"]
file-types = ["elm", "json"]
comment-token = "--"
block-comment-tokens = { start = "{-", end = "-}" }
indent = { tab-width = 4, unit = " " }
language-servers = [ "elm-language-server-rs" ]
auto-format = trueRebuild the project with
cargo buildThen point your editor to the created ???/target/debug/elm-language-server-rs.
- switching to mimalloc, ~>25% faster (really nice) at the cost of 25% more memory consumption. Might be worth for some people but I'm already worried about our memory footprint!
declarations.shrink_to_fit();saves around 0.6% of memory at the cost of a bit of speed- upgrading
ltoto"thin"to"fat"both improve runtime speed by ~13% compared to the default (and reduce binary size) but increase build time by about 30% (default to thin) and 15% (thin to fat). As this prolongs installation and prevents people from quickly trying it, the default is kept. If this language server get distributed as a binary or people end up using this language server a lot, this"thin"might become a reasonable trade-off.
- reparse incrementally (somewhat easy to implement but somehow it's for me at least pretty much fast enough already without? More data points welcome)
- switch to
position_encoding: Some(lsp_types::PositionEncodingKind::UTF8). This makes source edits and parsing easier and faster at the cost of compatibility with lsp clients below version 3.17.0. Is that acceptable? (leaning towards yes). Also validate if elm --report region column is UTF-8 or UTF-16 (seems to be UTF-16 strangely) - if memory consumptions turns out to be a problem, stop storing the source in memory and request full file content on each change (potentially only for dependencies). This adds complexity and is slower so only if necessary.
- in syntax tree, use separate range type for single-line tokens like keywords, symbols, names etc to save on memory consumption
- switch most syntax tree
Box<str>s to https://docs.rs/smallstr/0.3.1/smallstr/ to for example speed up collecting references (e.g. for rename) - in syntax tree, use
Box<[]>instead ofVecfor common nodes like call arguments - on init, read modules in parallel, not just projects, to even out difference in project size (seems not worth using threads, maybe something more lightweight?)