在Vim中,有什么快速的方法可以注释/取消注释行呢?

1542

我在vi中打开了一个Ruby代码文件,其中有用#注释掉的行:

class Search < ActiveRecord::Migration
  def self.up
    # create_table :searches do |t|
    #   t.integer :user_id
    #   t.string :name
    #   t.string :all_of
    #   t.string :any_of
    #   t.string :none_of
    #   t.string :exact_phrase
    # 
    #   t.timestamps
    # end
  end

  def self.down
    # drop_table :searches
  end
end

假设我想取消注释第一个 def ... end 段落中的所有行,有没有在 Vim 中高效完成的方法?

总的来说,我正在寻找一种简单流畅的方法来注释和取消注释代码行。这里涉及到 Ruby 代码,但也可能是 JavaScript (//) 或 Haml (-#)。


50
应该将被接受的答案更改为其中一个详细说明如何在不使用插件的情况下添加/取消注释块的答案。当前被接受的答案基本上只是一个指向第三方插件的链接。 - faintsignal
最高评分的答案没有提到任何插件,@rationalis的评论是误导性的,请您纠正或删除它,谢谢。 - bonobo
接受的答案应该是Magnus的回答 - user3313834
一个理想的解决方案是,一个热键可以切换注释“关闭”和“打开”,无论是“光标所在行”还是“选择的多行”。其他任何操作都太麻烦了。 - Lonnie Best
55个回答

21

我使用vim 7.4,以下是如何对3行进行注释/取消注释:

注释:

如果行首无tab/space:
ctrl + V,然后jjj,再按shift + I(大写i),输入//,最后按esc esc
如果行首有tab/space,可以使用上述方法或者选用c
ctrl + V,然后jjj,再按c,输入//,最后按esc esc

取消注释:

如果行首无tab/space:
ctrl + V,然后jjj,再按ll(小写L),按下c

如果行首有tab/space,则需要空出一个位置,再按下esc
ctrl + V,然后jjj,再按ll(小写L),按下c,再空出一个位置,按下esc


20

这是我.vimrc的一部分:

"insert and remove comments in visual and normal mode
vmap ,ic :s/^/#/g<CR>:let @/ = ""<CR>
map  ,ic :s/^/#/g<CR>:let @/ = ""<CR>
vmap ,rc :s/^#//g<CR>:let @/ = ""<CR>
map  ,rc :s/^#//g<CR>:let @/ = ""<CR>

在正常模式和可视模式下,这让我可以按 ,ic 插入注释并按,rc 删除注释。


这对于初学者学习如何编写自己的.vimrc非常有帮助。 - coolesting
6
map 包含正常模式和可视模式,因此您不需要 vmap 行。 - doubleDown
更好的位置在 after/ftplugin/ruby.vim - Santosh Kumar
请使用 <leader>ic<leader>rc - Hans Kristian

20

Visual 和 Shift-I 对我不起作用。

最简单的方法是:


  1. 选择块 - 用 V 选中然后使用 j 或者 k 或者任何相关动作(不要使用箭头键) :)

  2. 然后按下 : ,就会提示命令 :'<,'>

    进行注释

Using #  - `s/^/#/` 

Using `//` - `s/^/\/\//`

取消注释

Using #  - `s/^#//` 

Using `//` - `s/^\/\//`

说明:

'<,'> - 应用于可视块

s - 替换

^ - 以 ... 开始

/ 后加入字符 #,在这种情况下,\/\/ 转义成了 //


更新

我编写了一个函数来使用 <Space><Space> 注释和取消注释当前行。

例如,对于下一行的 10 个字符,可以使用 10<Space><Space>

将其粘贴到 .vimrc 中

function CommentUncomment()
  let line = getline('.')
  if line[:1] == "//"
      norm ^2x
  else 
      norm I//
  endif
endfunction

nnoremap <Space><Space> :call CommentUncomment()<CR>

3
这是我找到的最简单的方法。在这种情况下,插入命令的完整指令是 '<,'>s/^/#/g。对于我来说,如果没有在结尾添加 /g,它就无法工作,这表示光标移动到 '<,'> 范围的末尾。 - RicHincapie
1
如果您启用了行号,可以执行以下操作::1,10 s/^/#/ 来注释第 1 至 10 行。 - tomato
1
不需要转义斜杠,只需使用其他分隔符号: :s#^#// - Alexander Stumpf

18

我将Phil和jqno的答案组合起来,并使用空格制作了未切换的注释:

autocmd FileType c,cpp,java,scala let b:comment_leader = '//'
autocmd FileType sh,ruby,python   let b:comment_leader = '#'
autocmd FileType conf,fstab       let b:comment_leader = '#'
autocmd FileType tex              let b:comment_leader = '%'
autocmd FileType mail             let b:comment_leader = '>'
autocmd FileType vim              let b:comment_leader = '"'
function! CommentToggle()
    execute ':silent! s/\([^ ]\)/' . escape(b:comment_leader,'\/') . ' \1/'
    execute ':silent! s/^\( *\)' . escape(b:comment_leader,'\/') . ' \?' . escape(b:comment_leader,'\/') . ' \?/\1/'
endfunction
map <F7> :call CommentToggle()<CR>

它是如何工作的:

假设我们使用#-注释。

第一个命令 s/\([^ ]\)/# \1/ 搜索第一个非空格字符 [^ ] 并将其替换为 # +它本身。在搜索模式中,\(..\) 执行它本身的替换操作,在替换模式中,\1 用于指代原来的那个字符。

第二个命令 s/^\( *\)# \?# \?/\1/ 搜索以双井号开始的行 ^\( *\)# \?# \?(接受0或1个空格),并简单地将这些行替换为非注释部分 \( *\)(意思是前面有相同数量的空格)。

有关vim模式的更多详细信息,请查看此链接


11
如果您已经知道行号,那么n,ms/# //可以使用。

实际上应该这样写:n,ms / ^ \ s。#// 因为您可能有前导空格,并且可能不会在哈希后跟随一个。 - Skip Huffman

11

在我前面有30个答案,我尝试给出一个更简单的解决方案:在行首插入#,然后换行并按下点号 (.)。要重复操作,可以使用j,.,j,.等方法。要取消注释,删除#(可以在#上按下x),然后使用k,.等反向操作即可。


1
这是一个非常简单的答案,即使是初学者也可以理解和使用。但是,在大量行进行注释时,它的工作速度相当慢。为了解决这个问题,您可以将I#<Esc>j写入缓冲区(比如c),然后执行10@c或适合你的任意行数。 - Daerdemandt
这么简单的任务需要使用如此繁琐的按键组合:( 我经常使用cmd+/进行注释和取消注释,缺乏内置该功能是我不使用vim进行严肃工作的原因。 - Sebastian

10

如何在 vi 中取消注释以下三行:

#code code
#code
#code code code

将光标放在左上角的#符号上,按下CtrlV键,进入可视块模式。按下向下箭头或J键三次选择所有三行,然后按下D键。所有注释都将消失。要撤消,请按U键。

如何在vi中注释下面的三行:

code code
code
code code code

将光标放在左上角的字符上,按CtrlV。这将使您进入可视块模式。按J键三次以选择所有三行。然后按下:

I//Esc

那是一个大写字母I、两个斜杠和Escape。

当您按下ESC键时,所有选定的行都将获得您指定的注释符号。


1
如果你错过了“左上角”的井号,你可以在可视模式下按 o 键将光标移动到“另一侧”。 - dylnmc
我认为这是最好的选择。不需要任何第三方工具,只需使用本地的vim即可。 - Ardi Nusawan
最佳答案,简单明了,不涉及任何第三方。 - aze

9

8

有一款由 tpope 制作的插件叫做 vim-commentary,它可以改变你的生活。

https://github.com/tpope/vim-commentary

这个插件提供了以下功能:

  • 更加清晰明了
  • 正确缩进注释
  • 不会注释掉空白或无关紧要的行

使用方法:

  • 通过 Vundle 安装(或者是 Pathogen)。
  • 选中你想要注释的文本并按下 :,会显示为 :<,'>
  • 输入 Commentary,即 :<,'>Commentary,然后按下 Enter
  • 完成!

vim-commentary(就像tpope的所有插件一样)的优点是它符合vim的习惯用法。 gc =“go comment”,gcap =“go comment a paragraph”等。 - goldenratio
这可能只是Jim Stewart对Tim Pope答案的编辑吗? - SO_fix_the_vote_sorting_bug

8
是的,这个问题已经有33个(大多数是重复的)答案了。
以下是另一种在Vim中如何注释代码的方法:motions。基本思路是使用与yanking段落相同的方法来注释或取消代码行,例如输入yip可以复制整个段落,输入dj可以删除两行。
使用这种方法,你可以做到以下几点:
  • 输入ccj可以注释下面2行,cuk则可以取消注释;

  • 输入cci{可以注释一个块,cui{则可以取消注释;

  • 输入ccip可以注释一个整段,cuip则可以取消注释;

  • 输入ccG可以注释从当前行到最后一行的所有内容,cugg则可以取消注释从第一行到当前行的所有内容。

你只需要两个操作motion的函数和对应的两个映射即可实现以上功能。首先是映射:
nnoremap <silent> cc  :set opfunc=CommentOut<cr>g@
vnoremap <silent> cc  :<c-u>call  CommentOut(visualmode(), 1)<cr>
nnoremap <silent> cu  :set opfunc=Uncomment<cr>g@
vnoremap <silent> cu  :<c-u>call  Uncomment(visualmode(), 1)<cr>

请查看有关g@运算符和operatorfunc变量的手册。

现在是函数列表:

function! CommentOut(type, ...)
  if a:0
    silent exe "normal!  :'<,'>s/^/#/\<cr>`<"
  else
    silent exe "normal!  :'[,']s/^/#/\<cr>'["
  endif
endfunction

function! Uncomment(type, ...)
  if a:0
    silent exe "normal!  :'<,'>s/^\\(\\s*\\)#/\\1/\<cr>`<"
  else
    silent exe "normal!  :'[,']s/^\\(\\s*\\)#/\\1/\<cr>`["
  endif
endfunction

根据您对#的位置偏好,修改上述正则表达式:


“完全新的[...]动作”似乎有点过头了:t_comment和vim-commentary插件都早于这个答案,允许您使用动作进行注释。 - Rich
好东西!已点赞。(我也觉得我可能会开始使用这种方法,而不是之前使用的插件,所以感谢您编写它!) - Rich

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接