2

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:

  • Place the cursor infront of the @ symbol
  • Ctrl-V: Switch to enter block-select mode
  • Select the column down to the } closing parenthesis using multiple hits of j
  • Shift-I: to enter block-insert
  • Type //
  • ESC to excit
  • Enter to finish the command

--> 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?

TMOTTM
  • 3,286
  • 6
  • 32
  • 63
  • I concur that you would be happier with a plugin, but I just want to let you know that `:s` is flexible with delimiters so you can pick e.g. `#` instead of `/`; also, since you are only replacing once per line (at the start of the line), `g` is not doing anything useful; so this much simpler statement works, and no need to escape anything: `:'<,'>s#^#//` – Amadan Oct 24 '19 at 10:14

5 Answers5

3

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.

Ingo Karkat
  • 167,457
  • 16
  • 250
  • 324
  • I like Commentary: it's super simple, and does everything I need. Select, `gc` — commented. Select, `gc` — uncommented. (You can also `gcu` to uncomment the comment block you're in, without selecting). – Amadan Oct 24 '19 at 10:16
  • @Amadan gc works with text objects too, so `gcap` is easier than e.g., `vapgc`. It’s also a text object, so `dgc` does what you’d expect! – D. Ben Knoble Oct 24 '19 at 11:05
  • 1
    @D.BenKnoble Yeah, I know. I just meant, the only sequence to remember is `gc` (and `gcu`); everything else is derived from `gc` in a standard way: `gcgc` (like `dd`), `gcG` (like dG), `v...gc` (like `v...d`)... It's just that `ap` is not typically what I use with code, as I will often have line breaks within a function. `va{okgc` for a general case would be preferable unless I am sure I can shorten it. – Amadan Oct 24 '19 at 11:06
  • Thanks for the references. Can this also be enabled for the Vim-Plugin of Intellij IDEA? – TMOTTM Oct 24 '19 at 14:09
  • Vim plugins typically just support simple mappings, but not the whole Vimscript, so no. But you can probably leverage IDEA's built-in keys (i.e. `Ctrl-/`) for commenting lines. – Ingo Karkat Oct 24 '19 at 14:24
1

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//
D. Ben Knoble
  • 4,273
  • 1
  • 20
  • 38
1

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'.

Matt
  • 13,674
  • 1
  • 18
  • 27
0

" 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
SergioAraujo
  • 11,069
  • 3
  • 50
  • 40
0

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.

Stun Brick
  • 1,124
  • 6
  • 17