TMOTTM
TMOTTM

Reputation: 3381

Vim command to comment out a selection of lines?

Say I have a bunch of lines:

@Override
public void draw(Graphics g) {
    g.setColor(Color.MAGENTA);
    g.fillRect(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
    g.setColor(Color.BLACK);
    g.drawRect(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
}

When I want to comment them out with // (i prefer line comments instead of block comments), what I do is:

--> The lines are now commented out.

Is there an easier way where I don't need to do the block-select? I found I can use a substitution like :'<, '>s/^/\/\///g but this has two problems:

  1. Its very clumsy and error prone to type (multiple forward and backward slashes need to be escaped)
  2. It places the comment symbols (//) at the beginning of the line (position 0), not at the position where the first character of that line was (so indentation is lost).

How can I insert // on the selected lines at the position of the first character of each line using Vi?

Upvotes: 4

Views: 9555

Answers (5)

Stun Brick
Stun Brick

Reputation: 1244

Make a macro with q, lets put it into the a buffer, so hit qa on a given line. Then press I// to jump to start of line, and comment it out. hit Esc and q and now your macro is done. This macro will comment out the current line.
The full command is qaI//Escq

Now visually select a bunch of lines with V, and type :norm!@a to run your a macro over those lines. This will comment out a bunch of lines.

Record another macro to do the opposite with qb^xx. This can be invoked by visually selecting the lines you want to uncomment and typing norm!@b

You can save these macros in your .vimrc and map the specific macro to a key combination if you want to "save" these commands.

Upvotes: 0

SergioAraujo
SergioAraujo

Reputation: 11800

" I have a 'toggle comment function' that looks like " Reference: https://stackoverflow.com/a/24652257/2571881

" these lines are needed for ToggleComment()
" Reference: https://stackoverflow.com/a/24652257/2571881
autocmd FileType c,cpp,java      let b:comment_leader = '//'
autocmd FileType arduino         let b:comment_leader = '//'
autocmd FileType sh,ruby,python  let b:comment_leader = '#'
autocmd FileType zsh             let b:comment_leader = '#'
autocmd FileType conf,fstab      let b:comment_leader = '#'
autocmd FileType matlab,tex      let b:comment_leader = '%'
autocmd FileType vim             let b:comment_leader = '"'

function! ToggleComment()
    if exists('b:comment_leader')
        let l:pos = col('.')
        let l:space = ( &ft =~ '\v(c|cpp|java|arduino)' ? '3' : '2' )
        if getline('.') =~ '\v(\s*|\t*)' .b:comment_leader
            let l:space -= ( getline('.') =~ '\v.*\zs' . b:comment_leader . '(\s+|\t+)@!' ?  1 : 0 )
            execute 'silent s,\v^(\s*|\t*)\zs' .b:comment_leader.'[ ]?,,g'
            let l:pos -= l:space
        else
            exec 'normal! 0i' .b:comment_leader .' '
            let l:pos += l:space
        endif
        call cursor(line("."), l:pos)
    else
        echo 'no comment leader found for filetype'
    end
endfunction
nnoremap <Leader>t :call ToggleComment()<CR>
inoremap <Leader>t <C-o>:call ToggleComment()<CR>
xnoremap <Leader>t :'<,'>call ToggleComment()<CR>
" vnoremap <Leader>t :call ToggleComment()<CR>

So, once you have this function on your ~/.vimrc you can do:

vip ...................... visual inner paragraph
<leader>t ................ in order to call the function

Upvotes: 0

Matt
Matt

Reputation: 15091

How can I insert // on the selected lines at the position of the first character of each line using Vi?

Although, I'm agree with others and the dedicated plugin is a must have, but, as it is formulated in the OP, that's quite an easy task which can be implemented as one-liner:

vnoremap <silent>gc :call setline(".", printf("%*s" . &cms, indent("."), "", trim(getline("."))))<CR>

Now select some text, press "gc", and, voila, it works. To force // usage instead of the default /**/ set the following option for your buffer: setlocal cms=//\ %s. See :h 'cms'.

Upvotes: 1

D. Ben Knoble
D. Ben Knoble

Reputation: 4673

I use Commentary as in the other answer, but a few thoughts:

  • <C-v>jjjjj could be <C-v>} or <C-v>/}<CR>
  • :substitute doesn’t have to use / as a separator: :'<,'>s-^-//
  • with a visual selection, you can also do :'<,'>normal! I//

Upvotes: 1

Ingo Karkat
Ingo Karkat

Reputation: 172550

You can define a custom mapping or command for your :substitute.

However, there are several commenter plugins that do this very well, and those are generic (and often extensible) so that they work for any filetype:

I'd highly recommend to use one of those plugins instead of trying to reinvent a poor solution yourself.

Upvotes: 3

Related Questions