Stories
Slash Boxes
Comments
NOTE: use Perl; is on undef hiatus. You can read content, but you can't post it. More info will be forthcoming forthcomingly.

All the Perl that's Practical to Extract and Report

use Perl Log In

Log In

[ Create a new account ]

Ovid (2709)

Ovid
  (email not shown publicly)
http://publius-ovidius.livejournal.com/
AOL IM: ovidperl (Add Buddy, Send Message)

Stuff with the Perl Foundation. A couple of patches in the Perl core. A few CPAN modules. That about sums it up.

Journal of Ovid (2709)

Friday June 06, 2008
03:11 AM

My Favorite Vim Function, ever!

[ #36602 ]

This could use some work, but it's quickly become an indispensable navigation tool for me. Place your cursor on any package name and type ',gm' (GotoModule -- assumes your leader is a comma) and you will automatically jump to that module.

Features:

  • Uses @INC to find the same modules Perl would find.
  • If only one version is found, automatically jumps to it.
  • If more than one version is found, you will be presented with a list to pick from.
  • Cached searches for better performance.
  • Highlighted "Module '$module' not found" if the module is not found.

let g:perl_path_to = {}
function! GotoModule(module)
    let files  = []

    if !has_key(g:perl_path_to, a:module)
        let g:perl_path_to[a:module] = []
        let lib    = split(system("perl -le 'print join $/ => @INC'"), "\n")
        let module = substitute(a:module, '::', '/', 'g') . '.pm'

        for path in lib
            let path = path . '/' . module
            if filereadable(path)
                let g:perl_path_to[a:module] = g:perl_path_to[a:module] + [ path ]
            endif
        endfor
    endif

    let paths = g:perl_path_to[a:module]
    if empty(paths)
        echomsg("Module '".a:module."' not found")
    else
        let file = PickFromList('file', paths)
    endif
    execute "edit " . file
endfunction

function! PickFromList( name, list, ... )
    let forcelist = a:0 && a:1 ? 1 : 0

    if 1 == len(a:list) && !forcelist
        let choice = 0
    else
        let lines = [ 'Choose a '. a:name . ':' ]
            \ + map(range(1, len(a:list)), 'v:val .": ". a:list[v:val - 1]')
        let choice  = inputlist(lines)
        if choice > 0 && choice <= len(a:list)
            let choice = choice - 1
        else
            let choice = choice - 1
        endif
    end

    return a:list[choice]
endfunction

There are a couple of bugs (such as still trying to edit a file if you cancel), but I'll work 'em out later. For now, you probably want the following added to your .vimrc to make those work:

" only works for Perl
au! FileType perl :noremap <buffer> <leader>gm  :call GotoModule(expand('<cword>'))<cr>

" make sure we pick up the colon as part of our keyword
autocmd FileType perl setlocal iskeyword+=:

" don't kill 'undo' in other buffers
set hidden

I now use this thing constantly to quickly and easily navigate to any module listed in my code, even core modules. It's really sped things up for me.

The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
 Full
 Abbreviated
 Hidden
More | Login | Reply
Loading... please wait.
  • Sounds good, but could you clarify what this does over Vim's supplied gf command? That's normally "goto file", but for Perl files it munges colons and @INC to DTRT. (Also for Ctrl+W f, which opens a new window with the file.