/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 Python dependencies: python-epc
  2. 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)
(require 'lsp-bridge)
(require 'lsp-bridge-jdtls)       ;; provide Java third-party library jump and -data directory support, optional

(yas-global-mode 1)
(global-lsp-bridge-mode)

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-show-signature-help-in-minibuffer: 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)

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-candidate-doc-preview: preview of the candidate document, enable by default
  • lsp-bridge-enable-signature-help: show function parameter in minibufer, 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
  • acm-backend-lsp-enable-auto-import: automatic insert import code, enable by default

Customize language server configuration

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

Anyway you can customize server configuration with the following priority:

  1. lsp-bridge-get-lang-server-by-project: write your own function to get server configuration based on project-path and file-path, this function is nil by default
  2. lsp-bridge-lang-server-extension-list: load server configuration based on file extension, such as, we launch volar server instead javascript server when open *.vue file
  3. lsp-bridge-lang-server-mode-list: load server configuration based on 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) in lsp-bridge-lang-server-list, such as (python-mode . "pyright")
  3. Add new mode-hook to lsp-bridge-default-mode-hooks

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

Supported language servers

Index LSP Server Language Note
1 clangd c, 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 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
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

TODO:

  • Code action
  • Show signature help with eldoc

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. Code formatting: each LSP server has its own formatting specification, we can gain finer control using Emacs' builtin formatting tool.
  2. Syntax highlighting: Tree-sitter is a wonderful incremental parsing library for syntax highlighting.
  3. Xref: Xref's mechanism is simultaneously. lsp-bridge is completely asynchronous, recommended to use wrap function to uniformly key

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, dabbrev 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 LSP Specification and The Design of lsp-bridge first.

Then turn on 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