README.org

February 11, 2025 ยท View on GitHub

#+ATTR_HTML: align="center"; margin-right="auto"; margin-left="auto" =lsp-mode= uses =lsp-docker= to run language servers using in containers

[[./images/logo.png]]

[[https://melpa.org/#/lsp-docker][file:https://melpa.org/packages/lsp-docker-badge.svg]] [[https://stable.melpa.org/#/lsp-docker][file:https://stable.melpa.org/packages/lsp-docker-badge.svg]] [[https://github.com/emacs-lsp/lsp-docker/actions][file:https://github.com/emacs-lsp/lsp-docker/workflows/CI/badge.svg]]

  • Table of Contents :TOC_4_gh:noexport:
    • [[#preconfigured-language-servers][Preconfigured language servers]]
    • [[#usage][Usage]]
    • [[#emacslsplsp-docker-langservers][emacslsp/lsp-docker-langservers]]
      • [[#configuration][Configuration]]
      • [[#how-it-works][How it works]]
    • [[#emacslsplsp-docker-full][emacslsp/lsp-docker-full]]
      • [[#flags][Flags]]
        • [[#emacs][Emacs]]
        • [[#spacemacs][Spacemacs]]
    • [[#custom-language-server-containers][Custom language server containers]]
      • [[#building-a-container-or-an-image-manually][Building a container (or an image) manually:]]
      • [[#registering-a-language-server-using-a-persistent-configuration-file][Registering a language server using a persistent configuration file:]]
      • [[#registering-a-language-server-using-a-dir-locals-file][Registering a language server using a =.dir-locals= file:]]
      • [[#automatic-image-building][Automatic image building:]]
    • [[#docker-over-tramp-tbd][Docker over TRAMP (TBD)]]
    • [[#see-also][See also]]
    • [[#maintainers][Maintainers]]

** Preconfigured language servers =emacslsp/lsp-docker-langservers= has the following content:

** emacslsp/lsp-docker-langservers This container is used by =lsp-docker= to run =Language Servers= for =lsp-mode= over local sources. =You must pull the container before lsp-docker can use it= *** Configuration - Clone the repo #+begin_src bash git clone https://github.com/emacs-lsp/lsp-docker #+end_src - Pull the container #+begin_src bash docker pull emacslsp/lsp-docker-langservers #+end_src - Add repo to load path and register the docker clients in your =~/.emacs= file #+begin_src elisp ;; Uncomment the next line if you are using this from source ;; (add-to-list 'load-path "") (require 'lsp-docker)

  (defvar lsp-docker-client-packages
      '(lsp-css lsp-clients lsp-bash lsp-go lsp-pylsp lsp-html lsp-typescript
        lsp-terraform lsp-clangd))

  (setq lsp-docker-client-configs
      '((:server-id bash-ls :docker-server-id bashls-docker :server-command "bash-language-server start")
        (:server-id clangd :docker-server-id clangd-docker :server-command "clangd")
        (:server-id css-ls :docker-server-id cssls-docker :server-command "css-languageserver --stdio")
        (:server-id dockerfile-ls :docker-server-id dockerfilels-docker :server-command "docker-langserver --stdio")
        (:server-id gopls :docker-server-id gopls-docker :server-command "gopls")
        (:server-id html-ls :docker-server-id htmls-docker :server-command "html-languageserver --stdio")
        (:server-id pylsp :docker-server-id pyls-docker :server-command "pylsp")
        (:server-id ts-ls :docker-server-id tsls-docker :server-command "typescript-language-server --stdio")))

  (require 'lsp-docker)
  (lsp-docker-init-clients
    :path-mappings '(("path-to-projects-you-want-to-use" . "/projects"))
    :client-packages lsp-docker-client-packages
    :client-configs lsp-docker-client-configs)
  #+end_src

*** How it works =lsp-mode= starts the image passed as =:docker-image-id= and mounts =:path-mappings= in the container. Then when the process is started =lsp-mode= translates the local paths to =docker= path and vice versa using the =:path-mappings= specified when calling =lsp-docker-init-default-clients=. You may use =lsp-enabled-clients= and =lsp-disabled-clients= to control what language server will be used to run for a particular project(refer to =lsp-mode= FAQ on how to configure .dir-locals).

** emacslsp/lsp-docker-full The container =emacslsp/lsp-docker-full= contains: - The above language servers - =Emacs28= compiled with native JSON support for better performance. *** Flags | Flag | Purpose | Default | |-----------------+----------------------------------------+-------------------------------------------------------| | EMACS_D_VOLUME | Emacs folder to use for =/root/.emacs= | Emacs: =(pwd)/emacs.d=Spacemacs:=(pwd)/emacs.d= Spacemacs: =(pwd)/spacemacs= | | PROJECTS_VOLUME | Directory to mount at /Projects | =$(pwd)/demo-projects/= | | TZ | Timezone to user in container | Europe/Minsk | | DOCKER_FLAGS | Any additional docker flags | N/A | **** Emacs - Clone =lsp-docker=. #+begin_src bash git clone https://github.com/emacs-lsp/lsp-docker cd lsp-docker #+end_src - Run #+begin_src bash bash start-emacs.sh #+end_src **** Spacemacs - Clone =lsp-docker=. #+begin_src bash git clone https://github.com/emacs-lsp/lsp-docker cd lsp-docker #+end_src - Clone spacemacs repo #+begin_src bash # Clone spacemacs develop git clone -b develop https://github.com/syl20bnr/spacemacs spacemacs #+end_src - Run #+begin_src bash EMACS_D_VOLUME=/path/to/spacemacs bash start-spacemacs.sh #+end_src

** Custom language server containers You can use manually built language containers or images hosting language server(s), just follow a few simple rules (shown below). The docker images may feature an optional tag, if omitted latest will be assumed.

*** Building a container (or an image) manually: You have 2 constraints: - A language server must be launched in =stdio= mode (other types of communication are yet to be supported) - A docker container (only =container= subtype, see the configuration below) must have your language server as an entrypoint (basically you have to be able to launch it with =docker start -i <container_name>= as it is launched this way with =lsp-docker=)

When you have sucessfully built a language server, you have to register it with either a configuration file or a =.dir-locals= file.

*** Registering a language server using a persistent configuration file: A configuration file is a yaml file that can be located at: #+begin_src <PROJECT_ROOT>/.lsp-docker.yml <PROJECT_ROOT>/.lsp-docker.yaml <PROJECT_ROOT>/.lsp-docker/.lsp-docker.yml <PROJECT_ROOT>/.lsp-docker/.lsp-docker.yaml <PROJECT_ROOT>/.lsp-docker/lsp-docker.yml <PROJECT_ROOT>/.lsp-docker/lsp-docker.yaml <PROJECT_ROOT>/.lsp-docker/config.yml <PROJECT_ROOT>/.lsp-docker/config.yaml #+end_src

It is structured in the following way:

#+begin_src yaml

single server configuration

lsp: server: type: docker # subtype: # - "container": attach to an already running container # - "image": when image does not exist, try to build it based on the dockerfile found in the project-scope # (see Automatic image building). An image might feature an optional tag, i.e. ':'. If a # tagless image is indicated 'latest' will be assumed. subtype: container # Image/container name to use for this language server. name: image-container-name # server id of a registered LSP server. You can find the list of registered servers evaluating: # # (ht-keys lsp-clients) # # source: # https://stackoverflow.com/questions/17066169/retrieve-keys-from-hash-table-sorted-by-the-values-efficiently server: server-id-of-the-base-server # an (optional) array of parameters (docker or podman) to launch the image with # initially intended to host the '--userns' parameter # NOTE: 'launch_parameters' are not used with 'container' subtype servers # in this case embed all required parameters when creating the server instead launch_parameters: - "--userns=nomap" # command to launch the language server in stdio mode # NOTE: 'launch_command' is not used with 'container' subtype servers as a command is embedded in a # container itself and serves as entrypoint launch_command: "launch command with arguments" mappings: # NOTE: the paths must be within the project this server is being build for - source: "/your/host/source/path" destination: "/your/path/inside/the/container"

multiple server configuration

lsp: server: - type: ... subtype: ... ... # keys as in the classic single server case, e.g. type, subtype, etc... - ... # other single server configuration(s) mappings: # shared among all servers - source: destination: ... # other mappings #+end_src

*** Registering a language server using a =.dir-locals= file: Just refer to the source code and general conventions of using =.dir-locals=. The variable you need is =lsp-docker-persistent-default-config=, its content is merged with the =lsp= section from a configuration file (if present).

*** Automatic image building: You can also build an image automatically (currently supported only for =image= subtype): just drop the corresponding =Dockerfile= into the =.lsp-docker= folder in the project root (=Dockerfile= may be named as =Dockerfile= or =Dockerfile.lsp=). Building process is triggered by the =lsp-docker-register= call (you will be prompted whether you want to build the image). Image building takes place in the project root (not in the =.lsp-docker= subfolder)! In case of an automatic build the image will be registered automatically (based on the values from the config or =.dir-locals= file).

You can also troubleshoot any issues with supplemental docker calls (checking whether the required image already exists, building a new image) using the supplemental logging functionality: there are 2 variables: first you have to set =lsp-docker-log-docker-supplemental-calls= to true-like value (by default it is =nil=) and then specify the log buffer in the =lsp-docker-log-docker-supplemental-calls-buffer-name= variable (by default it is set to =*lsp-docker-supplemental-calls*=)

** Docker over TRAMP (TBD) Docker running the language servers and hosting the sources, Emacs running on the desktop machine and connecting to docker instance over TRAMP. ** See also