Introduction
Just under a year ago our very own Neil Mitchell blogged about his vision of a GHC IDE. Today, this project forms the core of DAML’s IDE. It’s maintained by @cocreature and team; also, @shaynefletcher has added support for hlint
, as was intended in the original post. All this ships as a plugin to VSCode - but what if, like me, you’re obstinate and don’t want to switch to a new editor, and want to stick to vim
? Read on …
In this post I will show you how to integrate Microsoft’s Langauge Server Protocol into vim
. LSP is what allows VSCode to provide real-time error highlighting, code snippets, auto-complete etc., while remaining language agnostic. In fact, this will work not only for DAML but for a large number of other languages as well; we’ll only cover DAML here though.
Setup
LSP is a client-server architecture. The client sits in your editor (vim
in our case) and displays the information which it gets from the language server, such as errors, on your screen.
1. Client
There are a number of LSP clients available for vim
; I’ve chosen vim-lsp as it’s fully written in vim
s native scripting language, and it’s also non-blocking, making it light-weight.
We’re going to install it using Vim 8’s native packaging system. Again, you have a wide number of package managers you can choose from, but I’ve selected the built-in one as it doesn’t require installing even more stuff on my system. Simply:
mkdir -p ~/.vim/pack/async/start
cd ~/.vim/pack/async/start
git clone https://github.com/prabirshrestha/async.vim.git
mkdir -p ~/.vim/pack/lsp/start
cd ~/.vim/pack/lsp/start
git clone https://github.com/prabirshrestha/vim-lsp.git
(n.b. yes, you need to clone everything under start/
- it’s a bit weird).
2. Server
So where are we going to find a LSP DAML language server? Googling doesn’t seem to turn up anything. I’ll let you in on a little secret: the daml SDK itself contains a fork of hgcide, which I told you about in the introduction! You can run it with the daml assistant like so: daml damlc ide
. If you try this it won’t appear to do anything - it just sits there and listens for commands from the client.
To make the language server start this automatically with vim
, append the following to your .vimrc
:
au User lsp_setup call lsp#register_server({
\ 'name': 'damlc',
\ 'cmd': {server_info->['daml', 'damlc', 'ide', '--RTS', '+RTS', '-M6G', '-N']},
\ 'whitelist': ['daml'],
\ })
Restart vim
, and that’s it! You should now have working code integration. You can check this by opening a *.daml
file and then typing :LspStatus
in vim. You should see:
damlc: running
Troubleshooting
When I went through above process myself, I ran into a couple of problems:
-
First of all, you should check that you have a working SDK. Create a skeleton project using
daml new
and then compile it withdaml build
. If you can’t get that to work, refer to the official documentation to install the DAML SDK. -
If error highlighting isn’t working, ensure you are on a recent version of Vim, preferably 8.2. There are known issues with earlier versions. If like me, you’re using Ubuntu LTS 18.04, you will have to upgrade to 20.04 or use a custom PPA.
-
When we (manually) installed the LSP client, we pulled down the latest development version - if you’re experiencing problems, you may want to switch to a stable release, by going to
.vim/lsp/start
, andgit check
ing out a stablegit tag
.
What next?
Head on over to github vim-lsp to learn more about how to use this extension. For instance, try :LspDocumentDiagnostic
to populate the quick fix buffer with a list of errors (:help :ll
). Sadly this doesn’t update in real-time, so you may want to create an auto-command (:help :au
) to execute this every time you save the file.
Why do I need LSP at all? Why vim
?
Vim does provide a :make
command (:help :make
) that also allows you to get error highlighting. Previously I was using this with a custom configuration (remind me to post it here later). This works fine for smaller projects, but when I started working on one of our larger client projects - by large I mean tens of thousands of lines of code - I found that even with the daml build --incremental=yes
flag, build times would run into the minutes.
The language server, on the other hand, is able to provide instantaneous feedback. It seems that this is at the cost of only processing open buffers. So for instance it doesn’t seem know how to find definitions outside the current file. I’m not certain whether this is a limitation of the vim plugin, or an issue with the LSP.
As for vim
: well, I’ve been using it for 20 years now. I was forced into it at my first job, where we were configuring a bank’s trading systems that ran on Solaris servers. We would need to telnet to the servers, and I found that vi
was ubiquitous at the time (and probably still is) - you would always find it pre-installed on Unix systems. Since then, I’ve grown accustomed to it. It’s lightweight, extremely configurable, and fast. And well, better than emacs
of course …