Simple vim function of visual mode to switch comments (learning exercise)

微信扫一扫,分享到朋友圈

Simple vim function of visual mode to switch comments (learning exercise)

Partly for practice, and partly for personal use, I would like to be able to enter visual mode, select some lines, and then hit “,” which would then toggle commenting. (I know NerdCommenter exists but I want something simple with nothing fancy – and again, this is practice, too.)

I’ve learned that you can do ‘&filetype’ to access the filetype, and that ‘.’ concatenates strings, ==# is case-sensitive string comparison, and =~ is regex matching. I also learned that getline(‘.’) gets the line that visual mode has highlighted (each line if multiple lines are highlighted).

Here’s my (flawed)

.vimrc

vnoremap , :call ToggleComment()
function! ToggleComment()
  "Choose comment string based on filetype.
  let comment_string = ''
  if &filetype ==# 'vim'
    let comment_string = '"'
  elseif &filetype ==# 'cpp'
    let comment_string = '//'
  endif

  let line = getline('.')
  if line =~ '^' . comment_string
    "Comment.
    " How could I do the equivalent of "shift-I to go to the beginning of the
    " line, then enter comment_string"?
  else
    "Uncomment. This is flawed too. Maybe I should just go to the beginning of
    "the line and delete a number of characters over?
    execute 's/^' . comment_string . '//'
  endif
endfunction

One thing I get for the uncomment case, regardless of whether the line is commented or not, is

Pattern not found: ^"

(I tested on my vimrc file.)

Advice appreciated – I feel like this shouldn’t be too complicated.

You can use the range
option after function declatarion, that lets you use two variables that contain the beginning and end of the range, a:firstline
and a:lastline
.

Inside an execute
instruction prepend them to the substitution command to executes it only in that range. At the time of removing apply escape()
to the variable to avoid collision of forward slashes:

function! ToggleComment() range
    let comment_string = ''
    if &filetype ==# 'vim'
        let comment_string = '"'
    elseif &filetype ==# 'cpp'
        let comment_string = '//'
    endif
    let line = getline('.')
    if line =~ '^' . comment_string
        execute a:firstline . "," . a:lastline . 's/^' . escape(comment_string, '/') . '//'
    else
        execute a:firstline . "," . a:lastline . 's/^/=printf( "%s", comment_string )/'
    endif
endfunction

UPDATE: To add and remove comments just before first non-blank character, you have to add optional spaces after the zero-width assertion of beginning of line. This is the part that changes. Note how I add s*
to comparison if it exists comments in that line and add 1
or submatch(1)
in the replacement part of substitutions:

if line =~? '^s*' . comment_string
    execute a:firstline . "," . a:lastline . 's/^(s*)' . escape(comment_string, '/') . '/1/'
else
    execute a:firstline . "," . a:lastline . 's/^(s*)/=submatch(1) . printf( "%s", comment_string )/'
endif

微信扫一扫,分享到朋友圈

Simple vim function of visual mode to switch comments (learning exercise)

Cryptocurrency Reading List For Noobs

上一篇

Sinespace Launch Certified Creators Program To Speed Up User-Generated Content Creation

下一篇

你也可能喜欢

Simple vim function of visual mode to switch comments (learning exercise)

长按储存图像,分享给朋友