3

我将如何设置热键(例如:CTRL+ )以对当前缓冲区中的当前视觉选择g执行操作?VIMGREP我的意图是在所有匹配搜索结果的“快速修复”窗口中显示一个行号列表。

现在,如果我想获得正则表达式搜索的结果列表,我可以像这样执行命令模式查询:

:vimgrep /foo/ %

但是,这样做有两个问题:

  1. 我不想输入整个查询。我总是可以进行视觉选择,然后使用CTRL+ rCTRL+w将当前视觉选择粘贴到命令缓冲区中,但我想要比这更简单的东西。
  2. 上述方法要求当前缓冲区已经保存到文件中。我希望能够在我粘贴到 VIM 的临时缓冲区上工作,而不是每次我想这样做时都必须保存文件缓冲区。

谢谢你。

4

3 回答 3

6

低级解决方案

尝试[I:ilist命令:

[I                 " lists every occurrence of the word under the cursor
                   " in the current buffer (and includes)

:ilist /foo<CR>    " lists every occurrence of foo in the current buffer 
                   " (and includes)

:后跟一个行号并<CR>跳到该行。

您可以通过简单的映射在视觉选择上使用它们:

xnoremap <key> "vy:<C-u>ilist /<C-r>v<CR>:

不过,您可能需要在插入时对寄存器进行消毒。

:help :ilist

另一个更低级别的解决方案

既然我们在这里,让我们更深入地挖掘,发现惊人的简单和优雅:

:g/foo/#

您可以以与上述相同的方式使用:ilist

xnoremap <key> "vy:<C-u>g/<C-r>v/#<CR>:

限制

显然,上述解决方案不使用 quickfix 窗口,但它们允许您:

  • 以列表的形式查看他们的结果,
  • 使用行号实际到达您想要的位置。

但是,它们有局限性:

  • 该列表未缓存,因此如果您想获得不同的出现,则必须再次执行搜索,
  • 该列表不像快速修复列表那样是瞬态的,因此您不能使用导航命令:cnext:clast在结果中移动。

更高层次的解决方案

如果这些限制是一个阻碍,下面的函数,改编自 justinmk 在这个 /r/vim 线程中的回答,给你一个几乎完整的解决方案:

  • [I普通模式下按可在整个缓冲区中搜索光标下的单词,
  • ]I普通模式下按可在当前行之后搜索光标下的单词,
  • [I可视模式下按下以在整个缓冲区中搜索选定的文本,
  • ]I可视模式下按下可在当前行之后搜索所选文本。

下面的函数在缓冲区与文件关联时使用快速修复列表/窗口并回退到常规行为[I]I其他情况。它可能会被修改为用作:Ilist命令的一部分。

" Show ]I and [I results in the quickfix window.
" See :help include-search.
function! Ilist_qf(selection, start_at_cursor)

    " there's a file associated with this buffer
    if len(expand('%')) > 0

        " we are working with visually selected text
        if a:selection

            " we build a clean search pattern from the visual selection
            let old_reg = @v
            normal! gv"vy
            let search_pattern = substitute(escape(@v, '\/.*$^~[]'), '\\n', '\\n', 'g')
            let @v = old_reg

            " and we redirect the output of our command for later use
            redir => output
                silent! execute (a:start_at_cursor ? '+,$' : '') . 'ilist /' . search_pattern
            redir END

        " we are working with the word under the cursor
        else

            " we redirect the output of our command for later use
            redir => output
                silent! execute 'normal! ' . (a:start_at_cursor ? ']' : '[') . "I"
            redir END
        endif
        let lines = split(output, '\n')

        " better safe than sorry
        if lines[0] =~ '^Error detected'
            echomsg 'Could not find "' . (a:selection ? search_pattern : expand("<cword>")) . '".'
            return
        endif

        " we retrieve the filename
        let [filename, line_info] = [lines[0], lines[1:-1]]

        " we turn the :ilist output into a quickfix dictionary
        let qf_entries = map(line_info, "{
                    \ 'filename': filename,
                    \ 'lnum': split(v:val)[1],
                    \ 'text': getline(split(v:val)[1])
                    \ }")
        call setqflist(qf_entries)

        " and we finally open the quickfix window if there's something to show
        cwindow

    " there's no file associated with this buffer
    else

        " we are working with visually selected text
        if a:selection

            " we build a clean search pattern from the visual selection
            let old_reg = @v
            normal! gv"vy
            let search_pattern = substitute(escape(@v, '\/.*$^~[]'), '\\n', '\\n', 'g')
            let @v = old_reg

            " and we try to perform the search
            try
                execute (a:start_at_cursor ? '+,$' : '') . 'ilist /' .  search_pattern . '<CR>:'
            catch
                echomsg 'Could not find "' . search_pattern . '".'
                return
            endtry

        " we are working with the word under the cursor
        else

            " we try to perform the search
            try
                execute 'normal! ' . (a:start_at_cursor ? ']' : '[') . "I"
            catch
                echomsg 'Could not find "' . expand("<cword>") . '".'
                return
            endtry
        endif
    endif
endfunction

nnoremap <silent> [I :call Ilist_qf(0, 0)<CR>
nnoremap <silent> ]I :call Ilist_qf(0, 1)<CR>
xnoremap <silent> [I :<C-u>call Ilist_qf(1, 0)<CR>
xnoremap <silent> ]I :<C-u>call Ilist_qf(1, 1)<CR>

注意:<C-r><C-w>在光标下插入单词,而不是视觉选择,不幸的是没有这样的快捷方式。我们别无选择,只能猛拉。

于 2014-10-24T08:20:36.227 回答
5

抓取暂存缓冲区

您可以:global结合使用该命令:caddexpr将条目添加到当前的快速修复列表中。这是来自的示例:h :caddexpr

:g/mypattern/caddexpr expand("%") . ":" . line(".") .  ":" . getline(".")

这有几个问题:

  • 这种方法每行只匹配一个
  • 不启动新的快速修复列表
  • 打字真的好长
  • 假设默认全局'errorformat'未更改

要克服这些问题(每行除了多个匹配项之外的所有问题),请将以下命令放入您的~/.vimrc文件中:

command! -nargs=1 -bar Cgrep
      \ let s:errorformat = &errorformat |
      \ try |
      \   let &errorformat='%f:%l:%m' |
      \   cexpr [] |
      \   execute 'g'.<q-args>.'caddexpr expand("%").":".line(".").":".getline(".")' |
      \   cc |
      \ finally |
      \   let &errorformat = s:errorformat |
      \ endtry

现在您可以使用:Cgrep/foo/grep 当前缓冲区。

视觉映射

为了让你可以做一个可视化的版本,你需要拉入选定的文本并将其传递给我们的:Cgrep命令<c-r>。这是一个示例视觉映射g/来做到这一点:

xnoremap g/ y:<c-u>Cgrep/<c-r>"/<cr>

此映射也存在一些问题:

  • 这破坏了无名登记册,@"
  • 这假定视觉选择的文本将是有效的模式

以下映射通过使用表达式寄存器 via 来修复映射,<c-r>=并且非常不神奇,\V

xnoremap g/ :<c-u>let @/=@"<cr>gvy:let [@/,@"]=[@",@/]<cr>Cgrep/\V<cr>=substitute(escape(@/,'/\'),'\n','\\n','g')<cr>/<cr>

结论

就我个人而言,我会放弃映射并获得一个视觉明星插件(那里很少)。有一个很好的 Vimcast :Search for the selected text。然后我会将它与:Cgrep我们刚刚创建的命令一起使用,:Cgrep//或者更好xmap g/ *:Cgrep//<cr>

如需更多帮助,请参阅:

:h :caddexpr
:h :cexpr
:h :g
:h 'efm
:h registers
:h /\V
于 2014-10-28T19:06:40.263 回答
1

CTRL要通过热键+搜索文件 *.c 中的可视选定文本,g请执行以下操作:

:vmap <silent> <unique> <c-g> y:vimgrep "<c-r>"" *.c<CR>

仍然存在两个问题:

  1. 您想在缓冲区中搜索,而不是在文件中。
  2. 您需要快速修复中的行号。

To 1:据我所知 vimgrep 只能在文件中搜索。解决方案是将缓冲区写入临时文件并在此文件中搜索并在不再需要时删除临时文件。此解决方案需要一个通过热键调用的脚本。只是一个提示:要获得合适的文件名,可以使用 VIM 函数 tempname()。例子:

let s:tmpfile = tempname()

(抱歉,暂时没时间在这里展示脚本解决方案,也许我稍后再添加。也许其他人有更好的解决方案或者可以提供脚本?)

To 2:此命令将启用当前缓冲区中的行号:

:set number
于 2014-10-24T06:27:52.310 回答