I want to make block commenting easy. To comment out a range of lines, what I can do is something like: :17,21s/^/# This will comment lines 17 to 21 in Python. But I don't want to write the whole string search and replacement pattern all the time.

Initially I thought of making a parameterized mapping for this, where I could pass the line numbers as parameters to string search and replacement map but then realised that mappings cannot have parameters.

Then I got this function which will comment a range and the comment character can be passed to it as well (like # in Python and // in JavaScript):

command! -range -nargs=? Co call CommentThis(<line1>, <line2>, <q-args>)
function! CommentThis(l1, l2, lead)
    let l:lead = a:lead == '' ? '#' : a:lead
    exe printf('%i,%is+^+%s', a:l1, a:l2, l:lead)

Now doing something like :17,21Co will achieve the task and I can do :17,21Co// (for adding // instead of default #)

My question is: How can I modify this function so as to make it work as a comment toggle? Or add a different command line to it so that I can use command 'Co' for commenting and 'Cu' to uncomment? A search and replace pattern to uncomment a python comment would be :17,21s/^#/.

PS: The reason I don't want to use NERD Commentor is that it doesn't support ranges, it just supports count, where I have to either take the cursor to the line I want to comment or select it. Another plugin I found is Commentary VIM but its command :17,21Commentary is too long for me.

  • 3
    You can already shorten :Commentary to :Co like so :17,21Co. – romainl Oct 27 '15 at 11:11
  • 1
    :17,21call NERDComment('n', 'Toggle') – Sato Katsura Oct 27 '15 at 11:26
  • 2
    command! -range Co <line1>,<line2>call NERDComment('n', 'Toggle') – Sato Katsura Oct 27 '15 at 12:08
  • 2
    By just typing :17,21Co<CR>. – romainl Oct 27 '15 at 12:40
  • 3
    Most of these comments should really be answers...short answers are okay, so let's show the world (and Area 51) how good our "answers ratio" and "time to first answer" really are! :) – Wildcard Oct 27 '15 at 18:54

Now doing something like :17,21Co will achieve the task and I can do :17,21Co// (for adding // instead of default #)

tpope's commentary does this, just tab-expand the command into :17,21Commentary. It'll autodetect filetypes so you don't have to worry about passing # or //. It wont comment blank lines, although I'm not sure why that's necessary?

| improve this answer | |
  • What is the feature to uncomment a line then? – MohitC Oct 29 '15 at 5:27
  • The same command, it acts as a toggle like you want. – fruglemonkey Oct 30 '15 at 0:59

I have written a custom function for commenting in COBOL, you can use something similar for Python.

function! Comment(currmode) range
    let origpos=getpos('.')
    if a:currmode=="visual"
       if mode()=="v"
           let [linestart, colstart] = getpos("v")[1:2]
           let [lineend, colend] = getpos(".")[1:2]
           let [linestart, colstart] = getpos("'<")[1:2]
           let [lineend, colend] = getpos("'>")[1:2]
       if (line2byte(linestart)+colstart) > (line2byte(lineend)+colend)
           let [linestart, colstart, lineend, colend] =
           \   [lineend, colend, linestart, colstart]
       let comcount=lineend - linestart + 1
       call setpos('.',[0,linestart,1])
       let comcount=v:count1
       let linestart=line('.')
    if strpart(getline(linestart),6,1) == '*'
       let comment=0
       let label='uncomment'
       let comment=1
       let label='comment'
    call inputsave()
    let tag = input('Tag for '.label.': ')
    call inputrestore()
    let tag=strpart(Pad(tag,6),0,6)
    let i=1
    while i <= comcount
       if !comment
          let newline=substitute(getline('.'),'^.......',tag.' ','')
          call setline('.',newline)
          let newline=substitute(getline('.'),'^.......',tag.'*','')
          call setline('.',newline)
       let i = i+1
       call setpos('.',[0,linestart+i-1,1])
    call setpos('.',origpos)

And add the following mapping

nmap <silent>cp   :<C-U>call Comment('normal')<CR>
vmap <silent>cp   :<C-U>call Comment('visual')<CR>

COBOL commenting is very specific - comment is * in the 7th column of the line. With this code I can comment code using - a range, visual block, single line and add custom Tag (1st 6 chars of the line) using input at run-time (you probably won't need this).

Ex. If I want to comment 5 lines starting from current line I can-

a. 5cp in normal mode b. select 5 lines using visual block (V-LINE or V-BLOCK) and hit cp

Similarly for un-commenting.

The function basically computes the first and last line of the range. For visual mode I use getpos and for normal mode I use v:count1. Once I get the range, I run the comment/uncomment code in loop to insert the tag and an * in the 7th column.

Hope this is helpful.

| improve this answer | |

I used to do it manually until I found Commentary Master which I now used.

I was in the process of writing a function but had got to use some mappings or a macro that I loaded when the ft was right

For example I used for something like the following, assuming ft=txt but using a sql format comment

  This a a non comment line
 This is  
 So's this  
 This isn't
 This is  

for example recording a macro in w i eqw which goes to the beginning of th current line inserts a /* then adds to the end of the line an */ would look like this 0i/* ^[A */^[ and when you @w on each line does this

This a a non comment line
/* This is   */
/* So's this   */
This isn't
/* This is   */

However for me it was easier to set ft specific registers eg autocmd FileType txt let @b='<!--' which a C-Rb in insert mode put the /* and a matching command mapping to @e would put the close comment.

I had a matching command that removed them in one go, which I've deleted. :(

I prefer the plugin now as I didn't have time to write a function properly

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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