/lsp-mode

Emacs client/library for the Language Server Protocol

Primary LanguageEmacs LispGNU General Public License v3.0GPL-3.0

https://melpa.org/packages/lsp-mode-badge.svg https://stable.melpa.org/packages/lsp-mode-badge.svg https://badges.gitter.im/emacs-lsp/lsp-mode.svg https://travis-ci.org/emacs-lsp/lsp-mode.svg?branch=master

examples/logo.png

Language Server Protocol Support for Emacs

examples/head.png

Table of Contents

Why?

  • ❤️ Community Driven
  • 💎 Fully featured - supports LSP core and Language Server non-standard extensions
  • 🚀 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

Overview

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 flymake when Emacs > 26 or flycheck/lsp-ui)
  • Code completion - using company-lsp or builtin completion-at-point
  • Hovers - using lsp-ui
  • Code actions - using lsp-execute-code-action or lsp-ui
  • Code outline - using builtin imenu or helm-imenu
  • Code navigation - using builtin xref
  • Code lens (references/implementations) - using builtin xref
  • Highlights
  • Formatting
  • Debugger - dap-mode
  • Helm integration - helm-lsp

Installation

Install via melpa

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]

Configuration

Install language server

Check the table bellow with the list of supported servers and the corresponding instructions on how to install the server.

Configure lsp-mode

Vanilla Emacs

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-mode for completion.
(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.

Spacemacs

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.

use-package

Replace (require 'lsp-mode) with the following if you use use-package.

(use-package lsp-mode
  :commands lsp
  :init
  (setq ...))

(use-package lsp-ui :commands lsp-ui-mode)
(use-package company-lsp :commands company-lsp)

How it works?

lsp-mode has predefined list of server configurations (located in lsp-clients.el) containing a mapping from major-mode to the server configuration. 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 major-mode. 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 the project. Once the project is imported project root 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.

Supported languages

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.

LanguageLanguage ServerBuilt-inInstallation commandDebugger
Bashbash-language-serverYesnpm i -g bash-language-server
C++cclsemacs-cclscclsYes (gdb or lldb)
C++clangdYesclangdYes (gdb or lldb)
C++cqueryemacs-cquerycqueryYes (gdb or lldb)
CSS/LessCSS/SASS/SCSScssYesnpm install -g vscode-css-languageserver-bin
Dartdart_language_serverYespub global activate dart_language_server
Elixirelixir-lsYeselixir-lsYes
Fortranfortran-language-serverYespip install fortran-language-serverYes
GogoplsYesgopls go get -u golang.org/x/tools/cmd/goplsYes
GobingoYesbingoYes
Groovygroovy-language-serverYesgroovy-language-server
HackhhvmYeshhvm
HTMLhtmlYesnpm install -g vscode-html-languageserver-bin
HaskellIDE enginelsp-haskellIDE engine
JavaEclipse JDT LSlsp-javaAutomatic by lsp-javaYes
JavaScript/TypeScripttypescript-language-server (recommended)Yesnpm i -g typescript-language-server; npm i -g typescriptYes (Firefox/Chrome)
JavaScript/TypeScriptjavascript-typescript-stdioYesnpm i -g javascript-typescript-langserverYes (Firefox/Chrome)
JavaScript Flowflow (add-on if working on a Flow file)YesflowYes (Firefox/Chrome)
Ocamlocaml-language-serverYesocaml-language-server
PHP(recommended)intelephenseYesnpm i intelephense -gYes
PHPphp-language-serverYesphp-language-serverYes
PowershellPowerShellEditorServiceslsp-powershellAutomatic by lsp-powershell
PythonpylsYespip install ‘python-language-server[all]’Yes
Python(Microsoft)Microsoft Python Language Serverlsp-python-mslsp-python-msYes
RubysolargraphYesgem install solargraphYes
RustrlsYesrlsYes
Scalalsp-scalalsp-scalalsp-scala
Swiftsourcekit-LSPlsp-sourcekitsourcekit-LSPYes (via llvm debug adapter)
Vuevue-language-serverYesnpm install -g vue-language-serverYes (Firefox/Chrome)
Kotlinkotlin-language-serverYeskotlin-language-server

Commands

  • lsp-describe-session - Display session folders and running servers.
  • lsp-describe-thing-at-point - Display help for the thing at point.
  • lsp-execute-code-action - Execute code action.
  • lsp-format-buffer - Format current buffer
  • lsp-goto-implementation - Go to implementation
  • lsp-goto-type-definition - Go to type definition
  • lsp-rename - Rename symbol at point
  • lsp-organize-imports - Organize imports
  • lsp-restart-workspace - Restart project
  • lsp-symbol-highlight - Highlight all relevant references to the symbol under point.
  • lsp-workspace-folders-add - Add workspace folder
  • lsp-workspace-folders-remove - Remove workspace folder
  • lsp-workspace-folders-switch - Switch workspace folder
  • imenu or helm-imenu - display document structure.
  • completion-at-point - display completion using built-in emacs completion-at-point framework.
  • lsp-find-definition - to find the definition for the symbol under point.
  • lsp-find-references - Find references for the symbol under point.
  • lsp-lens-show - Show lenses in the current file
  • lsp-lens-hide - Hide lenses in the current file
  • lsp-lens-mode (experimental) - Turn on/off lenses in the current file.
  • lsp-save-logs - Save a trace of all messages to and from the language server to a given file. Only works when lsp-save-logs is non-nil.

Settings

  • lsp-print-io - If non-nil, print all messages to and from the language server to *lsp-log*.
  • lsp-trace - If non-nil, keep a trace of all messages to and from the language server, which can be saved to a file with lsp-save-logs.
  • lsp-print-performance - If non-nil, print performance info. to *lsp-log*.
  • lsp-inhibit-message - If non-nil, inhibit the message echo via inhibit-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.
  • lsp-restart - Defines how server exited event must be handled.
  • lsp-session-file - Automatically guess the project root using projectile/project.
  • lsp-auto-configure - Auto configure lsp-mode. When set to t lsp-mode will auto-configure lsp-ui and company-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 - Define whether all of the returned by document/onHover will be displayed. If lsp-markup-display-all is set to nil eldoc will show only the symbol information.
  • lsp-enable-completion-at-point - Enable completion-at-point integration.
  • lsp-enable-xref - Enable xref integration.
  • lsp-prefer-flymake - If you prefer flycheck and lsp-ui-flycheck is available, (setq lsp-prefer-flymake nil). If set to :none neither 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 - Enable textDocument/onTypeFormatting integration.
  • lsp-before-save-edits - If non-nil, lsp-mode will 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 of kind, name or position. 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.

Screenshots

  • RUST Completion with company-lsp examples/completion.png
  • Typescript references using lsp-ui examples/references.png
  • Debugging Python using dap-mode examples/python_debugging.png
  • Call hierarchy via ccls examples/call-hierarchy-ccls.png

Extensions

TRAMP (Experimental)

LSP mode has support for tramp buffers with the following requirements.

  • The language server have to be present on the remote server since it is running on the remote machine.
  • Having multi folder language server (like Eclipse JDT LS) cannot have local and remote servers.

How does it work?

lsp-mode detects whether a particular file is located on remote machine and looks for a client which can handle the current major mode and it is marked as :remote? t. Then lsp-mode starts the client through tramp.

Sample configuration

Here it is example how you can configure python language server to work when using TRAMP.

(lsp-register-client
 (make-lsp-client :new-connection (lsp-tramp-connection "pyls")
                  :major-modes '(python-mode)
                  :remote? t
                  :server-id 'pyls))

Limitations

File watches

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

Contributions are very much welcome.

Here is a throughput graph of the repository for the last few weeks:

https://graphs.waffle.io/emacs-lsp/lsp-mode/throughput.svg

Troubleshooting

  • set lsp-print-io to t to inspect communication between client and the server.
  • lsp-describe-session will show the current projects roots + the started severs and allows inspecting the server capabilities.

examples/describe.png

Adding support for languages

Registering server

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")

(lsp-register-client
 (make-lsp-client :new-connection (lsp-stdio-connection "pyls")
                  :major-modes '(python-mode)
                  :server-id 'pyls))

Sections

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"))))

FAQ

  • How to configure a server with local variables? Add lsp server call to hack-local-variables-hook which runs right after the local variables are loaded.
    (add-hook 'hack-local-variables-hook
              (lambda () (when (derived-mode-p 'XXX-mode) (lsp))))
        
  • 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.el predefined servers have priority -1, lower than external packages (priority 0 if unspecified). If a server is registered with :add-on? flag set to t it will be started in parallel to the other servers that are registered for the current mode.

See also

  • dap-mode - Debugger integration for lsp-mode.
  • eglot - An alternative minimal LSP implementation.