# Vim and Note-taking/Writing

· 03.11.2021 · etc

A while ago I posted about research tools I've built and a few parts focused on enhancements to vim (taking screenshots, opening media and links, automatically formatting text from pdfs), which is still my preferred program for writing and note-taking. Here are a few other enhancements that make it a more pleasant experience.

I have all of the following snippets enabled for markdown only (in ~/.vim/ftplugin/markdown.vim).

## Spelling correction

I still make a lot of typos and don't notice until a bit later. This snippet lets you hit <ctrl-f> while in insert or normal mode to automatically fix the closest speling error. This is an example.

setlocal spell

" quickly fix the closest previous spelling error.
imap <c-f> <c-g>u<Esc>[s1z=]a<c-g>u
nmap <c-f> [s1z=`

The only shortcoming is that the default vim dictionary is really lacking, so a lot of common words come up as spelling errors. You can easily add words to the dictionary by moving over them and hitting zg by default.

## Preview markdown as HTML

Sometimes it's easier to read through a markdown file as HTML. This lets you use <leader>v to compile the file and open it in a browser using nom.

" compile and open in browser
nnoremap <leader>v :r !nom view "%:p"<cr>

## Create footnote from text

I try my best to keep my citations organized in anything public-facing, but if you have a lot of footnotes it can be troublesome to manage them all in markdown. This lets me highlight a citation, hit <ctrl-f>, and then fills my clipboard with a markdown-formatted citation to paste in.

" make footnote from selected text
vnoremap <C-f> y:! cite "<C-r>0" \| xsel -b<cr>

## Writing mode

One challenge with writing in vim is that the text width can be too wide. There's a popular plugin called goyo that helps with this by artificially constraining the current vim window to a smaller number of columns, but I always had issues with it. Fortunately I found a much simpler implementation that I adapted below.

" writing mode
" <https://stackoverflow.com/a/59955784>
function! ToggleWriteMode()
let l:name = '_writeroom_'
if bufwinnr(l:name) > 0
colorscheme dark
:bwipeout _writeroom_
else
colorscheme light

" hide vertical split
hi VertSplit ctermfg=bg ctermbg=NONE cterm=NONE

" auto-close writeroom buffers when the text buffer closes
autocmd QuitPre <buffer> :bwipeout _writeroom_

" target column width
let l:target = 90
let l:width = (&columns - l:target) / 2
silent! execute 'topleft' l:width . 'vsplit +setlocal\ nobuflisted' l:name | wincmd p
silent! execute 'botright' l:width . 'vsplit +setlocal\ nobuflisted' l:name | wincmd p
endif
endfunction

In vim it's harder to get a sense of the high-level document structure and navigate through sections. There's a plugin called VOoM that basically adds a table of contents pane for markdown documents. It's nice but a bit cumbersome to jump to it and make your section selection there.

Instead I've set up a way to pull up section headings and quickly jump to them using the fzf.vim plugin (which I'll describe in more detail in the next section) and ripgrep.

" Expects that the line is delimited with ':'
" and the first field is the line number.
function! s:line_handler(line)
let keys = split(a:line, ':')
execute "normal! " . keys[0] . "gg"
endfunction

" Args
" - Source: user ripgrep to search for one or more '#' at the start of a line
"   in the current file
" - Sink: use the line hanlder function above to jump to the selected line
" - Options:
"   - reverse output
"   - split on ':' and take all fields from the 2nd on
"   (i.e. skip the line number)
command! -bang -complete=dir -nargs=? TOC
\ call fzf#run(fzf#wrap('toc', {
\'source': 'rg -Tcsv --line-number --no-heading "^#+" '.expand('%:p'),
\'sink': function('s:line_handler'),
\'options': '--reverse --delimiter=: --with-nth=2..'
\}, <bang>0))