如何让 vim 假装拥有来自复杂树的平面源目录?

How to make vim pretend to have a flat source directory from a complex tree?

我经常发现自己在目录结构类似于这样的项目中工作:

a/
  x/
    file1.h
  y/
    file2.h
  z/
    file3.h
b/
  u/
    file4.cpp
    file5.h
  v/
    file6.cpp
    file7.cpp
  w/

源文件分布在所有目录中。

我有一个快捷方式,这样说 Ctrl+n 会打开一个 :tabnew 提示符,但我仍然觉得仅通过 typing/auto-completing 目录来找到我想要的文件很麻烦,因为我有记住我要打开的特定文件所在的位置。

我可以 vim 假装整个目录结构是扁平的,或者更确切地说是查找然后打开吗?我仍然希望自动完成。 当然,理论上可能存在名称冲突,但在大多数情况下,即使技术上可以,您也不会在不同的目录中拥有相同名称的文件。


所以我想要的是源目录看起来像这样:

    file1.h
    file2.h
    file3.h
    file4.cpp
    file5.h
    file6.cpp
    file7.cpp

允许我输入类似 :magiccommand f<TAB>2<TAB> 的内容来打开 a/y/file2.h

有几个 fuzzyfinders 可以帮助实现这一点——我什至很久以前就写过一个。

您也可以坚持使用原版 Vim 并使用 starstar: :sp **/f*2<tab>

如果您正确设置 'path',您还可以输入 :find +sp f<tab>(但它似乎不适用于 :tabedit)。

:help 'path'

在你的情况下,是这样的:

:set path=/path/to/a/**,/path/to/b/**

然后:tabf file4.cpp。因此,将您的快捷方式更改为 :tabfind 而不是 :tabnew

我还建议您考虑使用 ctags,因为这样您就可以使用 :tag MyExcellentFunction(或 :stag ..:tab stag ...).

如果您最终使用标签并将 tags 文件放在项目根目录中,这将帮助您:

function! SetUpPath(filepath)
    setlocal path=
    for l:tagfile in tagfiles()
        let l:tagpath = fnamemodify(l:tagfile, ":h")
        execute "setlocal path+=" . fnameescape(l:tagpath) . '/**'
    endfor
    setlocal path-=.
    setlocal path-=
    setlocal path-=
endfunction

autocmd BufEnter * call SetUpPath(fnamemodify(expand("<afile>"), ":p"))

(如果您愿意,也可以修改为查找 .git 或 .svn 目录。)

我最终使用了受 答案启发的解决方案,它基本上独立于项目及其树结构。

map <C-b> :tabfind 
imap <C-b> <C-o><C-b>
set path=.,,**,/usr/include

缺点是我不应该在我的主目录或类似的完整目录中使用 <C-b>。但为此我建议回退到:

map <C-n> :tabnew 
imap <C-n> <C-o><C-n>