我在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(-#)。


当前回答

前面有30个答案,我将尝试给出一个更简单的解决方案:在行的开头插入#。然后沿直线向下按点(.)。要重复,请执行j,。,j要取消注释,请删除#(可以在#上单击x),然后使用k、.、,。,等

其他回答

我使用Tim Pope的vim评论插件。

很好的问题,但没有那么多好的答案。首先,我想说,在这里使用块插入模式不是一个简单的解决方案,只是击键太多,所以显然它必须在选定的行上工作,以提高代码编辑的性能。另一个没人提到的问题是:注释符号应该放在哪里-在行首或实际文本之前?这可能是一个品味问题,但我认为,应该将它放在文本之前,以保持代码可读:当注释符号放在最开始的一行时,它会破坏缩进代码的视觉一致性,因此看起来像一个项目符号列表。考虑到这一点,我最终得到了以下解决方案(我以#comment为例)。在我的vimrc中:

vnoremap 1 :s:^\(\s*\)\([^#\t ]\):\1#\2:e<CR>
vnoremap 2 :s:^\(\s*\)#\(\s*\):\1\2:e<CR>

键1在每个选定行的文本前(空格后)插入#。它检查是否已经有#,而不是两次插入#。并且还忽略空行。键2删除一个#。它还可以确保行右侧的注释安全。


更新:这里是一个示例,说明如何生成依赖于文件类型的切换注释命令。要了解更多信息,请阅读:http://learnvimscriptthehardway.stevelosh.com/chapters/14.html

为了使其正常工作,在.vimrc文件中放入以下行。

" build the whole regex search/replace command
function! Build()
    let b:Comment_ON='''<,''>s:^\(\s*\)\([^\t ]\):\1' . b:cs . '\2:e'
    let b:Comment_OFF='''<,''>s:^\(\s*\)' . b:cs . '\(\s*\):\1\2:e'
endfunction

" run this group on Filetype event
augroup SetCS
    autocmd!
    "default comment sign
    autocmd FileType * let b:cs='--'
    "detect file type and assign comment sign
    autocmd FileType python,ruby let b:cs='#'
    autocmd FileType c,cpp,java,javascript,php let b:cs = '\/\/'
    autocmd FileType vim let b:cs='"'
    autocmd FileType * call Build()
augroup END

vnoremap 1 :<C-u>execute b:Comment_ON<CR>
vnoremap 2 :<C-u>execute b:Comment_OFF<CR>

首先,我要感谢@mike的回答,因为我使用的是它的修改版本。我想发布我的版本,以防有人感兴趣。我的主要功能区别在于,它将始终在射程的每一行上执行相同的动作。如果所选范围包含任何未注释的行,则每一行都会添加注释引线。这样,如果在未注释的代码块中有人类可读的注释,则它们不会变为未注释。然后,当您取消注释块时,人类可读的文本将保持注释状态,因为它有两个注释引线。完成后,它还会恢复光标位置。

ToggleComment函数:

function! ToggleComment() range
    "Ensure we know the comment leader.
    if !exists('b:comment_leader')
        echo "Unknown comment leader."
        return
    endif
    "Save the initial cursor position, to restore later.
    let l:inipos = getpos('.')
    "Make a list of all of the line numbers in the range which are already commented.
    let l:commented_lines = []
    for i in range(a:firstline, a:lastline)
        if getline(i) =~ '^\s*' . b:comment_leader
            let l:commented_lines = add(l:commented_lines, i)
        endif
    endfor
    "If every line in the range is commented, set the action to uncomment.
    "  Otherwise, set it to comment.
    let l:i1 = index(l:commented_lines, a:firstline)
    let l:i2 = index(l:commented_lines, a:lastline)
    if l:i1 >= 0 && l:i2 >= 0 && (l:i2 - l:i1) == (a:lastline - a:firstline)
        let l:action = "uncomment"
    else
        let l:action = "comment"
    endif
    "Loop through the range, commenting or uncommenting based on l:action.
    for i in range(a:firstline, a:lastline)
        "Move to line i.
        exec "exe " . i
        "Perform the action.
        if l:action == "comment"
            exec 'normal! 0i' . b:comment_leader
        else
            execute 'silent s,' . b:comment_leader . ',,'
        endif
    endfor
    "Restore the initial position.
    call setpos('.', l:inipos)
endfunction

键映射(注意,我将注释键更改为“k”):

noremap <Leader>k :call ToggleComment()<CR>

最后,我将autocmds放在下面的“if”语句和augroup中,但它们保持不变。它们大多只是供参考。

if has("autocmd")
    augroup autocmds
        autocmd!
        autocmd FileType c,cpp,java      let b:comment_leader = '//'
        autocmd FileType arduino         let b:comment_leader = '//'
        autocmd FileType sh,ruby,python  let b:comment_leader = '#'
        autocmd FileType zsh             let b:comment_leader = '#'
        autocmd FileType conf,fstab      let b:comment_leader = '#'
        autocmd FileType matlab,tex      let b:comment_leader = '%'
        autocmd FileType vim             let b:comment_leader = '"'
    augroup END
endif

编辑:我从原始答案更新了ToggleComment函数。最重要的是,我修改了正则表达式。在许多情况下,如果字符串中有另一个注释引线实例,它将无法正常工作。我相信它可能必须在前面或后面加一个空格,但我记不起来了。不管怎样,下面是Python的错误示例。

print("Hello, World!") # Says hello to the world.

我已经解决了这个问题,并稍微简化了正则表达式。一个副作用是它不再在评论标题后面添加空格,但这并不困扰我。我在一些变量中添加了一个局部声明,我在最初的答案中忘记了这些变量。

我喜欢简短的、综合的、令人难忘的方法,不依赖于外部脚本——一种花哨的小题大做。。。

TLDR:按gI(大写i)将光标置于插入模式下的行首(无论是空格还是非空格字符,并防止自动缩进)

使用此选项可快速注释(例如)非连续行,注释符号(例如#或//)为第一个字符,不带缩进,方法是按。(点)-->,但如果仍有自动缩进机制,则在插入模式下按和以更正缩进,操作后退出到正常模式。现在可用于注释行。。。

长:我现在(几年后)意识到,按gI(大写I)会将光标置于插入模式下的第1列(意思是:无论是单词还是非单词字符,都在行的开头)。

插入注释符号(如#)并按escape-现在可以在只按的同时注释单个非连续行(注释符号作为第一个字符,没有缩进)。(点)。

与按0i或仅按I相反,它将注释符号放在第一个单词字符处,部分还带有不需要的缩进

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

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

此插件提供:

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

用法:

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