/lsp-bridge

Fastest LSP client for Emacs

Primary LanguageEmacs Lisp

English | 简体中文

lsp-bridge

Lsp-bridge's goal is to become the fastest LSP client in Emacs.

Lsp-bridge uses python's threading technology to build caches that bridge Emacs and LSP server. Lsp-bridge will provide smooth completion experience without compromise to slow down emacs' performance.

Installation

  1. Install Emacs 28 and above versions
  2. Install Python dependencies:
  1. Install Elisp dependencies:
  1. Clone or download this repository (path of the folder is the <path-to-lsp-bridge> used below).
  2. Add following code in your ~/.emacs:
(add-to-list 'load-path "<path-to-lsp-bridge>")

(require 'yasnippet)
(yas-global-mode 1)

(require 'lsp-bridge)
(global-lsp-bridge-mode)

Usage

lsp-bridge is design for out the box. After installing the LSP server and mode plugin corresponding to the open file, you can write the code directly without additional settings.

It should be noted that there are three scan modes of lsp-bridge:

  1. When detecting the .git directory (check by command git rev-parse-is-inside-work-tree), lsp-bridge scan the entire directory file to provide completion
  2. When the .git directory was not detected, lsp-bridge only scan opened file to provide completion
  3. Custom lsp-bridge-get-project-path-by-filepath function, the input parameter is the path string of opened file, the output parameter is the project directory path, lsp-bridge will scan project directory path to provide provide completion

Commands

  • lsp-bridge-find-def: jump to the definition
  • lsp-bridge-find-def-other-window: jump to the definition in other-window
  • lsp-bridge-find-impl: jump to the implementation
  • lsp-bridge-find-impl-other-window: jump to the implementation in other-window
  • lsp-bridge-return-from-def: return to the location before calling lsp-bridge-find-def
  • lsp-bridge-find-references: traverse across code references (forked from color-rg.el)
  • lsp-bridge-lookup-documentation: lookup documentation of symbol under the cursor
  • lsp-bridge-popup-documentation-scroll-up: scroll up popup document.
  • lsp-bridge-popup-documentation-scroll-down: scroll down popup document.
  • lsp-bridge-rename: rename symbol under the cursor
  • lsp-bridge-jump-to-next-diagnostic: Jump to the next diagnostic position
  • lsp-bridge-jump-to-prev-diagnostic: Jump to the previous diagnostic position
  • lsp-bridge-list-diagnostics: List all diagnostic information
  • lsp-bridge-ignore-current-diagnostic: Insert comment to ignore the current diagnosis
  • lsp-bridge-signature-help-fetch: show signature help in minibuffer manually (move cursor to parameters area will show signature help automatically)
  • lsp-bridge-insert-common-prefix: insert common prefix of candidates
  • lsp-bridge-restart-process: restart lsp-bridge process (only used for development)
  • lsp-bridge-popup-complete: Manually popup the completion menu, you only need this command when turn on option lsp-bride-complete-manually
  • acm-doc-scroll-up: API document window scroll up
  • acm-doc-scroll-down: API document window scroll down

Options

  • lsp-bridge-completion-popup-predicates: the predicate function for completion menu, completion menu popup after all the functions pass
  • lsp-bridge-completion-stop-commands: completion menu will not popup if these commands are executed
  • lsp-bridge-completion-hide-characters: completion menu will not popup when cursor after those characters
  • lsp-bridge-diagnostics-fetch-idle: diagnostic delay, start pulling diagnostic information 1 second after stopping typing
  • lsp-bridge-enable-diagnostics: code diagnostic, enable by default
  • lsp-bridge-enable-signature-help: show function parameter in minibufer, enable by default
  • lsp-bridge-enable-search-words: index the word of the file, enable by default
  • lsp-bridge-enable-auto-format-code: automatic format code, disable by default
  • lsp-bridge-org-babel-lang-list: list of language to support org-mode code block completion
  • lsp-bridge-disable-backup: forbidden version manage of emacs, enable by default
  • lsp-bridge-enable-log: enable the LSP message log, disable by default
  • lsp-bridge-enable-debug: enable program debugging, disable by default
  • lsp-bridge-python-command: The path of the python command, if you use conda, you may customize this option
  • lsp-bridge-signature-function: The function used for displaying signature info
  • lsp-bridge-c-lsp-server: C language server, you can choose clangd or ccls
  • lsp-bridge-python-lsp-server: Python language server, you can choose pyright or jedi
  • lsp-bridge-tex-lsp-server: LaTeX language server, you can choose taxlab or digestif
  • lsp-bridge-complete-manually: Only popup completion menu when user call lsp-bridge-popup-complete command, default is nil
  • acm-backend-lsp-enable-auto-import: automatic insert import code, enable by default
  • acm-candidate-match-function: The complete menu matching algorithm, the algorithm prefix of orderless-* needs to be installed additional orderless
  • acm-enable-doc: Whether the complete menu display the help document
  • acm-enable-icon: Whether the complete menu shows the icon, macOS users need to add option --with-rsvg to the brew command to install emacs to display SVG icon
  • acm-enable-quick-access: Whether the index is displayed behind the icon, you can quickly select the candidate through Alt + Number, disable by default
  • acm-snippet-insert-index: The display position of snippet candidate in the complementary menu
  • acm-doc-frame-max-lines: Max line number of help documentation, default is 20
  • acm-enable-tabnine-helper: Enable tabnine support,disable by default,when enable call tabnine-bridge-install-binary command, and it can be used

Customize language server configuration

The default configuration of for each language server is stored at lsp-bridge/langserver.

In most cases, you can customize server configuration with the following priority:

  1. lsp-bridge-get-single-lang-server-by-project: The user custom function, the input parameter is project-path and file-path, return the corresponding LSP server string, you can query all LSP servers in the list of lsp-bridge-single-lang-server-mode-list option, this function return nil default
  2. lsp-bridge-single-lang-server-extension-list: load server configuration based on file extension, such as, we launch wxml server when open *.wxml file
  3. lsp-bridge-single-lang-server-mode-list: load server configuration based on major-mode

If you are writing JavaScript code, you may need to customize multi-server configuration:

  1. lsp-bridge-get-multi-lang-server-by-project: The user custom function, the input parameter is project-path and file-path, return the multi-server configuration name, you can find configuration name in the subdirectory lsp-bridge/multiserver
  2. lsp-bridge-multi-lang-server-extension-list: Return multi-server configuration name according to the expansion of the file, for example, when opening the *.vue file, we will use the volar and emmet-ls to provide completion service
  3. lsp-bridge-multi-lang-server-mode-list: Return the corresponding multi-server configuration name according to Emacs's major-mode

Add support for new language?

  1. Create configuration file under lsp-bridge/langserver, such as pyright.json for pyright (windows user please uses pyright_windows.json, macOS user please uses pyright_darwin.json).
  2. Add (mode . server_name) to lsp-bridge-single-lang-server-mode-list in lsp-bridge.el, such as (python-mode . "pyright").
  3. Add new mode-hook to lsp-bridge-default-mode-hooks in lsp-bridge.el.
  4. Add new mode indent to lsp-bridge-formatting-indent-alist in lsp-bridge.el.

Welcome to send PR to help us improve support for LSP servers, thanks for your contribution!

Supported language servers

You need to install the LSP server corresponding to each programming language, then lsp-bridge can provide code completion service.

Index LSP Server Language Note
1 clangd c, c++, object-c
2 pyright python pip install pyright
3 solargraph ruby
4 rust-analyzer rust
5 elixirLS elixir please ensure that the elixir-ls release directory is in your system PATH at first
6 gopls go make sure install go-mode and gopls in PATH, please do ln -s ~/go/bin/gopls ~/.local/bin, and do go mod init first
7 hls haskell
8 dart-analysis-server dart
9 metals scala
10 typescript typescript, javascript
11 ocamllsp ocaml
12 erlang-ls erlang
13 texlab latex
14 eclipse.jdt.ls java please ensure that org.eclipse.jdt.ls.product/target/repository/bin is in your system PATH at first
15 clojure-lsp clojure if you use homebrew , please ensure install clojure-lsp/brew/clojure-lsp-native clojure-lsp-native
16 bash-language-server bash
17 volar vue
18 sumneko lua please ensure bin under sumneko installation is in your system PATH at first
19 wxml-language-server wxml
20 vscode-html-language-server html
21 vscode-css-language-server css
22 elm-language-server elm
23 intelephense php
24 yaml-language-server yaml npm install -g yaml-language-server
25 zls zig execute zls config to generate configuration for zls. see Configuration Options
26 groovy-language-server groovy Create a script "groovy-language-server" in PATH, with $JAVA_HOME/bin/java -jar <path>/groovy-language-server-all.jar
27 docker-language-server Dockerfiles
28 serve-d d serve-d does not support single file mode, please init .git repository under project root at first or custom lsp-bridge-get-project-path-by-filepath function
29 fortls Fortran
30 ccls c, c++, object-c lsp-bridge-c-lsp-server set to ccls
31 jedi python lsp-bridge-python-lsp-server set to jedi
32 emmet-ls html, js, css, sass, scss, less
33 rnix-lsp nix
34 digestif latex lsp-bridge-tex-lsp-server set to digestif
35 rlanguageserver R
36 graphql-lsp GraphQL
37 microsoft-python-language-server Python legacy language server for Python2
38 cmake-language-server cmake pip install cmake-language-server

Features that won't be supported

The goal of lsp-bridge is to become the fastest LSP client in Emacs, not a complete implementation of LSP protocol.

Emacs can do better for the following tasks, we will not reinvent the wheel in lsp-bridge:

  1. Syntax highlighting: Tree-sitter is a wonderful incremental parsing library for syntax highlighting.
  2. Xref: Xref's mechanism is synchronous, but lsp-bridge is completely asynchronous. I recommended binding your xref key to a wrapper function that combines xref and lsp-bridge together.

Join development

The following is the framework of lsp-bridge:

The following is the directory structure of the lsp-bridge project:

File Explanation
lsp-bridge.el Elisp main logic part that provides custom options and elisp functions for python sub-process calls like code jumping, renaming, etc.
lsp-bridge-epc.el Communicating with lsp-bridge python sub-process, which mainly implements elisp IPC to connect to python EPC for data serialization, sending, receiving, and deserialization
lsp-bridge-ref.el Framework of code referencing, providing references viewing, batch renames, regex filtering of reference results, etc. The core code is forked from color-rg.el
lsp-bridge-jdtls.el Provide java language third-party library jumping function
lsp-bridge.py Python main logic part that provides event loop, message scheduling and status management
acm/acm.el Asynchronous completion menu, specially designed for lsp-bridge backend, supports LSP, elisp, words, TabNine and other backend
core/fileaction.py Tracking the status of each file, processing LSP response messages, calling Emacs elisp function
core/lspserver.py LSP message processing module, mainly to analyze, send and receive LSP messages, and ensure that the sequence of LSP requests conforms with the LSP protocol specification
core/utils.py Utility functions of convenience for each module call
core/mergedeep.py JSON information merger is mainly used to send custom options to LSP server
core/hanlder/ The implementation of sending and receiving LSP message, where init.py is a base class
langserver The configurations of the LSP servers, each server corresponding to a JSON file that defines the name of the server, language ID, starting command, options, etc.

Please read below articles first:

Then turn on develop option lsp-bridge-enable-log and happy hacking! ;)

Report bug

Please use emacs -q and load a minimal setup with only lsp-bridge to verify that the bug is reproducible. If emacs -q works fine, probably something is wrong with your Emacs config.

If the problem still exists, please report it here with *lsp-bridge* buffer content, it contains many clues that can help us locate the problem faster.

If you get a segfault error, please use the following way to collect crash information:

  1. Install gdb and turn on option lsp-bridge-enable-debug
  2. Use the command lsp-bridge-stop-process to stop the current process
  3. Restart lsp-bridge, send issue with *lsp-bridge* buffer content when next crash

Contributor