diff options
Diffstat (limited to 'vim/indent/perl.vim')
-rw-r--r-- | vim/indent/perl.vim | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/vim/indent/perl.vim b/vim/indent/perl.vim new file mode 100644 index 00000000..cd01f30b --- /dev/null +++ b/vim/indent/perl.vim @@ -0,0 +1,131 @@ +" Custom Vim indent file for Perl5; the stock one didn't suit me. + +" Only load this indent file when no other was loaded. +if exists('b:did_indent') || &compatible + finish +endif +let b:did_indent = 1 + +" Indent settings +setlocal indentexpr=GetPerlIndent(v:lnum) +setlocal indentkeys=o,O,0=,0=},0=),0=],0=&&,0=\|\|,0=//,0=?,0=:,<Space> + +" Build patterns for heredoc indenting. Note that we detect indented heredocs +" with tildes like <<~EOF, but we don't treat them any differently. We don't +" strictly match the quotes either, in an effort to keep this fast. +let s:heredoc_word = '\I\i*' +let s:heredoc_open = '<<\~\?' + \ . '\(' + \ . '\\\?' . s:heredoc_word + \ . '\|' + \ . "['`\"]" . s:heredoc_word . "['`\"]" + \ . '\)' + \ . '.*;\s*$' + +" Define indent function +function! GetPerlIndent(lnum) + + " Get previous line, bail if none + let l:pn = prevnonblank(a:lnum - 1) + if !l:pn + return 0 + endif + + " Heredoc and POD flags + let l:heredoc = 0 + let l:pod = 0 + + " Start loop back through up to 512 lines of context + let l:lim = 512 + let l:hpn = a:lnum > l:lim ? a:lnum - l:lim : 0 + while l:hpn < a:lnum + let l:hpl = getline(l:hpn) + + " If we're not in a heredoc and not in a comment ... + if !l:heredoc && l:hpl !~# '^\s*#' + + " POD switching; match any section so that we can handle long PODs + if stridx(l:hpl, '=') == 0 + let l:pod = stridx(l:hpl, '=cut') != 0 + + " Heredoc switch on + else + let l:hpm = matchstr(l:hpl, s:heredoc_open) + if strlen(l:hpm) + let l:heredoc = 1 + let l:hpw = matchstr(l:hpm, s:heredoc_word) + let l:pn = l:hpn + endif + endif + + " If we are in a heredoc and we found the token word, finish it + elseif l:heredoc && l:hpl =~# '^'.l:hpw.'\>' + let l:heredoc = 0 + unlet l:hpw + endif + + " Bump the loop index + let l:hpn = l:hpn + 1 + + endwhile + + " If we ended up in a heredoc, never indent. + if l:heredoc + return 0 + endif + + " If we're in POD, just autoindent; simple and good enough. + if l:pod + return indent(a:lnum - 1) + endif + + " Get data of previous non-blank and non-heredoc line + let l:pl = getline(l:pn) + let l:pi = indent(l:pn) + + " Get value of 'shiftwidth' + let l:sw = &shiftwidth ? &shiftwidth : &tabstop + + " Get current line properties + let l:cl = getline(a:lnum) + + " Base indent with any fractional indent removed + let l:pb = l:pi - l:pi % l:sw + + " Just follow comment indent + if l:pl =~# '^\s*#' + return l:pi + + " Move out with closing brace + elseif l:cl =~# '^\s*[])}]' + return l:pb >= l:sw ? l:pb - l:sw : 0 + + " Move in after opening brace + elseif l:pl =~# '[{([]\s*$' + return l:pb + l:sw + + " Never continue after a semicolon or a double-underscore + elseif l:pl =~# '\;\s*$' + \ || l:pl =~# '__DATA__' + \ || l:pl =~# '__END__' + return l:pb + + " Line continuation hints + elseif l:pl =~# '[^])},]\s*$' + \ || l:cl =~# '^\s*\(and\|or\|xor\)' + \ || l:cl =~# '^\s*\(&&\|||\|//\)' + \ || l:cl =~# '^\s*[?:=]' + return l:pb + l:sw / 2 + + " Default to indent of previous line + else + return l:pb + + endif + +endfunction + +" How to undo all of that +let b:undo_indent = 'setlocal indentexpr<' + \ . '|setlocal indentkeys<' + \ . '|delfunction GetPerlIndent' |