2020-10-08 23:07:35 +02:00
|
|
|
+++
|
|
|
|
title = "Language Server Protocols in Vim"
|
|
|
|
date = 2020-09-16
|
2020-10-15 00:06:47 +02:00
|
|
|
tags = ["vim"]
|
2020-10-08 23:07:35 +02:00
|
|
|
+++
|
|
|
|
Language Server Protocol aka LSP is an open source initiative of ... Microsoft.
|
|
|
|
Each "language server" defines every detail of a programming language's syntax
|
|
|
|
and grammar, like its keywords, and how you put them together. This knowledge
|
|
|
|
base is in turn used by editor helpers who can for instance lint your code or
|
|
|
|
suggest completion, a field of features labeled "Intellisense".
|
|
|
|
|
|
|
|
Since Vim 8, programmers may run asynchronous code in vimscript. This feature is
|
|
|
|
leveraged in some plugins that use LSP to lint or suggest while you type. Let's
|
|
|
|
name [vim-lsp][vim-lsp], [coc.vim][coc.vim] and [vim-ale][vim-ale].
|
|
|
|
|
|
|
|
## Vim plugins on your own
|
|
|
|
|
|
|
|
It is worth noting that coc.vim provides a language server installer (vim-lsp
|
|
|
|
also has `vim-lsp-settings` that _should_ do the job, although I was not able to
|
|
|
|
run it on my system). It is very likely that your operating system chips some,
|
|
|
|
at least if it's a linux. _But_ if you already have Vim running on your OS, it
|
|
|
|
should be quite simple to use one of the formers with a plugin manager. If you
|
|
|
|
don't have any plugin manager, be advised that Vim 8 ships its own plugin system
|
|
|
|
; you just need to unpack the plugin's main directory in
|
|
|
|
`~/.vim/pack/PACK_NAME/start/`. `PACK_NAME` can be anything you want, and its
|
|
|
|
subdirectory `start` can be filled with as many plugins as you please. In this
|
|
|
|
case, you could do for instance :
|
|
|
|
```
|
|
|
|
$ mkdir -p ~/.vim/pack/LSP/start
|
|
|
|
$ cd ~/.vim/pack/LSP/start
|
|
|
|
$ git clone https://github.com/neoclide/coc.nvim
|
|
|
|
```
|
|
|
|
And that's it ! (If you don't have git neither a terminal but still have Vim,
|
|
|
|
you can still go at [coc.vim][coc.vim] and manually unpack the latest version's
|
|
|
|
tarball you Vim's config dir - `pack` should lie next to `ftplugin` et al).
|
|
|
|
|
|
|
|
## Vim plugins in your package manager
|
|
|
|
|
|
|
|
You might prefer to use your system's package manager to install plugins, so
|
|
|
|
that they get upgraded with the rest of the system. In this case you could do
|
|
|
|
for instance in [Arch linux](http://archlinux.org) :
|
|
|
|
```
|
|
|
|
# pacman -S vim-ale
|
|
|
|
```
|
|
|
|
Once properly set up, vim-ale will lint the file you are editing in the
|
|
|
|
background (using Vim 8 async processes). It will send all errors and warnings
|
|
|
|
found while you type to the location window, a temporary "subwindow" that you
|
|
|
|
can check back with `:lw`. See `:help location-list-window` to get more info on
|
|
|
|
this feature. You can jump to the last diagnosed error with `:ll`, and navigate
|
|
|
|
with `:lla` and `:lne`.
|
|
|
|
|
|
|
|
The nice bonus is the completion option. It lists all matching expressions with
|
|
|
|
what you began typing, and as you scroll the list, Vim's `preview-window` pops
|
|
|
|
up and gives a description of whatever you are coding - objects in python,
|
|
|
|
functions in bash, etc.
|
|
|
|
|
|
|
|
I'm afraid vim-ale on its own doesn't know much about any language at all. You
|
|
|
|
will have to feed it with a knowledge provider for each of the languages you
|
|
|
|
care for. See the next chapter about this.
|
|
|
|
|
|
|
|
Meanwhile, I tweaked vim-ale to populate Vim's default completion sequence,
|
|
|
|
remap completion shortcuts, and let the preview window be opened at the bottom
|
|
|
|
with the following content into `~/.vim/plugin/ale.vim` :
|
|
|
|
``` vimscript
|
|
|
|
" vim-ale settings
|
|
|
|
|
|
|
|
" Enable ale completion where available.
|
|
|
|
" This setting must be set before ALE is loaded.
|
|
|
|
let g:ale_completion_enabled = 1
|
|
|
|
let g:ale_completion_autoimport = 1
|
|
|
|
|
|
|
|
" Lets ctrl-x ctrl-o open ale completion
|
|
|
|
set omnifunc=ale#completion#OmniFunc
|
|
|
|
|
|
|
|
" Remap tab, shift-tab and enter to useful completion shortcuts when
|
|
|
|
" completion already began :
|
|
|
|
inoremap <expr> <Tab> pumvisible() ? "\<C-n>" : "\<Tab>"
|
|
|
|
inoremap <expr> <S-Tab> pumvisible() ? "\<C-p>" : "\<S-Tab>"
|
|
|
|
inoremap <expr> <cr> pumvisible() ? "\<C-y>" : "\<cr>"
|
|
|
|
|
|
|
|
" Let preview window open on the bottom (J)
|
|
|
|
augroup previewWindowPosition
|
|
|
|
au!
|
|
|
|
autocmd BufWinEnter * call PreviewWindowPosition()
|
|
|
|
augroup END
|
|
|
|
function! PreviewWindowPosition()
|
|
|
|
if &previewwindow
|
|
|
|
wincmd J
|
|
|
|
endif
|
|
|
|
endfunction
|
|
|
|
```
|
|
|
|
|
|
|
|
## Installing language servers
|
|
|
|
|
|
|
|
You could install your favourite language's language server. For example under
|
|
|
|
Arch :
|
|
|
|
|
|
|
|
# pacman -S bash-language-server
|
|
|
|
|
|
|
|
And then let Vim know about it. Create `~/.vim/plugin/language-servers.vim` and
|
|
|
|
paste :
|
|
|
|
|
|
|
|
``` vimscript
|
|
|
|
" Support for bash
|
|
|
|
if executable('bash-language-server')
|
|
|
|
augroup LspBash
|
|
|
|
autocmd!
|
|
|
|
autocmd User lsp_setup call lsp#register_server({
|
|
|
|
\ 'name': 'bash-language-server',
|
|
|
|
\ 'cmd': {server_info->[&shell, &shellcmdflag, 'bash-language-server start']},
|
|
|
|
\ 'allowlist': ['sh'],
|
|
|
|
\ })
|
|
|
|
augroup END
|
|
|
|
endif
|
|
|
|
```
|
|
|
|
Arch users also get python, C/C++ (in the `ccls` package), and LaTeX language
|
|
|
|
servers in community. I also found `rls-git` for Rust language server, HTML from
|
|
|
|
Microsoft's VSCode, and javascript with `typescript-language-server-bin` in the
|
|
|
|
AUR.
|
|
|
|
|
|
|
|
vim-lsp maintains a list of usual Vim LSP support scripts [on its
|
|
|
|
wiki][vim-lsp-support]. Once you've picked up your choice and installed it it's
|
|
|
|
mostly a matter of copy and paste.
|
|
|
|
|
|
|
|
Well, all this sounded quite systematic ! But ... vim-ale also maintains a list
|
|
|
|
of working linters [here][vim-ale-linters]. And it turns out that before
|
|
|
|
language servers, there was quite a bunch of linters doing the job all right.
|
|
|
|
And vim-ale is able to run those "traditional" linters while you type. And they
|
|
|
|
allow completion while you type. They also bear a smaller footprint. This
|
|
|
|
discussion could go more into the details of each language support, but finally
|
|
|
|
why go for the big overhead of this open source infrastructure ?
|
|
|
|
|
|
|
|
I ended up replacing language servers as follows :
|
|
|
|
|
|
|
|
| language | LSP implementation | linter |
|
|
|
|
|---|---|---|
|
|
|
|
| bash | `bash-language-server` | `shellcheck` |
|
|
|
|
| C/C++ | ? | `ccls` |
|
|
|
|
| css | `vscode-css-languageserver-bin` | `prettier` |
|
|
|
|
| javascript | `typescript-language-server-bin` | `typescript`'s tsserver |
|
|
|
|
| json | `vscode-json-language-server` | `prettier` |
|
|
|
|
| html | `vscode-html-languageserver-bin` | `htmlhint` |
|
|
|
|
| markdown | ? | `mdl` |
|
|
|
|
| python | `python-language-server` | `autopep8` |
|
|
|
|
| vala | `vala-language-server` | `uncrustify` |
|
|
|
|
| vimscript | `vim-language-server` | `vint` |
|
|
|
|
|
|
|
|
[vim-ale]: https://github.com/dense-analysis/ale
|
|
|
|
[vim-ale-linters]: https://github.com/dense-analysis/ale/blob/master/supported-tools.md
|
|
|
|
[vim-lsp]: https://github.com/prabirshrestha/vim-lsp
|
|
|
|
[vim-lsp-support]: https://github.com/prabirshrestha/vim-lsp/wiki/Servers
|
|
|
|
[coc.vim]: https://github.com/neoclide/coc.nvim
|