How I

Karl Yngve Lervåg

Research scientist, numerical mathematics

Trondheim, Norway

Who are you and what do you use Vim for?

My name is Karl Yngve Lervåg. I’m a research scientist at SINTEF Energy Research in Trondheim Norway. My main area of research is the study of flow multiphase flow phenomena and thermodynamics.

I use Vim for many things: writing papers (with vimtex), development of numerical codes for solving scientific problems (mostly python and Fortran), writing notes (vimwiki and markdown), writing scripts (bash, zsh, python).

I started using Vim during my undergraduate studies, somewhere around 2003-2004. I learnt early on to use motions and commands, but I have to admit that I was slow to learn about text objects. When I did, it really was a revelation, and I begun to realize that Vi/Vim is like a language for editing text. For me, this has become an essential thing, and today I use modal settings for my terminal shell (zsh) and for my web reader (google chrome with cvim). Anyway, I’ve learnt to use Vim obviously by using it a lot, and through reading custom configurations. I think the help system is very good, and I use it almost daily. I learned to write vimscript through contributing to plugins like LaTeX-Box and through writing my own LaTeX plugin vimtex.

When it comes to versions of Vim: I mainly use gvim, but of course also terminal vim when necessary. I’ve looked into neovim: I like the idea, but with age has also come some conservative attitudes. Vim works for me, and the combination of vim with a terminal is great. So far there are no clear reasons to switch. I use Arch Linux, and as such I tend to use very recent versions of software such as Vim. Today this means 8.0.86.

I have to admit that I have looked into Emacs. It is clearly more powerful and customizable, e.g. because of elisp. I really (really) like Lisp, although I have not had the opportunity of working with it a lot. I think Spacemacs looks very promising, as it combines the good from Emacs and Vim. Also, org-mode is very tempting. There are no real alternatives to it for Vim, even though vimwiki is OK. However, Vim really does work very well for me. After I’ve become quite proficient with vimscript, I find I can typically add/implement features that I want without too much work.

Introduce us to your Vim config.

My configuration consists of my vimrc file, where plugins are loaded with the well known and fantastic vim-plug. I also have a lot of minor additions in a personal “plugin”. Thus my configurations looks like this:

dotvim
├── bundle
├── personal
│   ├── after
│   ├── autoload
│   ├── ftdetect
│   ├── ftplugin
│   ├── indent
│   ├── plugin
│   └── syntax
├── snippets
├── spell

If I clone my dotvim repo, then do cat **/*.vim | wc -l, I find I have 2371 lines of Vim configuration. Most of it is in my vimrc file, which currently is at 1096 lines. Today I think it is a little bit too heavy, and I often try to strip away things I don’t need. I have 59 plugins installed, but I would guess that about 10 of them are not really that useful.

When it comes to options, I think I use rather standard settings. I wrote my vimrc from scratch some time long ago, and I’ve tried to update it with the idea that I should always know what I’m doing.

I’ve relatively recently reverted from using a dedicated statusline plugin, as I have found both that I can easily define my own statusline (and tabline, but I rarely use tabs), and that I want to keep it very simple and distraction free. The latter has become pretty important for me, so I also change the default fold text to remove dashes, I use the cursor to indicate mode, and I change some highlighting options to avoid underlines.

A recent update to my configuration was to disable cursorline when vim focus is lost. Today I use the following autocommands, which I think provides a nice way to indicate where the current focus is.

" Only use cursorline for current window
autocmd WinEnter,FocusGained * setlocal cursorline
autocmd WinLeave,FocusLost   * setlocal nocursorline

I have a few mappings, and I use <space> as my leader key. One of the most important mappings is probably jk -> <esc>, which I like because I now almost never need the <esc> key. I know all the alternatives (move escape to caps lock, etc), but I find this is enough for my needs. Other important mappings to me are gb and gB to change buffers and <leader>ev to open my vimrc file.

Finally, when it comes to plugins, I want to draw attention to junegunn’s vim-easy-align. It provides a very convenient command to interactively tabularize text based on delimiters, :LiveEasyAlign. I don’t use it very often, but I smile every time I do! I also find vim-sandwich by machakann great: It provides both text objects and “verbs” for manipulating surroundings. Opposed to surround.vim by tpope, it allows very advanced surround definitions.

Further, I think Konfekts FastFold plugin is good: It solves the problem with Vim’s slow folding for syntax and expression foldmethods. I also have to mention tpopes fugitive, as well as Shougo’s neocomplete and unite and welle’s targets.vim. Great plugins!

Tell us the story behind vimtex.

vimtex is a plugin for writing LaTeX documents. LaTeX is a system for typesetting beautiful documents, and is very much favored by mathematicians and physicists e.g. because it is easy to write equations. I use it to write my papers, as well as many other things. Although, I should mention that today I use markdown for simple things, because it is more convenient.

I had been contributing to LaTeX-Box for quite awhile before I started on vimtex. I found it was difficult to solve issues, and I was thinking it had to do with the structure of the code. I thought that it shouldn’t take too long to rewrite the code and make things better, and so on a plane to Iceland I started writing vimtex. It began as rewrite of LaTeX-Box, but it didn’t take long until I had updated, changed, moved or removed almost every line.

The core idea was to have a more consistent code structure. And even though there are things I see today that I should have done differently, I think it has been a success. With vimtex I now have a LaTeX plugin that does what I want. It has relevant text objects and good commands for compiling and viewing documents. I think the features are getting close to full, although there might be some improvements to format expressions and motions in the future. Else I think my efforts will mainly focus on solving issues and fixing bugs (strange how there always seem to be some bugs remaining).

The main issues today concern support for Windows, I think. I don’t really use Vim on windows, and even though I do have a Windows computer where I can test things, it takes much more time for me to do it. And time is a thing I really don’t have much of these days. So, as the plugin is getting more popular, so are issues related to running vimtex on Windows. I hope and think that I am getting closer to a version that should work well for most people, but I have realized that I need to add a section in the docs with troubleshooting for Windows. Some things are just too difficult…

I have to say that even though I have mainly developed vimtex all by myself, it would NOT have been possible without the help from users who open issues and help solve them. I think I have been lucky in that there are many users who take their time to write good and thoughtful bug reports and feature requests. This can not be stressed enough: vimtex would not have been as good as it is today without contributions from fellow Vim users who write LaTeX documents!

Share a snippet of Vim script you’ve written and talk about what it does.

command! MergeMode :call s:setup_merge_mode()

function! s:setup_merge_mode()
  if !&diff | return | endif

  " Create straightforward mappings
  nmap     ]] ]n
  nmap     [[ [n
  nnoremap do <nop>
  nnoremap <silent> dp        :diffput 2<cr>
  nnoremap <silent> dol       :diffget 1<cr>
  nnoremap <silent> dor       :diffget 3<cr>
  nnoremap <silent> do1       :diffget 1<cr>
  nnoremap <silent> do3       :diffget 3<cr>
  nnoremap <silent> <leader>q :xa!<cr>

  " Add some more complex mapppings
  let l:sid = matchstr(expand('<sfile>'), '\zs<SNR>\d\+_\ze.*$')
  execute 'nnoremap <silent> u :call ' . l:sid . 'undo()<cr>'

  " Set buffer options
  1wincmd w
  setlocal noswapfile
  setlocal nomodifiable
  3wincmd w
  setlocal noswapfile
  setlocal nomodifiable

  " Move to local window and to first conflict
  2wincmd w
  normal gg]]
endfunction

function! s:undo()
  if winnr() ==# 2
    normal! u
  else
    2wincmd w
    normal! u
    wincmd p
  endif
endfunction

Combined with settings for git and Mercurial, I find Vim is really good at solving merge conflicts.

#
# In .hgrc
#
[merge-tools]
vim.executable = gvim
vim.args = -f -d $local $output $other +MergeMode
vim.premerge = keep-merge3

#
# In .gitconfig
#
[merge]
  tool = mydiff
  conflictStyle = diff3

[mergetool]
  keepBackup = false
  prompt = false

[mergetool "mydiff"]
  cmd = gvim -f -d $LOCAL $MERGED $REMOTE -c "MergeMode"

First, I want to point out that the code snippet displays quite well my coding preference. I typically use two space indentation and I like to keep things in lower case. I use empty lines to separate blocks of code (then { and } make it easy to move between the blocks), and I try to write code that is easy to read - thus that don’t need too many comments. Still, I try to comment things that are difficult to understand.

The function s:setup_merge_mode() does most of the “magic”. First, it does nothing unless the diff option is enabled (i.e., we are diffing something). Next, and important(!): It assumes we are opening three files: The local file is buffer 1 (local = left), the remote file is buffer 3 (remote = right), and the merge result is buffer 2 (middle). The function basically just does two things: Creates some mappings and turns the local/left and remote/right buffers nomodifiable (and turns of swap files). I map ]] and [[ to move between conflicts (note that [n and n come from tpope’s unimpaired). Then I map do1 and do3 (or dol and dor) to diff obtain left|right, and dp to diff put. I use the last mapping only when I’m navigating one of the local or remote buffers. The mappings make it simple to go through the conflicts and choose which side to use. Finally, I use the s:undo mapped to u to allow undos to affect the merge result buffer, even when I am viewing the other buffers. Thus, if I do dp from the local buffer, I can undo it with u.

I have to stress: This snippet is specifically designed for my own workflow, and it needs to be used in a specific way. The function is used to define a command, and I’ve provided examples for how the command should be run in the .hgrc and .gitconfig files.