As of August 15, 2024, it's been announced that the three projects bein compared here will soon merge! See the official Elixir blog post for more details: https://elixir-lang.org/blog/2024/08/15/welcome-elixir-language-server-team/
We'll be comparing the following:
- I'm not an LSP expert.
- There is no "best" Elixir language server implementation.
- This comparison does not take performance into account.
- Language servers might support similar features that operate differently.
- Let me know if anything is incorrect or poorly explained.
Legend:
- ✅: The language server supports it.
⚠️ : The language server supports a version of it, but with caveats.- ❌: The language server does not support it.
- ❓: I don't know if the language server supports it.
- Items that needs more detail will add additional links/notes.
Feature | ElixirLS | Lexical LSP | Next LS | Notes/Caveats |
---|---|---|---|---|
Go to definition | ✅ | ✅ | ✅ | |
Find references | ✅ | ✅ | ✅ | |
Find implementation | ✅ | ❓ | ❓ | |
Code folding | ✅ | ❓ | ❓ | |
Signature help | ✅ | ❓ | ❓ | Shows the docs for the completion item and bolds/underlines the parameter you are currently typing |
Debugger | ✅ | ❓ | ❓ | |
Document symbols | ✅ | ✅ | ✅ | Power bread crumbs, outline views, and you can use them to fzf to a specific symbol in the document |
Workspace symbols | ✅ (currently returns inconsistent symbols) | ✅ | ✅ | Similar to document symbols, but for the whole project and might include different symbols |
Workspace (monorepo) support | ❓ | ❓ | ✅ | |
Workspace commands | ✅ (ToPipe, FromPipe, Expand Macro, Restart LSP) | ❓ | ✅ (To Pipe, From Pipe, alias module) | Usually invoked via a command pallette, sometimes overlap with code actions |
Code actions | ❌ | ✅ (Underscore unused variables) | ✅ (Underscore unused variables, require module, remove debugger expression, create undefined function) | Generally operates on currently highlighted or right-clicked symbol. Could also include "ignore this error" or "import this module" |
Rename symbol | ❌ | ❓ | ❌ | |
Lenses | ✅ (Typespec suggestions, run test overlay) | ❓ | ❌ | |
Code completion | ✅ | ✅ | ✅ | |
Code formatter | ✅ | ✅ | ✅ | |
Documentation on hover | ✅ | ✅ | ✅ | |
Compilation diagnostics | ✅ | ✅ (sometimes the Elixir compiler reports an error on one line but the actual cause is elsewhere, in which case Lexical figures this out for you and emits better errors) | ✅ | Need more details on what this is/does |
Compilation on save | ✅ | ✅ | ✅ | |
Compilation on type | ✅ | ❓ | ||
Credo integration | ❌ | ✅ (via plugin) | ✅ | |
Dialyzer integration | ✅ | ❌ (tracking issue) | ❌ (tracking issue) | |
Ecto integration | ✅ | ❌ | ❌ | Gives you some auto-complete for assoc s in schema definitions; usually provided via elixir_sense |
VS Code integration | ✅ | ✅ | ✅ | |
Sublime integration | ✅ | ✅ | ✅ | |
Neovim integration | ✅ | ✅ | ✅ | |
Vim integration | ✅ | ✅ | ✅ | |
Emacs integration | ✅ | ✅ | ✅ | |
Helix integration | ✅ | ✅ | ✅ | |
Zed integration | ✅ | ✅ | ✅ |
Designing a complete language server for the Elixir programming language would involve implementing many of the standard LSP features but adapted to Elixir's specific constructs and idioms. Here's what such an implementation might cover:
- Text Synchronization:
- Keep track of open, change, save, and close events of Elixir source files.
- Diagnostics:
- Integrate with Elixir's compiler to provide real-time feedback on warnings and errors.
- Possibly integrate with other linting or static analysis tools specific to Elixir like Credo.
- Completion:
- Offer module, function, variable, and macro completions.
- Provide context-aware completions for functions from the standard library, installed hex packages, and user-defined modules.
- Recognize special Elixir constructs, such as sigils or special forms.
- Hover:
- Show documentation, types, or related metadata when hovering over a function, macro, module, or variable.
- Signature Help:
- Display function signatures, expected arguments, and documentation while typing.
- Go to Definition:
- Allow navigation to the definition of a function, macro, module, or variable.
- Understand and follow aliases and imports in Elixir.
- Find References:
- Find all usages of a given function, module, or variable throughout the codebase.
- Document Highlight:
- Highlight other occurrences of the selected module, function, variable, or macro in the current file.
- Document Symbols:
- List all the functions, macros, and modules defined in the current document.
- Workspace Symbols:
- Search for modules or functions throughout the entire project or workspace.
- Code Action:
- Suggest fixes for common issues.
- Offer refactorings, like extracting a function or changing function arity.
- Integrate with Elixir's formatting tool (mix format) to suggest code format changes.
- Code Lens:
- Display reference counts for functions or macros.
- Indicate test coverage or provide the option to run a particular Elixir test.
- Document Formatting:
- Integrate with mix format to automatically format Elixir source code.
- Rename:
- Safely rename functions, macros, modules, and variables while considering Elixir's scoping rules.
- Semantic Tokens:
- Provide syntax highlighting tokens specific to Elixir's semantics, differentiating functions, macros, module names, and more.
- Call Hierarchy:
- Display a tree of function calls, helping users understand the flow of complex Elixir applications.
- Selection Range:
- Assist with selecting Elixir-specific constructs like do blocks, case clauses, or entire function bodies.
- Implementation, Type Definition, and Declaration:
- While Elixir is dynamically typed, understanding protocols and behaviors can provide insights into types and implementations.
- Document Link:
- Link to related documentation or other source files.
- Color Provider & Folding Range:
- Not as crucial for Elixir, but can enhance the developer experience in specific contexts.
- Additionally, for a language like Elixir, there are some domain-specific features that would be valuable:
- Integration with Mix: Understand project dependencies, run tasks, or even provide diagnostics related to dependency issues.
- Support for Ecto: Recognize Ecto schemas and queries, provide completions and diagnostics within embedded SQL, etc.
- Understanding metaprogramming: Elixir's macro system is powerful, so having the language server understand and provide information about macros would be crucial.
- Integration with ExUnit: Recognize test cases and offer functionality to run tests directly from the editor, display test results, etc.
- The goal of a complete language server for Elixir would be to provide a seamless and rich development experience that understands and leverages Elixir's unique features and idioms.
I use Lexical in Sublime daily. I simply installed LSP-elixir and change the command setting. In fact, I leave both in my config and can quickly switch if I want. To edit the configuration: Preferences > Package Settings > LSP > Servers > LSP-elixir
Now, as you see, I have both projects checked out and will pull down latest changes when I see something of interest.