Polyglot Programming in Vim (or How to Get A Great Developer Experience for Any Language in Vim)
Vim comes with basic support for tons of languages out of the box like syntax highlighting and sensible rules of indentation. However, even with popular languages like JavaScript you won’t get great autocompletion, semantic navigation, diagnostics, etc… Features that you may have come to expect in this day and age. And when it comes to more modern or niche languages like Svelte, JSX or TSX, the syntax highlighting isn’t even there.
In this article you’ll learn how to setup Vim to get a better developer experience with both popular programming languages like JavaScript and modern languages like TypeScript, Svelte and JSX.
How to Get a Great Developer Experience for Any Language in Vim
Whenever you want to add support for a new language in Vim ideally your goal should be to have at least these two things set up:
- Proper syntax highlighting and indentation for that new language
- IDE-like features like autocompletion, semantic navigation, diagnostics, etc… That can make your life easier when working on that language
The easiest way to achieve both of these goals in Vim is by taking advantage of the rich Vim plugin ecosystem.
1. Syntax Highlighting
In order to add syntax highlighting for a new language in Vim you can follow any of these approaches:
- Install a syntax highlighting plugin for your language of choice (e.g. vim-svelte for Svelte, yats.vim for TypeScript).
- Install the vim-polyglot plugin. vim-polyglot is a language pack for Vim that provides syntax highlighting and indentation for lots and lots of programming languages. This plugin is written in a way that only loads plugins lazily and therefore it isn’t a burden to your vim startup initialization time.
- Write you own syntax highlighting plugin or overwrite parts of existing plugins.
You can freely choose among any of the above but I personally enjoy knowing exactly what’s on my vim config and having a modicum of control over that. That’s the main reason why I choose to install separate plugins for each language that I’m going to be working with.
VimAwesome.com is a great way to find plugin for new languages. It is a directory of Vim plugins where you can search for keywords (like TypeScript) and see a ranking of the most popular plugins for that keyword. For instance, these are all the TypeScript plugins available, which range from syntax plugins to autocompletion, formatting, linting, etc.
I’ve tried vim-polyglot but I found it had too many drawbacks to enjoy using it:
- From experimenting with the plugin it only includes syntax highlighting and indentation extracted from other language plugins. That is, additional features like mappings and commands, which are often really useful, are not included. This means that if you want to enjoy these additional features, all of the sudden you need to have vim-polyglot plus the original plugin within your vim config (which kinds of defeats the purpose of a language pack).
- If there is another plugin for a given language that you find more useful than the one that comes with vim-polyglot, you need to deactivate that one and install your plugin of choice.
Finally, writing my own customs syntax highlighting wouldn’t be my first choice but it can be useful at times like:
- When there are no plugins available for a given language (I’ve never run into this yet)
- When the syntax highlighting for a language isn’t good enough
- When you’re writing a plugin that provides its own special UI and you want it to look pretty (e.g. imagine writing a music player in Vim and you want to highlight the albums).
Excellent! So at this point we have syntax highlighting and proper indentation for that new language you want to start tinkering with. This gives you a basic development environment where you can get visual feedback of the different components of the syntax of a language plus all the amazing features that make Vim a great editor on its own.
What’s next? Adding IDE-like features!
2. IDE-like Features
I started my career in software development within the .NET ecosystem writing C# and using tools like Visual Studio and ReSharper so I’ve always been quite spoiled with powerful features like in-editor diagnostics, statement completion, smart refactorings, semantic code navigation, automagic code fixes, project wide renamings, etc… Some years ago it would’ve been mighty hard to get all these features into Vim, but today, with a growing number of LSP 1 enabled language servers we can enjoy all of these features right within Vim.
There’s numerous plugins available that provide this kind of functionality but of all the ones that I’ve tried I find that coc.nvim or Conquer of Completion provides the best support and strikes a great balance between ease of setup and number of features. In order to get coc.nvim set up for a given language you will need to follow these two steps:
- Install the coc.nvim plugin in Vim using your favorite plugin manager. You only need to do this once.
- Install and extension for that specific language (for example, you can run the
:CocInstall coc-tsserver
command to provide IDE-like support to JavaScript and TypeScript). There are a lot of extensions available for many popular programming languages. When installing an extension for a new language it is recommended to take a look at the documentation for that extension to see whether there’s some additional configuration required (e.g. coc-tsserver works out of the box but the docs provide additional information about how to configure it further).
Once installed coc.vim will be activated as soon as you open a file that matches one of your extensions. For instance, if you’ve installed coc-tsserver, any time that you open a TypeScript file coc.nvim will spring to life. It is useful to add the coc.nvim status information to your status line in Vim. That way you get immediate feedback that coc.nvim is working as expected whenever you open a file. Alternatively, you can use the :CocInfo
command to get detailed information about the current status of coc.nvim:
## versions
vim version: NVIM v0.4.2
node version: v12.6.0
coc.nvim version: 0.0.74-3712edf331
term: iTerm.app
platform: darwin
## Messages
## Output channel: tsserver
[Info - 12:55:23 PM] Started TSServer
{
"path": ".../.config/coc/extensions/node_modules/coc-tsserver/node_modules/typescript/lib",
"_pathLabel": "",
"_api": {
"versionString": "3.7.3",
"version": "3.7.3"
}
}
Each extension acts as a source of functionality and you can reach those sources using different coc.nvim commands. For example:
- You can use
:CocInstall {extension}
to install extensions :CocList
lets you access lists from different sources. Some examples are::CocList extensions
list your installed extensions:CocList outline
gives you an outline of your current file (like the one you’d get in an editor like VSCode or Visual Studio):CocList snippets
gives you a list of available snippets:CocList diagnostics
gives you a list of errors and warnings
:CocCommand {command}
lets you run a command provided by a source. For instance::CocCommand snippets.editSnippets
sends you to the snippets file for the language of your current file:CocCommand tsserver.executeAutoFix
fixes all autofixable errors that exist currently (e.g. missing imports and incorrectly implemented interface)
:CocAction
lets you perform actions to the code under you cursor or your current selection. Really useful actions like renaming, adding missing imports, refactorings like extract function or constant, extracting a snippet, etc.:CocFix
lets you apply fixes recommended by the language server
You can find a lot more information on how to setup coc.nvim, how to install extensions, how to configure it and how to provide a minimal configuration with sensible mappings on GitHub. The latter is super recommended with useful bindings such as these:
" Use `[g` and `]g` to navigate diagnostics
nmap <silent> [g <Plug>(coc-diagnostic-prev)
nmap <silent> ]g <Plug>(coc-diagnostic-next)
" Remap keys for gotos
nmap <silent> gd <Plug>(coc-definition)
nmap <silent> gy <Plug>(coc-type-definition)
nmap <silent> gi <Plug>(coc-implementation)
nmap <silent> gr <Plug>(coc-references)
coc.nvim also comes with a comprehensive documentation that you can find directly within vim using the always handy help command :h coc-nvim
.
Other alternatives to coc.nvim that are very established are YouCompleteMe, Ale, Deoplete and vim-lsp. You can also find a comprehensive list of IDE-like plugins in vimawesome.org.
Regardless of which plugin you choose in the end, I hope that the next time you configure Vim to use a new language you’ll get an amazing development experience. Take care and have a wonderful day.
- LSP stands for Language Server Protocol. (From wikipedia) It is an open, JSON-RPC-based protocol for use between text editors or IDEs and servers that provide programming language-specific features. The goal of the protocol is to allow programming language support to be implemented and distributed independently of any given editor or IDE.↩
Written by Jaime González García , dad, husband, software engineer, ux designer, amateur pixel artist, tinkerer and master of the arcane arts. You can also find him on Twitter jabbering about random stuff.