ZNHOO Whatever you are, be a good one!

Emacs LSP

  1. LSP
  2. Emacs eglot
  3. LSP Servers
    1. C/C++ clangd
    2. lua-lsp
    3. lua-language-server

LSP

Language Server Protocol (LSP) is originally from Mircosoft and now develops to a standard protocol.

LSP works in a client/server mode. In this post, the client is usually package of IDE (e.g. Emacs), while the server is specific to programing language (e.g. C/C++).

To configure Emacs with LSP support, we firstly, install the eglot in Emacs, then install a language-specific LSP server on your host, and might do some setup in init.el depending on the LSP server requirement.

Emacs eglot

Emacs supports LSP by its built-in package eglot or 3rd-party package lsp-mode.

eglot has less features but requires less dependencies. What is more, it is official!

  1. To install the eglot client, just run M-x package-install RET eglot RET.
  2. To start eglot for a LSP.
    1. Manually run M-x eglot.
    2. Automatically by (add-hook 'foo-mode-hook 'eglot-ensure).
  3. To turn off eglot and LSP.
    1. Manually run M-x eglot-shutdown.
    2. Automatically by (setq eglot-autoshutdown t).

LSP Servers

C/C++ clangd

Install the C/C++ LSP server clangd on Arch Linux.

~ $ sudo pacman -S clang

~ $ clangd --version

Make sure the value of variable eglot-server-programs contains c-mode and c++-mode. All the languages major mode listed here in is enabed by default.

Please open up a C/C++ source file and run M-x eglot. You will find LSP server clangd is automatically launched on your host, as the child process of Emacs. To shutdown the LSP server, just run M-x eglot-shutdown.

However, we'd like to automatically launch the LSP server upon a C/C++ source file is loaded. Add the following contents init.el.

(require 'eglot)
(add-hook 'c-mode-hook 'eglot-ensure)
(add-hook 'c++-mode-hook 'eglot-ensure)

lua-lsp

deprecated; see lua-language-server

This section assumes we are in Arch Linux system with mutliple Lua versions installed (e.g. extra/lua53 and extra/lua54).

To install lua-lsp, we should install Lua package manager luarocks first.

~ $ sudo pacman -S luarocks

Default Luarocks config (just a Lua script) is located under /etc/luarocks. We can inspect the full configuration of Lua 5.3 as below.

~ $ luarocks --lua-version 5.3 config --scope user
config_files = {
   nearest = "/etc/luarocks/config-5.3.lua",
   system = {
      file = "/etc/luarocks/config-5.3.lua",
      found = true
   },
   user = {
      file = "/home/outsinre/.luarocks/config-5.3.lua",
      found = true
   }
}
--
-- skipped
--
rocks_trees = {
   {
      name = "user",
      root = "/home/outsinre/.luarocks"
   },
   {
      name = "system",
      root = "/usr"
   }
}

rocks_trees refers the the root dir storing rocks contents. To avoid conflicts, we'd better configure different rocks tree for different Lua versions. Take Lua 5.3 for example, we will configure its rocks tree to ~/.luarocks53.

Let's change the current user's rocks tree for Lua 5.3.

~$ mkdir -p $HOME/.config/luarocks/
~$ cp /etc/luarocks/config-5.3.lua .config/luarocks/

~ $ vim .config/luarocks/config-5.3.lua
>{ name = "user", root = home .. "/.luarocks53" };

~ $ luarocks --lua-version 5.3 config --scope user

Finally, we install lua-lsp by explicitly provide the rocks tree.

# please omit option '--local'
~ $ luarocks --lua-version 5.3 --tree ~/.luarocks53 --server=http://luarocks.org/dev install lua-lsp

Now, we add the lua-lsp binary to PATH.

# ~/.bash_profile

eval $(luarocks --lua-version 5.3 path)

The built-in method above is provided by Luarocks but it exports LUA_PATH and LUA_CPATH as well. We may just want to set "PATH".

~ $ nano -w ~/.bash_profile
>PATH=$HOME/.luarocks53/bin:$PATH

To automatically launch lua-lsp, add the following lines to init.el.

(require 'eglot)
(add-hook 'lua-mode-hook 'eglot-ensure)

Repeat above steps for other Lua versions.

lua-language-server

lua-lsp has not been updated for years, and so we swtich the lua-language-server.

Let's install "lua-language-server" manually per-user.

~ $ wget https://github.com/LuaLS/lua-language-server/releases/download/3.6.19/lua-language-server-3.6.19-linux-x64.tar.gz

~ $ mkdir -p ~/.local/share/lua-language-server

~ $ tar -xzvf lua-language-server-3.6.19-linux-x64.tar.gz -C ~/.local/share/lua-language-server

We cannot add lua-language-server to "PATH" directly, instead we must create a wrapper, namely ~/bin/lsp-lua.

#!/usr/bin/env bash

exec "${HOME}/.local/share/lua-language-server/bin/lua-language-server" "--configpath=${HOME}/.local/share/lua-language-server/settings.lua" "$@"

Now let's have a try.

~ $ lsp-lua --version
3.6.19

lua-language-server by default is not added to eglot. So, we should manually set it up in init.el.

(add-to-list 'eglot-server-programs
             '(lua-mode "~/bin/lsp-lua"))
(add-hook 'lua-mode-hook 'eglot-ensure)

Restart Emacs and open a Lua file, eglot would automatically invokes ~/bi/lsp-lua to launch lua-language-server.

Before closing this section, let's configure lua-language-server a bit. Remember that, ~/bin/lsp-lua has specified the option --configpath to configurations from a Lua file settings.lua as follows. Plese read Settings for a complete list of parameters.

return {
    Lua = {
        ["runtime.version"] = "Lua 5.1",
        completion = {
            callSnippet = "Both",
            displayContext = 1,
            keywordSnippet = "Both",
        },
        ["hint.enable"] = true,
        ["format.enable"] = true,
    }
}

To format current buffer, just run M-x: eglot-format-buffer.