Poor man's snippets

1 Point

Lifepillar Lifepillar

1 month ago

To expand a snippet, type the name of the snippet followed by (this is a single character, not three dots: in my keyboard it is obtained with alt-.). For the details, see the comments in the code below.

" Put this line:
" 
"     call LoadSnippets()
" 
" in ~/.vim/after/ftplugin/<filetype>.vim for every file
" type for which you want to define snippets.
" The snippets themselves must be put into a plain text file
" ~/.vim/snippets/<filetype>.txt.
fun! LoadSnippets()
  let l:file = readfile($HOME.'/.vim/snippets/'.&ft.'.txt')
  let b:snippets = {}
  for l:line in l:file
    if l:line =~ '^snippet'
      let l:key = matchstr(l:line, '^snippet\s\+\zs.\+$')
      let b:snippets[l:key] = []
    else
      call add(b:snippets[l:key], l:line)
    endif
  endfor
  inoremap <buffer> <c-b> <esc>gnc
endf

" The syntax for each snippet is very simple. For example:
" 
"     snippet for
"     for (i = 0; i < ___; i++) {
"        ___ 
"     }
" 
" The first line is the keyword `snippet` followed by the
" text that should trigger the snippet (`for` in this case).
" The following lines contain the text that will be inserted
" verbatim when the snippet is expanded. Such lines may
" contain `___` placeholders (at least one placeholder must
" be present). The cursor will be put on the first
" placeholder when the snippet is expanded. Typing CTRL-B in
" Insert move will jump to the next placeholder.
fun! ExpandSnippet()
  let l:key = matchstr(getline('.'), '\S\+\%'.col('.').'c')
  let l:snippet = get(b:snippets, l:key, [])
  if !empty(l:snippet)
    let l:indent = matchstr(getline('.'), '^\s\+')
    call setline('.', l:indent . l:snippet[0])
    call append('.', map(l:snippet[1:-1], { _,t -> l:indent . t}))
    call search('___', 'csW')
    let @/ = '___'
    normal 3x
    return ''
  endif
  return '…'
endf

inoremap <silent> … <c-r>=exists('b:snippets') ? ExpandSnippet() : '…'<cr>