你可以告诉Vim打开一个不同于通过命令行或者:e传递的文件吗?

4
我想教Vim如何打开类似于File::Find的Perl 5模块。我已经编写了一个用Perl 5处理命令行的包装脚本(见下文),但我希望能够像这样说:tabe File::Find,并真正执行:tabe /home/cowens/apps/perlbrew/perls/perl-5.14.0/lib/5.14.0/File/Find.pm
我的当前计划是以某种方式使用autocmd BufNewFile和/或autocmd BufPreRead,但我无法弄清如何切换文件名。
#!/usr/bin/perl

use strict;
use warnings;

my @files = @ARGV;
for my $file (@files) {
    next if -f $file; #skip files that really exist

    #convert from module name to module file
    (my $module = $file) =~ s{::}{/}g;
    $module .= ".pm";

    #look for module in the include paths
    for my $dir (@INC) {
        my $candidate = "$dir/$module";
        if (-f $candidate) {
            $file = $candidate;
            last;
        }
    }
}

#replace this script with vim
exec "vim", "-p", @files;

2
你有看过并且排除了 ctags 吗? - searlea
@searlea 不,我从未使用过 ctags,我可以在 Vim 中输入 :help ctags 以了解更多信息吗? - Chas. Owens
是的...vim有相关帮助。它可以帮助直接从函数引用跳转到源定义等,远不止于根据模块名称启动或打开文件。 - searlea
@searlea 看起来 ctags 是一种根据当前缓冲区中的文本执行命令的方法。它似乎需要一个索引,每次添加文件时都必须进行修改(将字符串映射到命令)。这不是我想要的。我希望能够编辑任何文件,而不仅仅是当前文件中包含的文件。ctags 的一个问题是,当我输入 :tabe Foo 时得到的文件可能会因我的环境而改变。这可能可以通过足够复杂的命令来解决,但是为什么我不直接使用那个命令呢? - Chas. Owens
6个回答

5

进行中

:verbose au BufReadCmd

我将告诉你其他类型的插件如何实现这一点(例如zip,netrw,fugitive)。以下是样本输出,应该可以给您提供足够的想法:

zip  BufReadCmd
    zipfile:* call zip#Read(expand("<amatch>"), 1)
    Last set from C:\Program Files\Vim\vim73\plugin\zipPlugin.vim
    *.zip     call zip#Browse(expand("<amatch>"))
    Last set from C:\Program Files\Vim\vim73\plugin\zipPlugin.vim

Network  BufReadCmd
    ftp://*   exe "silent doau BufReadPre ".fnameescape(expand("<amatch>"))|call netrw#Nread(2,expand("<amatch>"))|exe "silent doau BufReadPost ".fnameescape(expand("<amatch>"))
    Last set from C:\Program Files\Vim\vim73\plugin\netrwPlugin.vim
    http://*  exe "silent doau BufReadPre ".fnameescape(expand("<amatch>"))|call netrw#Nread(2,expand("<amatch>"))|exe "silent doau BufReadPost ".fnameescape(expand("<amatch>"))
    Last set from C:\Program Files\Vim\vim73\plugin\netrwPlugin.vim

fugitive_files  BufReadCmd
    *.git/index
              exe s:BufReadIndex()
    Last set from C:\Program Files\Vim\vimfiles\plugin\fugitive.vim
    *.git/*index*.lock
              exe s:BufReadIndex()
    Last set from C:\Program Files\Vim\vimfiles\plugin\fugitive.vim
    fugitive://**//[0-3]/**
              exe s:BufReadIndexFile()
    Last set from C:\Program Files\Vim\vimfiles\plugin\fugitive.vim
    fugitive://**//[0-9a-f][0-9a-f]*
              exe s:BufReadObject()
    Last set from C:\Program Files\Vim\vimfiles\plugin\fugitive.vim

4

考虑使用ctags。如果您能够运行ctags进程来处理源代码,则可以轻松地执行以下操作:

vim -t File::Find

Vim有关于此的信息(:help vim)。我认为ctags可能远远超出了您尝试做的事情,它可以让您从一个源文件的中间跳转到另一个函数定义的原始位置。


Vim已经知道如何为Perl 5完成大部分操作。当我在模块名称上按下gF时,它会打开该模块。问题出现在当我在文件A中想要打开文件B时,但是文件A中没有对文件B的引用。 - Chas. Owens
我认为你不需要重新索引,我相信你可以使用多个标签文件... 参考 :help 'tags':help file-searching 来设置自动选择不同的标签文件,根据你所在的沙盒(例如,通过从当前源文件向上遍历目录树)。 - searlea
嗯,看起来没有类似于 :tabtag 的命令可以在新标签页中打开标签。我讨厌缓冲区,是我漏掉了什么吗?我想我可以创建自己的命令,打开一个新的标签页,然后运行 :tag 命令。 - Chas. Owens
另一个缺点是当添加新文件时,我将不得不重新索引,但我想我只需在darcs和git中放置钩子,在拉取或添加文件时触发重新索引即可。 - Chas. Owens
1
使用ctags的关键是保持索引本地化,与它们正在索引的内容相对应。您可以在vimrc中列出多个标签文件,并且如果要按不同顺序搜索,则可以在更改缓冲区时更改变量(自动)。更改环境变量需要重新启动vim才能生效,因此最好(在我看来)设置这些设置以使设置“知道”当前的沙箱。(这正是我所做的,以便我使用与我当前所在项目相关联的标签文件。) - dash-tom-bang
显示剩余3条评论

2

如果需要手动打开这些文件,建议使用:find:tabfind命令,而不是:edit:tabedit命令。两组命令的区别在于前者不仅在当前路径中查找文件,还会在path选项列出的目录中查找文件(请参见:help 'path')。如果将Perl @INC目录添加到Vim path选项中,您可以通过使用:find:tabfind命令快速定位模块文件。例如,要打开一个新的选项卡并编辑File::Find模块文件,则可以键入:

:tabfind File/Find.pm

您不必手动输入整个子路径,因为:find:tabfind命令会考虑当前的path值进行自动补全。

要使用gf^Wf^Wgf命令根据模块名自动定位这些文件,您需要针对Perl文件附加更改以下选项(可以使用文件类型插件或自动命令)。

:set isfname+=:
:set suffixesadd+=.pm
:set includeexpr=substitute(v:fname,'::','/','g')

在设置了这些选项(以及包含Perl @INC目录的path选项)之后,您可以使用与相应模块名称相似的gf命令轻松打开模块文件。

不行,那是行不通的。这里的关键不仅在于路径,还在于从 File::Find 转换到 File/Find.pm - Chas. Owens
@Chas:你可以很容易地通过使用Vim内置的机制来实现这种行为。请参考更新后的答案。 - ib.
再次强调,我希望能够像这样说:tabe File::Find。在Vim 7中,gf已经可以轻松找到Perl模块。我想在编辑文件A时意识到需要编辑文件B,并能够打开它,即使文件A中没有提到文件B。我经常从其他来源(如电子邮件、即时消息、日志等)获取模块名称,我已经厌倦了手动更改的过程。 - Chas. Owens

0

以下是基于sehe答案的懒惰解决方案。当前存在问题:

  1. 它写入的文件是原始名称,而不是修改后的名称
  2. 看起来设置文件类型的自动命令运行得太早、根本没有运行或者混淆了。
  3. 它使用外部命令来完成工作
  4. 它只适用于我想要的修改方式(即它不是通用的)

在我有更多空闲时间时,我希望解决所有上述问题并将其转化为插件。

.vimrc中。

autocmd BufReadCmd * r!cat_perl %

cat_perl

#!/usr/bin/perl

use strict;
use warnings;

sub cat {
    my $file = shift;
    open my $fh, "<", $file
        or die "could not open $file: $!";
    print while <$fh>;
    exit;
}

my $file = shift;

cat $file if -f $file;

#convert from module name to module file
(my $module = $file) =~ s{::}{/}g;
$module .= ".pm";

#look for module in the include paths
for my $dir (@INC) {
    my $candidate = "$dir/$module";
    cat $candidate if -f $candidate;
}
print "";

0

使用vim的gf命令(转到文件)可能是可行的。

在您的代码中,如果您看到像File :: Find这样的字符串,请将光标放在其上,在正常模式下键入gf。对我来说,这立即将我带到了File :: Find包。

我认为这是perl文件类型库的一部分,因为当我使用--noplugin执行vim时,它对我有效。


它存在,但它不能做我想要的事情。我想能够打开任何文件,而不仅仅是当前文件中引用的文件。 - Chas. Owens


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接