- Language Server Protocol Support for Emacs
- ❤️ Community Driven
- 💎 Fully featured - supports all features in Language Server Protocol v3.14.
- 🚀 Easy to configure - works out of the box and automatically upgrades if additional packages are present
- 🌟 Flexible - could be configured as full-blown IDE with flashy UI or minimal distraction free
Client for Language Server Protocol (v3.14). lsp-mode aims to provide IDE-like experience by providing optional integration with the most popular Emacs packages like company, flycheck and projectile.
- Non-blocking asynchronous calls
- Real-time Diagnostics/linting (via builtin
flymakewhen Emacs > 26, requires flymake>=1.0.5 or flycheck/lsp-ui) - Code completion - using company-lsp or builtin
completion-at-point - Hovers - using lsp-ui
- Code actions - using
lsp-execute-code-actionor lsp-ui - Code outline - using builtin imenu or
helm-imenu - Code navigation - using builtin xref
- Code lens (references/implementations) - using builtin xref
- Symbol highlights
- Formatting
- Semantic highlighting (as currently implemented by JDT LS and unreleased builds of clangd, cf. Semantic highlighting spec)
- Debugger - dap-mode
- Helm integration - helm-lsp
- Ivy integration - lsp-ivy
- Treemacs integration - lsp-treemacs
- Semantic highlighting (as currently implemented by JDT LS and unreleased builds of clangd, cf. Semantic highlighting spec)
- which-key integration for better discovery
The recommended way to install lsp-mode is via package.el - the built-in package manager in Emacs. lsp-mode is available on the two major package.el community maintained repos - MELPA Stable and MELPA.
M-x package-install [RET] lsp-mode [RET]
Check the table bellow with the list of supported servers and the corresponding instructions on how to install the server.
You could go minimal and use lsp-mode as it is without external packages with the built-in flymake and completion-at-point or you could install the following extensions for better experience:
- install lsp-ui for flycheck integration and higher level UI modules.
- install company-lsp if you want to use
company-modefor completion. - install lsp-treemacs for various three based UI controls (symbols, errors overview, call hierarchy, etc.)
- install helm-lsp provides on type completion afternative of
xref-aproposusinghelm. - install lsp-ivy provides on type completion afternative of
xref-aproposusingivy. - install dap-mode if your language is supported by the debugger.
;; if you want to change prefix for lsp-mode keybindings.
(setq lsp-keymap-prefix "s-l")
(require 'lsp-mode)
(add-hook 'XXX-mode-hook #'lsp)where XXX could be major mode like python, java, c++. Alternatively, if you want to minimize you configuration you may use prog-mode-hook. In case you do that, lsp will try to start for each programming mode and echo a message when there is no client registered for the current mode or if the corresponding server is not present. In addition, lsp-mode will automatically detect and configure lsp-ui and company-lsp. To turn off that behavior you could set lsp-auto-configure to nil.
To defer LSP server startup (and DidOpen notifications) until the buffer is visible you can use lsp-deferred instead of lsp:
(add-hook 'XXX-mode-hook #'lsp-deferred)lsp-mode is included in spacemacs develop branch. Add lsp to dotspacemacs-configuration-layers and configure the language that you want to use to be backed by lsp backend.
Replace (require 'lsp-mode) with the following if you use use-package.
(use-package lsp-mode
;; set prefix for lsp-command-keymap (few alternatives - "C-l", "C-c l")
:init (setq lsp-keymap-prefix "s-l")
:hook (;; replace XXX-mode with concrete major-mode(e. g. python-mode)
(XXX-mode . lsp)
;; if you want which-key integration
(lsp-mode . lsp-enable-which-key-integration))
:commands lsp)
;; optionally
(use-package lsp-ui :commands lsp-ui-mode)
(use-package company-lsp :commands company-lsp)
;; if you are helm user
(use-package helm-lsp :commands helm-lsp-workspace-symbol)
;; if you are ivy user
(use-package lsp-ivy :commands lsp-ivy-workspace-symbol)
(use-package lsp-treemacs :commands lsp-treemacs-errors-list)
;; optionally if you want to use debugger
(use-package dap-mode)
;; (use-package dap-LANGUAGE) to load the dap adapter for your language
;; optional if you want which-key integration
(use-package which-key
:config
(which-key-mode)
To defer LSP server startup (and DidOpen notifications) until the buffer is visible you can use lsp-deferred instead of lsp:
(use-package lsp-mode
:hook (XXX-mode . lsp-deferred)
:commands (lsp lsp-deferred))Refer to lsp-docker README which provide a guide how you can run lsp-mode in docker container.
lsp-mode has predefined list of server configurations (loaded in lsp-clients.el) containing a mapping from major-mode to the server configuration or by using activation function. In addition to the default server configuration located in lsp-clients.el there are few languages servers which require separate package(check Supported languages). When you open a file from a particular project lsp-mode and call lsp command lsp-mode will look for server registrations able to handle current file. If there is such client lsp-mode will look for the project root. If you open a file from the project for the first time you will be prompted to define the current project root. Once the project root is selected it is saved in lsp-session file and it will be loaded the next time you start Emacs so you no longer will be asked for a project root when you open a file from that project. Later if you want to change the project root you may use lsp-workspace-folder-remove to remove the project and call lsp-workspace-folder-add to add the root. If you want to force starting a particular language server in a file you may use C-u M-x lsp which will prompt you to select language server to start.
Some of the servers are directly supported by lsp-mode by requiring
lsp-clients.el while others require installing additional packages which provide
server specific functionality.
| Language | Language Server | Built-in | Installation command | Debugger |
|---|---|---|---|---|
| Ada | ada_language_server | Yes | Installation instructions | Yes (gdb) |
| Angular | vscode-ng-language-service | Yes | Installation instructions | Not relevant |
| Bash | bash-language-server | Yes | npm i -g bash-language-server | |
| C++ | ccls | emacs-ccls | ccls | Yes (gdb or lldb) |
| C++ | clangd | Yes | clangd | Yes (gdb or lldb) |
| C++ | cquery | emacs-cquery | cquery | Yes (gdb or lldb) |
| C# | OmniSharp-Roslyn | Yes | OmniSharp-Roslyn | No |
| Clojure | clojure-lsp | Yes | clojure-lsp | |
| CMake | cmake-language-server | Yes | pip install cmake-language-server | Not relevant |
| Crystal | scry | Yes | scry | |
| CSS/LessCSS/SASS/SCSS | css | Yes | npm install -g vscode-css-languageserver-bin | |
| Dart | dart_analysis_server | Yes | built into dart-sdk | |
| Dhall | dhall-lsp-server | Yes | Installation instructions | No |
| Dockerfile | dockerfile-language-server-nodejs | Yes | npm install -g dockerfile-language-server-nodejs | |
| Dart | dart_language_server | Yes | pub global activate dart_language_server | |
| Elixir | elixir-ls | Yes | elixir-ls | Yes |
| Elm | elmLS | Yes | npm i -g @elm-tooling/elm-language-server, or clone the repository and follow installation instructions | No |
| Erlang | erlang_ls | Yes | erlang_ls | |
| Eslint | eslint | Yes | LSP ESLint Guide | N/A |
| F# | fsautocomplete | Yes | Automatic by lsp-fsharp | No |
| Fortran | fortran-language-server | Yes | pip install fortran-language-server | Yes |
| Go | gopls | Yes | go get golang.org/x/tools/gopls@latest docs | Yes |
| Go | bingo | Yes | bingo | Yes |
| Groovy | groovy-language-server | Yes | groovy-language-server | |
| Hack | hhvm | Yes | hhvm | |
| HTML | html | Yes | npm install -g vscode-html-languageserver-bin | |
| Haskell | IDE engine | lsp-haskell | IDE engine | |
| Lua | EmmyLua | Yes | Installation | |
| Java | Eclipse JDT LS | lsp-java | Automatic by lsp-java | Yes |
| JavaScript/TypeScript | typescript-language-server (recommended) | Yes | npm i -g typescript-language-server; npm i -g typescript | Yes (Firefox/Chrome) |
| JavaScript/TypeScript | javascript-typescript-stdio | Yes | npm i -g javascript-typescript-langserver | Yes (Firefox/Chrome) |
| JavaScript Flow | flow (add-on if working on a Flow file) | Yes | flow | Yes (Firefox/Chrome) |
| Json | vscode-json-languageserver | Yes | Automatic or manual by npm i -g vscode-json-languageserver | |
| Julia | lsp-julia | lsp-julia | LanguageServer.jl | |
| Kotlin | kotlin-language-server | Yes | kotlin-language-server | |
| Nim | nimlsp | Yes | nimble install nimlsp | No |
| OCaml | ocaml-language-server | Yes | ocaml-language-server | |
| OCaml | ocaml-lsp-server | Yes | ocaml-lsp-server | |
| PHP(recommended) | intelephense | Yes | npm i intelephense -g | Yes |
| PHP | php-language-server | Yes | php-language-server | Yes |
| Powershell | PowerShellEditorServices | Yes | Automatic | Yes |
| Python | pyls | Yes | pip install ‘python-language-server[all]’ | Yes |
| Python(Microsoft) | Microsoft Python Language Server | lsp-python-ms | lsp-python-ms | Yes |
| R | languageserver | Yes | install.packages(“languageserver”) | No |
| Ruby | solargraph | Yes | gem install solargraph | Yes |
| Rust | rls | Yes | rls | Yes |
| Rust | rust-analyzer | Yes | rust-analyzer | |
| Scala | Metals | Yes | Metals | |
| Swift | sourcekit-LSP | lsp-sourcekit | sourcekit-LSP | Yes (via llvm debug adapter) |
| Terraform | terraform-lsp | No | Git clone outside of $GOPATH; go install. (Requires go > 1.11) | No |
| TeX, LaTeX, etc. | Digestif | Yes | luarocks --server http://luarocks.org/dev install digestif | |
| Verilog/SystemVerilog | hdl_checker | Yes | pip install hdl-checker –upgrade | No |
| VHDL | VHDL Tool | Yes | Download from http://www.vhdltool.com/download | No |
| Vimscript | vim-language-server | Yes | npm install -g vim-language-server | n/a |
| Vue | vue-language-server | Yes | npm install -g vue-language-server | Yes (Firefox/Chrome) |
| XML | lsp4xml | Yes | Download from lsp4xml releases | |
| YAML | yaml | Yes | npm install -g yaml-language-server |
When using lsp-mode most of the features depend on server capabilities.
lsp-mode provides default bindings which are dynamically enabled/disabled
based on the server functionality. All the commands are configured
lsp-command-map which is bound to lsp-keymap-prefix (default s-l).
| Keybinding | Description |
|---|---|
s-l s s | Entry point for the server startup. |
s-l s r | Restart language server |
s-l s q | Shutdown language server |
s-l s d | Describes current dession |
s-l s D | Disconnect the buffer from the language server keeping the server running. |
s-l = = | Ask the server to format this document. |
s-l = r | Ask the server to format the region, or if none is selected, the current line. |
s-l F a | Add new project root to the list of workspace folders. |
s-l F r | Remove project root from the list of workspace folders. |
s-l F b | Remove project root from the workspace blacklist. |
s-l T l | Toggle code-lens overlays. |
s-l T L | Toggle client-server protocol logging. |
s-l T h | Toggle symbol highlighting. |
s-l T S | Toggle minor mode for showing information for current line in sideline. (requires lsp-ui) |
s-l T d | Toggle minor mode for showing hover information in child frame. (requires lsp-ui) |
s-l T s | Toggle signature auto activate. |
s-l T f | Toggle on type formatting. |
s-l T T | Toggle global minor mode for synchronizing lsp-mode workspace folders and treemacs projects. (requires lsp-treemacs) |
s-l g g | Find definitions of the symbol under point. |
s-l g r | Find references of the symbol under point. |
s-l g i | Find implementations of the symbol under point. |
s-l g t | Find type definitions of the symbol under point. |
s-l g d | Find declarations of the symbol under point. |
s-l g h | Show the incoming call hierarchy for the symbol at point. (requires lsp-treemacs) |
s-l g a | Find all meaningful symbols that match pattern. |
s-l h h | Display the type signature and documentation of the thing at |
s-l h s | Activate signature help. |
s-l h g | Trigger display hover information popup and hide it on next typing. |
s-l r r | Rename the symbol (and all references to it). |
s-l r o | Perform the source.organizeImports code action, if available. |
s-l a a | Execute code action action. |
s-l a l | Click lsp lens using ‘avy’ package. |
s-l a h | Highlight symbol at point. |
s-l G g | Peek definitions to the identifier at point. (requires lsp-ui) |
s-l G r | Peek references to the identifier at point. (requires lsp-ui) |
s-l G i | Peek implementation locations of the symbol at point. (requires lsp-ui) |
s-l G s | Peek symbols in the worskpace. (requires lsp-ui) |
To enable which-key integration put that in your config.
(with-eval-after-load 'lsp-mode
(add-hook 'lsp-mode-hook #'lsp-enable-which-key-integration))lsp-log-io- If non-nil, print all messages to and from the language server to*lsp-log*.lsp-print-performance- If non-nil, print performance info. to*lsp-log*.lsp-inhibit-message- If non-nil, inhibit the message echo viainhibit-message.lsp-report-if-no-buffer- If non nil the errors will be reported even when the file is not open.lsp-keep-workspace-alive- If non nil keep workspace alive when the last workspace buffer is closed.lsp-enable-snippet- Enable/disable snippet completion support.lsp-auto-guess-root- Automatically guess the project root using projectile/project. Do not use this setting unless you are familiar withlsp-modeinternals and you are sure that all of your projects are followingprojectile=/=project.elconventions.lsp-restart- Defines how server exited event must be handled.lsp-session-file- File where session information is stored.lsp-auto-configure- Auto configurelsp-mode. When set to tlsp-modewill auto-configurelsp-uiandcompany-lsp.lsp-document-sync-method- How to sync the document with the language server.lsp-auto-execute-action- Auto-execute single action.lsp-eldoc-render-all- Display all of the info returned bydocument/onHover. If this is nil,eldocwill show only the symbol information.lsp-enable-completion-at-point- Enablecompletion-at-pointintegration.lsp-enable-xref- Enable xref integration.lsp-prefer-flymake- If you prefer flycheck andlsp-ui-flycheckis available,(setq lsp-prefer-flymake nil). If set to:noneneither of two will be enabled.lsp-enable-indentation- Indent regions using the file formatting functionality provided by the language server.lsp-enable-on-type-formatting- EnabletextDocument/onTypeFormattingintegration.lsp-before-save-edits- If non-nil,lsp-modewill apply edits suggested by the language server before saving a document.lsp-imenu-show-container-name- Display the symbol’s container name in an imenu entry.lsp-imenu-container-name-separator- Separator string to use to separate the container name from the symbol while displaying imenu entries.lsp-imenu-sort-methods- How to sort the imenu items. The value is a list ofkind,nameorposition. Priorities are determined by the index of the element.lsp-response-timeout- Number of seconds to wait for a response from the language server before timing out.lsp-enable-file-watchers- If non-nil lsp-mode will watch the files in the workspace if the server has requested that.lsp-server-trace- Request trace mode on the language server.lsp-enable-semantic-highlighting- Enable experimental semantic highlighting supportlsp-enable-imenu- If non-nil, automatically enable imenu integration when server providestextDocument/documentSymbol.lsp-signature-auto-activate- Auto activate signature when trigger char is pressed.lsp-signature-render-documentation- Include signature documentation in signature help.lsp-enable-text-document-color- EnabletextDocument/documentColorwhen server supports it.
- RUST Completion with company-lsp

- Typescript references using lsp-ui

- Debugging Python using dap-mode

- Call hierarchy via ccls

- Metals Doctor

- Semantic highlighting as provided by clangd (built from unreleased 10.0 branch). In this screenshot, all other font-locking has been disabled (hence no syntax highlighting of comments or basic keywords such as
auto)
LSP mode has support for tramp buffers with the following requirements:
- The language server has to be present on the remote server.
- Having multi folder language server (like Eclipse JDT LS) cannot have local and remote workspace folders.
lsp-mode detects whether a particular file is located on remote machine and looks for a client which matches current file and it is marked as :remote? t. Then lsp-mode starts the client through tramp.
Here it is example how you can configure python language server to work when using TRAMP. Note that if you are trying to convert existing language server configuration you should copy all of it’s properties(e. g. :request-handlers, activation-fn, etc).
(lsp-register-client
(make-lsp-client :new-connection (lsp-tramp-connection "binary-or-full-path")
:major-modes '(python-mode)
:remote? t
:server-id 'pyls-remote))With TRAMP, Emacs does not have an easy way to distinguish stdout and stderr, so when the underlying LSP process writes to stderr, it breaks the lsp-mode parser. As a workaround, lsp-mode is redirecting stderr to /tmp/<process-name>-<id>~stderr.
When some of the workspaces that are active in the current project requests file notifications via workspace/didChangeWatchedFiles lsp-mode will start monitoring each of the folders in the workspace for changes. In case your project contains a lot of files you might want to disable file monitoring via lsp-enable-file-watchers (you may use dir-locals).
Contributions are very much welcome.
Here it is a list of the current lsp-mode members and what they are primary working on/responsible for.
| Member | Responsible for: |
|---|---|
| TOTBWF | F# |
| brotzeit | Rust |
| dsyzling | Scala |
| kurnevsky | Scala & Rust |
| seagle0128 | Go & MS Python Language Server |
| sebastiansturm | lsp-mode core & C++ |
| vibhavp | lsp-mode core |
| yyoncho | lsp-mode core and Java |
- set
lsp-log-iototto inspect communication between client and the server. Uselsp-workspace-show-logto switch to the corresponding log buffer. lsp-describe-sessionwill show the current projects roots + the started severs and allows inspecting the server capabilities.
Here it is the minimal configuration that is needed for new language server registration. Refer to the documentation of lsp-client.el for the additional settings supported on registration time. lsp-language-id-configuration must be updated to contain the corresponding mode -> language id - in this case (python-mode . "python")
(defvar lsp-language-id-configuration
'(...
(python-mode . "python")
...))
;; if you are adding the support for your language server in separate repo use
;; (add-to-list 'lsp-language-id-configuration '(python-mode . "python"))
(lsp-register-client
(make-lsp-client :new-connection (lsp-stdio-connection "pyls")
:major-modes '(python-mode)
:server-id 'pyls))If the language server supports environment variables to control additional behavior, you can register that by using the :environment-fn function, like the Bash language client does:
(lsp-register-client
(make-lsp-client :new-connection (lsp-stdio-connection '("bash-language-server" "start"))
:major-modes '(sh-mode)
:priority -1
:environment-fn (lambda ()
(("EXPLAINSHELL_ENDPOINT" . lsp-bash-explainshell-endpoint)
("HIGHLIGHT_PARSING_ERRORS" . lsp-bash-highlight-parsing-errors)))
:server-id 'bash-ls))lsp-bash-explainshell-endpoint and lsp-bash-highlight-parsing-errors are language client defcustom that expose supported server environment settings in a type-safe way. If you change any of those variables, restart the language server with lsp-restart-workspace for the changes to be applied.
lsp-mode provides tools to bridge emacs defcustom as a language configuration sections properties(see specification workspace/configuration). In addition you may use lsp-generate-settings from Generate Settings script to generate defcustom from package.json VScode plugin manifest. Example:
(defcustom lsp-foo-language-server-property "bar"
"Demo property."
:group 'foo-ls
:risky t)
(lsp-register-custom-settings '(("foo.section.property" lsp-foo-language-server-property)))
(lsp-configuration-section "foo")
;; => (("foo" ("settings" ("property" . "bar"))))- How do I troubleshoot “Server FOO-LS:pid exited with status signal. Do you want to restart it? (y or n)”?
- This message indicates that the language server has crashed for some
reason. You may check the server stderr which is
*FOO-LS::stderr*. If you get this message on startup you may try to run the exact command thatlsp-modeis running in the terminal. You may find it in*lsp-log*buffer.
- This message indicates that the language server has crashed for some
reason. You may check the server stderr which is
- How to configure a server with local variables?
- Add
lspserver call tohack-local-variables-hookwhich runs right after the local variables are loaded.(add-hook 'hack-local-variables-hook (lambda () (when (derived-mode-p 'XXX-mode) (lsp))))
- Add
- I have multiple language servers registered for language FOO. Which one will be used when opening a project?
- The one with highest priority wins.
lsp-clients.elpredefined servers have priority -1, lower than external packages (priority 0 if unspecified). If a server is registered with:add-on?flag set totit will be started in parallel to the other servers that are registered for the current mode.
- The one with highest priority wins.
- I have multiple language servers for language
FOOand I want to select the server per project, what can I do?- You may create
dir-localfor each of the projects and specify list oflsp-enabled-clients. This will narrow the list of the clients that are going to be tested for the project.
- You may create
- The completion does not work fine and inserts arguments and placeholders, what I am doing wrong?
- Snippet support works only with
company-lspso if you are usingcompletion-at-pointthe snippets won’t be expanded and you should either disable them by settinglsp-enable-snippettonilor you should switch tocompany-lsp. Note also thatcompany-tngfrontend does not support snippet expansion(see company-mode#891)
- Snippet support works only with
- How to automatically follow
lsp-ui-log?- Go into the log buffer and execute the following snippet(source: Emacs auto scrolling log buffer)
(set (make-local-variable 'window-point-insertion-type) t)
- I am getting “Package ‘spinner-1.7.3’ is unavailable” when trying to install
lsp-mode.- This is caused by GPG keys used by the ELPA package manager not being up to date. You may fix by installing: gnu-elpa-keyring-update
- Json completion doesn’t seem working?
- The latest vscode-json-languageserver is broken. You will need to install the earlier version of it
npm i vscode-json-languageserver@1.2.1
- The latest vscode-json-languageserver is broken. You will need to install the earlier version of it
- The flycheck does not work in
typescript,htmlandjavascriptblocks invue-mode. How to fix that?- This is caused by the fact that
vue-modeuses multiple major modes in single file and thelsp-uichecker may not associated with the major mode at point. You could fix that by adding the following lines to your config.(with-eval-after-load 'lsp-ui-flycheck (mapc 'lsp-ui-flycheck-add-mode '(typescript-mode js-mode css-mode vue-html-mode)))
- This is caused by the fact that
- lsp-docker - provide docker image with preconfigured language servers with corresponding emacs configuration.
- company-box -
companyfrontend with icons. - dap-mode - Debugger integration for
lsp-mode. - eglot - An alternative minimal LSP implementation.
- which-key - Emacs package that displays available keybindings in popup
- projectile - Project Interaction Library for Emacs



