wanderings/content/posts/vim-language-servers.md

153 lines
6.3 KiB
Markdown
Raw Normal View History

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