简体   繁体   中英

vim: mapping key to comment with indentation

Before I was using this in .vimrc to use '+' and '-' to comment the code has been highlighted:

noremap <silent>+ :s/^/\/\/ /<CR>:noh<CR>
noremap <silent>- :s/^\/\/ //<CR>:noh<CR>

so when I comment the code it becomes:

int main() {
//     int x = 0;
//     int y = 0;
    return 0;
}

I want to comment codes with indents, like the following:

int main() {
    // int x = 0;
    // int y = 0;
    return x;
}

However I try to use:

noremap <silent>+ :le<CR>:s/^/\/\/ /<CR>==:noh<CR>                              
noremap <silent>- :le<CR>:s/^\/\/ //<CR>==:noh<CR>

The commenting result looks like:

int main() {
    // int x = 0;
int y = 0;
    return x;
}

I was wondering what is wrong with my mapping and how I can fix it...

In addition, is there a "smarter" way to do this?

(I am willing to learn to write a mapping instead of installing some plugins such as NERDcommenter)

Thanks,

Update:

Maybe I didn't put my questions clear so there are some answers below didn't get what I meant...

Many thanks to everyone who attempted to answer my question, I found Ben's solution is easiest to understand for beginners and rc0r's has less lines as well as it works with multiple level of indentation (even though I don't know what it really does, I will do some self-studying later).

So now the code I use looks like:

if has("autocmd")
    autocmd FileType c,cpp,java,verilog noremap <silent><Leader>. :s:^\(\s*\):\1// :<CR>:noh<CR>
    autocmd FileType c,cpp,java,verilog noremap <silent><Leader>, :s:^\(\s*\)// :\1:<CR>:noh<CR>
    autocmd FileType sh,zsh,python,perl,ruby noremap <silent><Leader>. :s:^\(\s*\):\1# :<CR>:noh<CR>
    autocmd FileType sh,zsh,python,perl,ruby noremap <silent><Leader>, :s:^\(\s*\)# :\1:<CR>:noh<CR>
    autocmd FileType vim noremap <silent><Leader>. :s:^\(\s*\):\1" :<CR>:noh<CR>
    autocmd FileType vim noremap <silent><Leader>, :s:^\(\s*\)" :\1:<CR>:noh<CR>
    autocmd FileType asm noremap <silent><Leader>. :s:^\(\s*\):\1; :<CR>:noh<CR>
    autocmd FileType asm noremap <silent><Leader>, :s:^\(\s*\); :\1:<CR>:noh<CR>
    autocmd FileType vhdl,sql noremap <silent><Leader>. :s:^\(\s*\):\1-- :<CR>:noh<CR>
    autocmd FileType vhdl,sql noremap <silent><Leader>, :s:^\(\s*\)-- :\1:<CR>:noh<CR>
endif

and it works well enough to me.

You say you're using the map on a visual selection.

The problem, then, is that your initial :left command in your mapping ends visual mode, so that the next :s command only acts on the current line instead of the entire visual selection.

You have a couple options:

  1. Use gv to return to visual mode on the last visual selection
  2. Use :'<,'>s instead of plain :s to explicitly set the range to the last visual selection

Either way, you should probably change your noremap to xnoremap instead, so that it only applies in visual mode. You can make another separate nnoremap mapping for normal-mode on a single line without the gv or '<,'>

There's no doubt a better way to do it :) but the following

noremap <silent>+ :le<CR>gv:'<,'>s/^\/\/ ../\/\/ /<CR>gv==:noh<CR>   

changes

int main() {
  //   int x = 0;
  //   int y = 0;
  return 0;
}

to

int main() {
    // int x = 0;
    // int y = 0;
    return 0;
}

Didn't have time to work out the uncomment one yet nor work out how best not to repeat the bits in the substitue

Your command adds // to the begining of the line because you forgot to take whitespace into consideration:

:s/^\s*/\/\/ /

But you should use a plugin instead.

I'm not an expert for setting up vim maps, but with a slightly modified search and replace pattern your initial map should do the trick:

noremap <silent>+ :s:^\(\s*\):\1// :<CR>:noh<CR>
noremap <silent>- :s:^\(\s*\)// :\1:<CR>:noh<CR>

The above regex used for commenting searches for a variable number of space characters at the beginning of a line ( ^\\(\\s*\\) ) and replaces the found pattern with itself (using a back reference \\1 ) followed by the characters for the comment ( \\1// ). The second regex shown above removes the comment chars in a similar way: search for variable number of spaces followed by comment characters ( ^\\(\\s*\\)// ) and replace all that with just the spaces (back reference \\1 ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM