aboutsummaryrefslogtreecommitdiff
path: root/vim/indent/perl.vim
diff options
context:
space:
mode:
Diffstat (limited to 'vim/indent/perl.vim')
-rw-r--r--vim/indent/perl.vim131
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'