开发者

Can you tell Vim to open a different file than the one passed on the commandline or to :e?

开发者 https://www.devze.com 2023-03-14 23:29 出处:网络
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

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:

  1. the file it writes is the original name, not the munged name
  2. it looks like the autocommands that set the filetype are running too soon, not at all, or are confused.
  3. it is using an external command to do the work
  4. 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).

0

精彩评论

暂无评论...
验证码 换一张
取 消