我在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

假设我想取消注释第一个定义中的所有行。。。端部。在Vim中有什么有效的方法可以做到这一点?

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


当前回答

如果您无法安装插件,但仍希望注释字符遵循现有缩进级别,则此答案非常有用。

这里的答案是:1)显示要粘贴到.vimrc中的正确代码,以使vim 7.4+在保持缩进级别的同时,在视觉模式下使用1个快捷键进行块注释/取消注释;2)解释它。代码如下:

let b:commentChar='//'
autocmd BufNewFile,BufReadPost *.[ch]    let b:commentChar='//'
autocmd BufNewFile,BufReadPost *.cpp    let b:commentChar='//'
autocmd BufNewFile,BufReadPost *.py    let b:commentChar='#'
autocmd BufNewFile,BufReadPost *.*sh    let b:commentChar='#'
function! Docomment ()
  "make comments on all the lines we've grabbed
  execute '''<,''>s/^\s*/&'.escape(b:commentChar, '\/').' /e'
endfunction
function! Uncomment ()
  "uncomment on all our lines
  execute '''<,''>s/\v(^\s*)'.escape(b:commentChar, '\/').'\v\s*/\1/e'
endfunction
function! Comment ()
  "does the first line begin with a comment?
  let l:line=getpos("'<")[1]
  "if there's a match
  if match(getline(l:line), '^\s*'.b:commentChar)>-1
    call Uncomment()
  else
    call Docomment()
  endif
endfunction
vnoremap <silent> <C-r> :<C-u>call Comment()<cr><cr>

工作原理:

let b:commentChar='//':这将在vim中创建一个变量。这里的b指的是作用域,在本例中,它包含在缓冲区中,意味着当前打开的文件。您的注释字符是字符串,需要用引号括起来,当切换注释时,引号不是要替换的部分。autocmd BufNewFile,BufReadPost*…:自动命令在不同的事情上触发,在这种情况下,当新文件或读取的文件以某个扩展名结束时,自动命令就会触发。触发后,执行以下命令,这允许我们根据文件类型更改commentChar。有其他方法可以做到这一点,但对新手(像我)来说,它们更容易混淆。作用Docomment():函数以函数开头,以endfunction结尾。函数必须以大写开头。这个确保此函数使用此版本的Doccomment()覆盖以前定义为Doccomment)的任何函数。没有!,我有错误,但这可能是因为我通过vim命令行定义了新函数。执行“”<,“”>s/^\s*/&'.escape(b:commentChar,'\/')。“/e':Execute调用命令。在这种情况下,我们正在执行替换,它可以取一个范围(默认情况下,这是当前行),例如整个缓冲区的%或突出显示部分的“<,”>^\s*是正则表达式,以匹配一行的开头,后跟任意数量的空格,然后将其附加到(由于&)。这个这里用于字符串连接,因为escape()不能用引号括起来。escape()允许您转义commentChar中与参数(在本例中,\和/)匹配的字符,方法是在它们前面加上\。之后,我们再次用替换字符串的结尾连接,该字符串带有e标志。这个标志让我们无声地失败,这意味着如果我们在给定的行上找不到匹配项,我们就不会对它大喊大叫。作为一个整体,这一行允许我们在第一个文本之前放置一个注释字符,后跟一个空格,这意味我们保持缩进级别。执行“”<,“”>s/\v(^\s*)'.escape(b:commentChar,'\/')。“\v\s*/\1/e':这类似于我们上一个巨大的长命令。唯一的是,我们有\v,它确保我们不必逃避我们的(),还有1,它指的是我们用()组成的组。基本上,我们匹配的是以任意数量的空格开头的行,然后是注释字符,然后是任意数量的空白,我们只保留第一组空白。同样,如果这行没有注释字符,e会让我们默默地失败。let l:line=getpos(“'<”)[1]:这设置了一个变量,就像我们对注释字符所做的那样,但l引用了本地作用域(该函数的本地作用域)。在本例中,getpos()获取高亮显示的开始位置,[1]表示我们只关心行号,而不关心列号等其他内容。if match(getline(l:line),'^\s*'.b:commentChar)>-1:你知道if是如何工作的。match()检查第一个对象是否包含第二个对象,因此我们获取开始突出显示的行,并检查它是否以空格开头,后跟注释字符。match()返回索引,如果为true,则返回-1。因为if计算所有非零数字为真,所以我们必须比较输出,看看它是否大于-1。vim中的比较如果为false,则返回0,如果为true,则返回1,这就是if希望看到的正确评估结果。vnoremap<silent><C-r>:<C-u>调用Comment()<cr><cr>:vnoremap意味着在视觉模式下映射以下命令,但不要递归映射(意味着不要更改可能以其他方式使用的任何其他命令)。基本上,如果你是一个vim新手,请始终使用noremap来确保你不会破坏东西<silent>的意思是“我不需要你的言语,只需要你的行动”,并且告诉它不要向命令行打印任何内容<C-r>是我们正在映射的对象,在这种情况下是ctrl+r(注意,在正常模式下,使用此映射,您仍然可以正常使用C-r进行“重做”)。C-u有点让人困惑,但基本上它可以确保你不会忘记视觉高亮显示(根据这个答案,它会让你的命令以“<,”>开头,这就是我们想要的)。这里的调用只是告诉vim执行我们命名的函数,<cr>是指点击enter按钮。我们必须点击它一次才能真正调用该函数(否则我们只是在命令行上键入了call function(),我们必须再次点击它以让替代品一直执行(不确定为什么,但无论如何)。

无论如何,希望这能有所帮助。这将接受用v、v或C-v突出显示的任何内容,检查第一行是否有注释,如果有,尝试取消注释所有突出显示的行,如果没有,则为每行添加一层注释字符。这是我想要的行为;我不只是想让它切换块中的每一行是否有评论,所以在问了多个关于这个主题的问题后,它非常适合我。

其他回答

有时我会被推到一个远程盒子里,我的插件和.vimrc无法帮助我,或者有时NerdCommenter会出错(例如嵌入HTML中的JavaScript)。

在这些情况下,一种低技术的替代方法是内置的norm命令,它只在指定范围内的每一行运行任意vim命令。例如:

评论#:

1. visually select the text rows (using V as usual)
2. :norm i#

这将在每行的开头插入“#”。请注意,当您键入:范围将被填充,因此它看起来真的像:'<,'>norm i#

取消注释#:

1. visually select the text as before (or type gv to re-select the previous selection)
2. :norm x

这将删除每行的第一个字符。如果我使用了一个2个字符的注释,比如//,那么我只需要:norm xx来删除这两个字符。

如果注释如OP问题中那样缩进,那么您可以这样锚定删除:

:norm ^x

意思是“转到第一个非空格字符,然后删除一个字符”。请注意,与块选择不同,即使注释有不均匀的缩进,此技术也有效!

注意:由于norm实际上只是执行常规的vim命令,所以您不限于注释,还可以对每一行进行一些复杂的编辑。如果需要将转义符作为命令序列的一部分,请键入ctrl-v,然后按转义键(或者更简单,只需录制一个快速宏,然后使用norm在每行上执行该宏)。

注2:如果您发现自己经常使用规范,当然也可以添加映射。例如,在~/.vimrc中放入以下行可以让您在进行视觉选择后键入ctrl-n而不是:norm

vnoremap <C-n> :norm

注意3:裸骨vim有时没有编译规范命令,因此请确保使用增强版本,即通常为/usr/bin/vim,而不是/bin/vi

(感谢@Manbroski和@rakslice对本答案的改进)

要注释vim中的块:

按Esc键(退出编辑或其他模式)点击ctrl+v(视觉块模式)使用↑/↓ 箭头键选择所需的线条(它不会突出显示所有内容-这很好!)Shift+i(大写i)插入所需的文本,例如%按Esc键


要取消注释vim中的块:

按Esc键(退出编辑或其他模式)点击ctrl+v(视觉块模式)使用↑/↓ 箭头键选择要取消注释的行。如果要选择多个字符,请使用一种或组合以下方法:使用左/右箭头键选择更多文本要选择文本块,请使用shift+←/→ 箭头键您可以重复按下下面的删除键,就像常规的删除按钮按d或x删除字符,必要时重复

tpope有一个改变生活的插件,叫做vim comments

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

此插件提供:

神志正常正确缩进注释不注释空/不必要的行

用法:

通过Vundle(我猜是病原体)安装。突出显示文本并按:,将显示为:<,'>在此处键入注释:<,'>注释,然后按Enter键。繁荣你做的花蕾。

尽管这个问题已经有了很多答案,但我仍然认为我会对我写的一个小插件大声叫好:commentify。

Commentify使用commentstring设置来决定如何注释掉代码块,因此您不必在配置中保留不同注释类型的映射,并且支持基于行的注释(例如,//)和块注释(例如/**/)。

它还为注释和取消注释块映射了相同的快捷方式(默认为ctrl+c),因此您不必记住两个映射或一组复杂的命令。

通过mark命令标记文本区域,例如ma和mbtype命令::'a,'bg/(.*)/s////\1/

您可以在http://bknpk.ddns.net/my_web/VIM/vim_shell_cmd_on_block.html