我从事一个相当大的C ++项目。它组织中最令人沮丧的方面之一是将非常大的函数放置在可笑的大文件中。

我经常想搜索特定全局变量或函数调用的任何实例,但仅限于当前函数。

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

#1 楼

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

vnoremap if [[O][


说明:vnoremap表示在处于可视模式时将左侧if映射到右侧[[mO][if表示在功能中,尽管您可以根据需要重命名。 [[跳至功能的开头。 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
...


评论


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

–卢克·赫米特(Luc Hermitte)
16年5月24日在17:49



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

– joeytwiddle
16年5月24日在19:56



关于您的最后编辑。 CTRL-]跳转到光标下方的标签。不启动当前功能。这不会有帮助。

–卢克·赫米特(Luc Hermitte)
16年5月25日在9:16

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

–卢克·赫米特(Luc Hermitte)
16年5月26日在15:54



#2 楼

DJ McMayhem的解决方案启发了我写我自己的文章,它依靠ctags和matchit对功能边界进行适当的分析。

lh-dev和lh-tags已经完成了一些困难的工作years:


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

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

所以我现在定义了两个新的映射:可视模式映射和操作员待处理的模式映射: br />依靠的是:

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


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

感谢DJ McMayhem的映射

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


我们可以执行vif/pattern来搜索当前函数中的pattern。等。

这是应用于实际C ++函数(即不缩进0)时的外观:

#3 楼

查找函数的开头和结尾可能很困难,尤其是在没有function关键字的语言中……以及许多缩进样式冲突的语言中。

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

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


从那里,在函数中搜索foo只是一个问题:

:'<,'>g/foo/#


将它们放在一起,我们可以获得一个很好的映射:

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




也就是说,视觉模式映射很容易被whileif所欺骗,因此它可能会从抛光中受益。另外,保持视觉选择可能不是一个好主意...

评论


这只是选择它可以找到的下一个块。一旦添加if,for,while等,该功能将根本无法使用。

–詹姆斯
16年5月26日在16:17

#4 楼

不完美的解决方案是使用折叠。折叠所有内容:

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


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

set foldopen-=search


然后现在,在相关功能(zO)上打开折叠。

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

例如,在以下情况下:



折叠功能具有size的许多用法,但n不会引我围绕该功能中size的每次使用。

#5 楼

另一种方法:


使用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之类的东西或类似东西。