Skip to content

Instantly share code, notes, and snippets.

@matveyt
Last active March 21, 2022 11:22
Show Gist options
  • Save matveyt/2717fb5cbe1076c1caa0f008b29c6c6e to your computer and use it in GitHub Desktop.
Save matveyt/2717fb5cbe1076c1caa0f008b29c6c6e to your computer and use it in GitHub Desktop.
Vim won't comment on this

This is a pretty common question by beginners: how do I comment out some stuff? And a pretty common answer is to use Visual-Block mode or substitute command. There's even a wiki page to explain this in detail.

But then the novice keeps asking more and more: How do I uncomment? How do I comment with different filetypes? How do I... And then we come again to the usual "go get and install another 10000+ lines plugin named xxx or yyy". But is it really worth one?

So let's put a problem: (1) write a (very!) small command/function able both to comment and uncomment arbitrary line range; (2) an action to be taken depends on the first non-blank line; (3) comment format follows :h 'commentstring' option to allow for easy customization; (4) blank lines are not to be changed; (5) there are two comment styles supported - with indentation (....//foo) and without one (//....foo).

So my best attempt is:

" ToggleComment({line1}, {line2}, {preserveindent})
function! ToggleComment(line1, line2, pi) abort
    let l:lnum = nextnonblank(a:line1)
    let l:end = prevnonblank(a:line2)
    if l:lnum >= 1 && l:lnum <= l:end
        let l:pat = printf('^\(\s*\)\(%s\)$', printf(escape(&cms, '^$.*~[]\'), '\(.*\)'))
        let l:sub = '\=empty(submatch(2)) ? submatch(0) : submatch(1)..submatch(3)'
        if getline(l:lnum) !~# l:pat
            let l:pat = a:pi ? '^\s*\zs.*' : '.*'
            let l:sub = printf(escape(&cms, '&\'), '&')
        endif
        call setline(l:lnum, map(getline(l:lnum, l:end), {_, v -> empty(v) ? v :
            \ substitute(v, l:pat, l:sub, '')}))
    endif
endfunction

" :[range]Comment[!]
command! -range -bar -bang Comment call ToggleComment(<line1>, <line2>, <bang>0)

Pretty compact, isn't it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment