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


当前回答

我在.vimrc文件中添加了一个简单的插件,它工作得很好,可以很容易地扩展。您只需向comment_map及其注释引线添加一个新的文件类型。

我添加了一个普通模式和视觉模式的映射,但您可以重新映射到任何您喜欢的模式。我只希望有一个“切换”样式的函数。一个熊具有多个映射等。

let s:comment_map = { 
    \   "c": '\/\/',
    \   "cpp": '\/\/',
    \   "go": '\/\/',
    \   "java": '\/\/',
    \   "javascript": '\/\/',
    \   "lua": '--',
    \   "scala": '\/\/',
    \   "php": '\/\/',
    \   "python": '#',
    \   "ruby": '#',
    \   "rust": '\/\/',
    \   "sh": '#',
    \   "desktop": '#',
    \   "fstab": '#',
    \   "conf": '#',
    \   "profile": '#',
    \   "bashrc": '#',
    \   "bash_profile": '#',
    \   "mail": '>',
    \   "eml": '>',
    \   "bat": 'REM',
    \   "ahk": ';',
    \   "vim": '"',
    \   "tex": '%',
    \ }

function! ToggleComment()
    if has_key(s:comment_map, &filetype)
        let comment_leader = s:comment_map[&filetype]
        if getline('.') =~ "^\\s*" . comment_leader . " " 
            " Uncomment the line
            execute "silent s/^\\(\\s*\\)" . comment_leader . " /\\1/"
        else 
            if getline('.') =~ "^\\s*" . comment_leader
                " Uncomment the line
                execute "silent s/^\\(\\s*\\)" . comment_leader . "/\\1/"
            else
                " Comment the line
                execute "silent s/^\\(\\s*\\)/\\1" . comment_leader . " /"
            end
        end
    else
        echo "No comment leader found for filetype"
    end
endfunction


nnoremap <leader><Space> :call ToggleComment()<cr>
vnoremap <leader><Space> :call ToggleComment()<cr>

注:

我没有对文件类型/加载使用任何回调或挂钩,因为我发现它们比.vimrc静态函数/map更慢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>

我标记第一行和最后一行(ma和mb),然后做:‘a,‘bs/^#//

我使用vim多个光标。

要选择区域,请按0(它是零,而不是字母“o”)转到要注释掉的区域的第一行或最后一行的第一个字符。然后按V键并使用J、K或上下箭头键选择区域。然后按CtrlN将虚拟光标放在选择的每一行上。然后按I键同时编辑选择的每一行。

此解决方案映射到注释和?取消注释(使用单个映射切换注释太复杂,无法正确实现)。它从VIM的内置注释字符串选项中获取注释字符串,如果声明了filetype plugin on,则从/usr/share/VIM/VIM*/ftplugin/*.VIM等文件填充注释字符串。

filetype plugin on
autocmd FileType * let b:comment = split(&commentstring, '%s', 1)
autocmd FileType * execute "map <silent> <Leader>/ :normal 0i" . b:comment[0] . "<C-O>$" . b:comment[1] . "<C-O>0<CR>"
autocmd FileType * execute "map <silent> <Leader>? :normal $" . repeat('x', strlen(b:comment[1])) . "0" . strlen(b:comment[0]) . "x<CR>"

对于这些任务,我使用了大部分时间块选择。

将光标放在第一个#字符上,按CtrlV(或按CtrlQ表示gVim),然后向下移动到最后一个注释行,然后按x,这将垂直删除所有#字符。

对于注释文本块几乎是相同的:

首先,转到要评论的第一行,按CtrlV。这将使编辑器处于VISUAL BLOCK模式。然后使用箭头键并选择直到最后一行现在按ShiftI,这将使编辑器处于INSERT模式,然后按#。这将在第一行添加一个哈希。然后按Esc键(给它一秒钟),它将在所有其他选定行上插入#字符。

默认情况下,对于debian/ubuntu附带的精简版vim,请在第三步中键入:s/^/#(可以使用:nohl删除每行第一个字符的任何剩余突出显示)。

这里有两个小屏幕录音,供视觉参考。

注释:

取消注释: