vim: add a 'use' statement without moving the cursor
You're writing Perl code in vim and have just typed a package name - maybe you want to create an object of this class:
some_statement;
my $o = Some::Class->new;
do_something_with($o);
You obviously need to write use Some::Class
at the top. So you either move
the cursor near the top and add the line, then jump to the previous line
number, or maybe you split the window, move to the new viewport, make the
change, then close that viewport.
There is a better way. Here is a vim function for adding a use
statement to
the top of your file. I prefer it to go below my last existing use
statement,
except for special cases like use strict
, use constant
etc. If there isn't
any such regular use
statement, I want the new use
statement to appear
below the ABSTRACT
(a Dist::Zilla-related comment) or below the package
statement. Failing that, I want the use
statement to appear below any
existing use
statement. If there isn't one of those either, below the shebang
line. If we don't even have that, just put it at the top of the file.
Your aesthetic requirements may vary, so change the function accordingly.
This is my first real Vim script function that I've written, so excuse the 'baby Vim'.
" perl: add 'use' statement
"
" make sure you have
" setlocal iskeyword=48-57,_,A-Z,a-z,:
" so colons are recognized as part of a keyword
function! PerlAddUseStatement()
let s:package = input('Package? ', expand('<cword>'))
" skip if that use statement already exists
if (search('^use\s\+'.s:package, 'bnw') == 0)
" below the last use statement, except for some special cases
let s:line = search('^use\s\+\(constant\|strict\|warnings\|parent\|base\|5\)\@!','bnw')
" otherwise, below the ABSTRACT (see Dist::Zilla)
if (s:line == 0)
let s:line = search('^# ABSTRACT','bnw')
endif
" otherwise, below the package statement
if (s:line == 0)
let s:line = search('^package\s\+','bnw')
endif
" if there isn't a package statement either, put it below
" the last use statement, no matter what it is
if (s:line == 0)
let s:line = search('^use\s\+','bnw')
endif
" if there are no package or use statements, it might be a
" script; put it below the shebang line
if (s:line == 0)
let s:line = search('^#!','bnw')
endif
" if s:line still is 0, it just goes at the top
call append(s:line, 'use ' . s:package . ';')
endif
endfunction
map ,us :<C-u>call PerlAddUseStatement()<CR>
How about us Emacs users?
Something like this seems to work (pardon the lame formatting):
(defun my-perl-insert-use (name)
(interactive
(let ((x (thing-at-point 'symbol)))
(list (read-string (format "Module [%s]: " x) nil nil x))))
(save-excursion
(goto-char (point-min))
(while (re-search-forward "^\\s *\\(use\\|package\\)" nil t))
(unless (= (point) (point-min))
(forward-line 1))
(insert (format "use %s;\n" name))))
Jonathan Rockway wrote about this for Emacs, which is where I got the idea from in the first place:
http://blog.jrock.us/posts/Learning%20Emacs%20Lisp%20has%20paid%20off.pod
This is awesome. It's going into my vim configuration right now. Thanks for sharing! :-)
The function itself can ensure we get a correct and otherwise uninterfering 'iskeyword':
(You might also want to change the 's:' variables to 'l:' variables, scoping them a bit tighter.)
Thanks for the script!