1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
|
#+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:
- Language servers:
| Language | Language Server |
|-----------------------+-----------------------------------|
| Bash | [[https://github.com/mads-hartmann/bash-language-server][bash-language-server]] |
| C++ | [[https://github.com/MaskRay/ccls][ccls]] |
| CSS/LessCSS/SASS/SCSS | [[https://github.com/vscode-langservers/vscode-css-languageserver-bin][css]] |
| Dockerfile | [[https://github.com/rcjsuen/dockerfile-language-server-nodejs][dockerfile-language-server-nodejs]] |
| Go | [[https://golang.org/x/tools/cmd/gopls][gopls]] |
| HTML | [[https://github.com/vscode-langservers/vscode-html-languageserver][html]] |
| JavaScript/TypeScript | [[https://github.com/theia-ide/typescript-language-server][typescript-language-server]] |
| Python | [[https://github.com/python-lsp/python-lsp-server][pylsp]] |
** Usage
There are two ways of working with containerized language servers:
- 2 containers provided by =lsp-docker=:
- [[#emacslsplsp-docker-langservers][emacslsp/lsp-docker-langservers]]
- [[#emacslsplsp-docker-full][emacslsp/lsp-docker-full]]
- [[#custom-language-server-containers][Custom language server containers]]
** 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 "<path-to-lsp-docker-dir>")
(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)/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. '<image>:<tag>'. 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: <path-on-host>
destination: <path-on-lang-server>
... # 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
- [[https://github.com/Silex/docker.el][docker]] - package for managing =docker= images/containers.
** Maintainers
- [[https://github.com/yyoncho][yyoncho]]
- [[https://github.com/rnikoopour][rnikoopour]]
|