Can you tell Vim to open a different file than the one passed on the commandline or to :e?
I want to teach Vim how to open Perl 5 modules from names like File::Find
. I already have a wrapper script written in Perl 5 that handles the commandline (see below), but I would like to be able to say things like :tabe File::Find
and have it really execute :tabe /home/cowens/apps/perlbrew/perls/perl-5.14.0/lib/5.14.0/File/Find.pm
.
My current plan is to somehow use autocmd BufNewFile
and/or autocmd BufPreRead
, but I can't figure out how to switch the file name.
#!/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;
Doing
:verbose au BufReadCmd
Will tell you how other types of plugins do this (e.g. zip, netrw, fugitive). Sample output that should give you plenty of ideas:
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
Consider using ctags
. If you're able to run the ctags process over your source code, you should be able to get to a point where you simply do:
vim -t File::Find
Vim has information about this (:help vim
) I think ctags probably goes well beyond what you're trying to do, allowing you to jump from the middle of one source file to the original function definition in another.
For opening those files manually I would recommend to use :find
and
:tabfind
commands instead of :edit
and :tabedit
respectively. The
difference between these two pairs of commands is that the former ones look
for a file not only in the current path, but also in directories listed in
path
option (see :help 'path'
). If you add your Perl @INC
directories
to Vim path
option, you can quickly locate a module file by using :find
or
:tabfind
commands. For example, to open a new tab page and edit
File::Find
module file in you can type
:tabfind File/Find.pm
(You don't have to type the whole sub-path manually since :find
and
:tabfind
completion takes the current path
value into account.)
To locating those files automatically by module name using gf
, ^Wf
,
^Wgf
, you need to additionally change (either with filetype plugin or
autocommand) the following options for Perl files.
:set isfname+=:
:set suffixesadd+=.pm
:set includeexpr=substitute(v:fname,'::','/','g')
After these options (as well as path
option containing Perl @INC
directories) are set, you can easily open module files using gf
-like
commands on corresponding module names.
Lazy solution based on sehe's answer below. Current problems:
- the file it writes is the original name, not the munged name
- it looks like the autocommands that set the filetype are running too soon, not at all, or are confused.
- it is using an external command to do the work
- it is specific to the munging I want (i.e. it is not general)
When I have more downtime, I hope to fix all of the above and turn it into a plugin.
in .vimrc
autocmd BufReadCmd * r!cat_perl %
in 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 "";
This may actually be possible with vim's gf
command (go to file).
In your code, if you see a string like File::Find, place your cursor over it and in normal mode type gf
. For me, that immediately takes me to the File::Find package.
I think this is native as part of the perl filetype libraries because it works for me when executing vim with --noplugin
.
Here's a working example showing how to use the BufReadCmd autocmd to edit a file other than the one specified (in this case editing a corresponding .scss file when you open a .css file).
精彩评论