Fermat618's Blog

Happy coding

vim打开文件时自动添加cscope连接

cscope是看源代码的得力工具。在编译进了cscope特性的vim中,可以在vim内部方便地使用cscope进行跳转. 使用cscope需要先生成一个默认文件名是cscope.out的交叉引用文件,在vim中使用cscope也需要使用:cscope add 命令指定交叉引用文件所在位置,也即所谓的建立cscope链接。

通常,cscope.out会在一个项目的根目录下面。当在这个目录下打开vim时,使用vim的cscope相关部分给出的示例设置

		if filereadable("cscope.out")
		    cs add cscope.out
		" else add database pointed to by environment
		elseif $CSCOPE_DB != ""
		    cs add $CSCOPE_DB
		endif

可以自动添加cscope.out文件。然而,当在一个项目的子目录下打开一个文件的时候,这份配置却不能正确添加cscope.out文件了。往往用cscope开始查找某个东西的时候,就提示说没有建立cscope链接,很是扫兴。

想做什么事被打断是很不爽的,所以就需要自动添加cscope.out文件了。比较直接的想法就是从当前目录一层一层地向上查找,如果找到了某个cscope.out文件,就把它添加进来。考虑到python3代码写起来比vim脚本爽多了,而我的vim又是自己编译几乎必带这个支持的,所以就在vimscript中用python3来实现了。

if has("cscope") && executable("cscope")
    if has('python3')
        py3 <<EOF
import os, os.path
from itertools import takewhile
def iterate(fun, x):
    yield x
    for element in iterate(fun, fun(x)):
        yield element
for path in takewhile(lambda x: x!='/', iterate(os.path.dirname, os.getcwd())):
    cscopefile = os.path.join(path, 'cscope.out')
    if os.access(cscopefile, os.R_OK): # file readable
        vim.command('cscope add ' + cscopefile +' '+ path)
        break
EOF
    endif
    if $CSCOPE_DB != ""
	cs add $CSCOPE_DB
    endif
endif

用python的好处是容易让代码成为自己想法的自然表达。程序的目的是在当前目录及其父目录中检查cscope.out文件的存在,再添加这个文件,那么这个程序自然的结构就是首先得到当前目录和它的父目录,然后再对这些目录进行一个一个地检查。生成父目录的方式就是对一个目录不停地用basename函数,想到一个生成某个函数对一个值不断应用而产生的序列的函数 iterate(), python 的itertools中竟然没有,那就自己定义一个吧。python的生成器使得程序既不会在当前目录下已经找到cscope.out的时候还去傻傻地生成当前目录的所有父目录的列表,还能让程序看起来很漂亮。用for in结构可比while漂亮。

最后再说下vim中的:cscope add命令。cscope.out文件中需要保存文件所在的位置,而这个位置通常是相对位置。如果vim的当前目录与生成cscope.out时的当前目录不一样,vim就会找不到cscope给出的文件位置。所以,就需要显示式指定cscope.out里面的路径是相对于哪个目录的,这就是cscope add命令的第二个参数。第一个参数自然就是cscope.out文件的路径了。