快速搜索,仅限于C ++函数


13

我从事一个相当大的C ++项目。其组织中最令人沮丧的方面之一是非常大的功能置于荒谬的大文件中。

我经常想搜索特定全局变量或函数调用的任何实例,仅限于当前函数。是否有一个合理的简单公式可以实现这一目标?

(我确实安装了ctags并使用了标签栏...这可能对此有所帮助)

Answers:


9

这就是我的做法。将此添加到您的.vimrc

vnoremap if [[O][

说明:vnoremap表示在可视模式下将左侧映射if到右侧[[mO][if表示In Function,尽管您可以根据需要重命名。[[跳转到函数的开头。O移至您视觉选择的文本的另一端,然后][移至函数的末尾。

因此,如果要搜索功能,则现在使用进入可视模式v,然后使用选择整个功能if。现在使用退出可视模式<esc>,并使用搜索/\%V\%V将您的搜索限制为先前选择的文本。如果您不想打<esc>/\%V,也可以将其添加到您的.vimrc

vnoremap / <esc>/\%V

然后,您的击键顺序将如下所示:

vif/foo<enter>

这将查找当前函数中所有出现的foo。


此方法的唯一缺点是,它期望打开和闭合大括号的缩进均为0。如果您经常使用没有此功能的代码,例如

int foo() {
    bar()
}

那么这个稍微复杂一些的版本将可以工作:

vnoremap if ][ma%O'a

这只希望右括号有0个缩进。如果开头括号有凹痕,则它仍然有效,尽管它确实有痕迹。如果您经常使用标记“ a”,则可以移动例如

vnoremap if ][mb%O'b
vnoremap if ][mc%O'c
...

this,这不适用于C ++函数。与C函数不同,它们很可能会缩进(对于在类定义中定义的内联成员函数以及名称空间中函数的默认缩进来说就是这种情况)。但是,由于可以使用ctags获得的函数定义范围,因此可以建立您的想法。我在lh#dev#find_function_boundarieslh-dev 的函数中执行此操作
Luc Hermitte,2016年

3
好的方法。如果您可以可靠地找到函数的顶行,则可以移至{,然后使用%到达底行。不确定如何找到以C ++开头的函数,但是对于Javascript来说可以正常工作:vnoremap if <Esc>?^\s*function<CR>v/{<CR>%o
joeytwiddle

1
关于您的最后编辑。CTRL-]跳转到光标下方的标签。没有到当前功能的开始。这不会有帮助。
卢克·赫米特

关于新的编辑。这不是那么简单。困难在于让vim知道当前功能。如果它具有信息,则不需要ctags帮助。从ctags获取信息的唯一方法是分析ctags产生的跳转到声明命令。如果这些命令是:linenumber,vim可以做我在插件中所做的事情。但是不能保证,这些命令可以改为搜索-Vim /pattern不能测试所有模式来知道哪个模式与当前函数匹配。IOW,我不知道有任何vim动作跳转到当前模式的开始。功能
卢克·赫米特

6

DJ McMayhem的解决方案激发了我编写依赖ctags和matchit对功能边界进行适当分析的自己的解决方案

困难的部分已经由lh-dev和lh-tags完成了几年:

  • 使用正确的选项通过ctags解析当前文件
  • 我们在标签数据库中查找所有函数定义,该函数定义仅限于为当前文件获取的标签
  • 多亏了数据库,我们有了所有功能的起始行号(以及templateinline部分可能会被ctags遗漏)
  • 通过简单的迭代搜索(可以完成二进制搜索,但是文件应该是“短”的),可以找到当前函数的开头
  • 多亏了matchit插件,它的最后一行也被找到了-我看到通用ctags提供了一个end可与C,C ++,Python和Vim一起使用的字段,该字段也可用于查找函数的结尾。

注意,该算法的任何部分都可以基于文件类型被覆盖。即python函数的边界检测可以搜索def和分析缩进,我们可以只function在javascript中搜索,依此类推-换句话说,当前版本还可以与Java,Vim和其他一些语言一起使用(我仍然有一些工作为Python做)

因此,我现在定义两个新的映射:可视模式映射和操作员待处理的模式映射:

onoremap <silent> if :<c-u>call lh#dev#_select_current_function()<cr>
xnoremap <silent> if :<c-u>call lh#dev#_select_current_function()<cr><esc>gv

依靠:

function! lh#dev#_select_current_function() abort
  let fn = lh#dev#find_function_boundaries(line('.'))
  exe fn.lines[0]
  normal! v
  exe fn.lines[1]
endfunction

我为您节省了几百行代码 lh#dev#find_function_boundaries()

多亏了DJ McMayhem的映射

" Note that my vim settings requires two backslashes here instead of one
vnoremap / <esc>/\\%V

我们可以在当前函数中vif/pattern进行搜索pattern

我们还可以使用删除函数,使用删除dif它们yif,等等。

这是应用于实际 C ++函数(即不缩进0)时的外观:截屏视频:选择C ++函数


4

很难找到函数的开头和结尾,尤其是在没有function关键字的语言中……以及许多相互矛盾的缩进样式。

如果您的函数以单独的右括号结尾(例如,在此处列出的13种样式中的10种),则可以通过以下方式直观地选择它:

xnoremap if /^\s*}<CR><Esc>V%

从那里开始,在foo函数中进行搜索仅需考虑以下事项:

:'<,'>g/foo/#

放在一起,我们可以得到一个相当不错的映射:

xnoremap if /^\s*}<CR><Esc>V%
nmap <key> vif:g//#<Left><Left>

搜索功能

也就是说,可视模式映射很可能会被a while或a愚弄,if因此它可能会受益于一些改进。另外,保持视觉选择可能不是一个好主意……


这只是选择它可以找到的下一个块。它不会在所有的工作,一旦你添加ifforwhile
詹姆斯

3

不完善的解决方案是使用折叠。折叠一切:

set foldmethod=syntax
set foldlevel=0
set foldminlines=0

告诉Vim不要打开折叠区域以显示搜索结果:

set foldopen-=search

然后打开有关函数(zO)的折叠。

现在,在折叠区域中搜索到的文本的所有匹配都将导致Vim跳到折叠行一次,然后继续进行下一个匹配。

例如,在以下情况下:

在此处输入图片说明

折叠函数具有的许多用法size,但n不会带我领略size该函数的所有用法。


3

另一种方式:

  • 使用ctags等来找到目标函数,去那里
  • 在函数体内向前移动光标
  • 使用Osyo Manga的搜索运算符(取决于vim-operator-user)仅在当前块内搜索。例如:

    " configure the plugin (once, vimrc):
     map g/ <Plug>(operator-search)
    
    " 1. use ctags etc. to jump to the beginning of the target function;
    " 2. move cursor inside the function definition, then:
    g/i{
    

...现在您可以在给定的提示下插入搜索词;点击n查看如何将搜索结果限制为当前提供的运动/文本对象。由于这是一个Vim(即可组合)运算符,因此,如果您有一个功能良好的文本对象,则在搜索之前甚至不需要在定义体内移动,而是直接使用诸如g/if或类似的东西。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.