Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

Vim automatically inserts a comment when I start a new line from a commented out line, because I have set formatoptions=tcroql. For example (cursor is *):

// this is a comment*

and after hitting <Enter> (insert mode) or o (normal mode) i am left with:

// this is a comment
// *

This feature is very handy when writing long multi-line comments, but often I just want a single line comment. Now if I want to end the comment series I have several options:

  • hit <Esc>S
  • hit <BS> three times

Both of these afford three keystrokes, taken together with the <Enter> this means four keystrokes for a new line, which I think is too much. Ideally, I would like to just hit <Enter> a second time to be left with:

// this is a comment
*

It is important that the solution will also work with different indentation levels, i.e.

int main(void) {
    // this is a comment*
}

hit <Enter>

int main(void) {
    // this is a comment
    // *
}

hit <Enter>

int main(void) {
    // this is a comment
    *
}

I think I have seen this feature in some text editor a few years ago but I do not recall which one it was. Is anyone aware of a solution that will do this for me in Vim? Pointers in the right direction on how to roll my own solution are also very welcome.

share|improve this question
1  
You can use ctrl-u in insert mode to delete the automatically inserted comment markers in one key-chord. –  Etan Reisner Nov 1 '13 at 16:14
    
@EtanReisner that's actually better, but still one keystroke too much for me since it is such a common use case :) –  padde Nov 1 '13 at 16:16
    
You suggested that you wanted to be able to hit enter again to get the behaviour you wanted but ctrl-u is too much? You could try mapping <enter><enter> in insert mode to automatically perform the ctrl-u for you but that would introduce a delay if you ever hit <enter> just once (without hitting anything else). –  Etan Reisner Nov 1 '13 at 16:19
    
Well additionally, it should only trigger if the commented line is empty. A noticeable delay when hitting <Enter> is also unacceptable. –  padde Nov 1 '13 at 16:34
    
It'll only delay if you don't hit any other keys I believe since vim will need to wait to make sure you aren't still planning to hit another key. You could use a function to perform that check too I think though it might not be particularly simple to do. –  Etan Reisner Nov 1 '13 at 16:36

3 Answers 3

up vote 3 down vote accepted

Try this:

function! EnterEnter()
  if getline(".") =~ '^\s*\(//\|#\|"\)\s*$'
    return "\<C-u>"
  else
    return "\<CR>"
  endif
endfunction

imap <expr> <CR> EnterEnter()
share|improve this answer
    
Thanks looks great! Will try when i get home. Do you know a way to extend the regex to match comment markers language independently? The information should be there in the syntax files or something. Maybe i can leverage the syntax feature for this... –  padde Nov 1 '13 at 22:59
    
I mean in C it should match // and /* and * (multiline comments) and in ruby # and so on –  padde Nov 1 '13 at 23:00
    
Obviously, this function is not generic at all. See :h 'comment' and :h format-comment'. –  romainl Nov 1 '13 at 23:15
    
Function modified to work with the # of ruby and the " of vimscript in addition to the classic //. It doesn't really make sense to do anything for the * of C-style multiline comments because it must end with the */ anyway. –  romainl Nov 2 '13 at 0:14
    
Hmm, maybe <CR><CR> could be used to finish the multiline comment... –  romainl Nov 2 '13 at 7:49

I extended @romainl's answer to work with arbitrary languages by generating the regex from Vim's &commentstring:

function! s:IsOnlyComment(getlineArg)
  let commentRegex='^\s*'.substitute(&commentstring,'%s','\\s*','').'$'
  return strlen(matchstr(getline(a:getlineArg), commentRegex)) > 0
endfunction

function! SmartEnter()
  if s:IsOnlyComment('.')
    return "\<Esc>S"
  else
    return "\<CR>"
  endif
endfunction

inoremap <expr> <CR> SmartEnter()

However, I can't seem to remap <CR> at all, this just won't work. For now, I use <CR><CR> until this issue is solved.

share|improve this answer
    
Why <Esc>S? <C-u> does the same without leaving insert mode. Anyway, I had a custom function that did a bunch of things on <CR> and renamed it to SmartEnter() just yesterday after I posted my answer ;-). Also I'm not sure &commentstring is the right choice as it generally only contains one form and it may be "linewise" or "blockwise" (/*%s*/ in C, //%s in Javascript, etc.). –  romainl Nov 2 '13 at 13:34

Remove r from 'formatoptions. That's what that option does. Turning it off will mean you never get vim doing that for you which means you will need to add the leading comment markers when you do actually want them but that's the tradeoff.

share|improve this answer
2  
I actually want Vim to add the comment markers for me, I love this. But i also want a quick way to exit the comment. Thanks for your answer though. –  padde Nov 1 '13 at 16:14
    
Thanks, I just wanted the option removed. –  Gilles Jun 3 at 1:20

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.