summaryrefslogtreecommitdiff
path: root/runtime/indent/perl.vim
blob: b3a9fc0214b4925630cae902ee1cd9c0e27a8b00 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
" Vim indent file
" Language:	Perl
" Author:	Rafael Garcia-Suarez <rgarciasuarez@free.fr>
" URL:		http://rgarciasuarez.free.fr/vim/indent/perl.vim
" Last Change:	2005 Sep 07

" Suggestions and improvements by :
"   Aaron J. Sherman (use syntax for hints)
"   Artem Chuprina (play nice with folding)

" TODO things that are not or not properly indented (yet) :
" - Continued statements
"     print "foo",
"	"bar";
"     print "foo"
"	if bar();
" - Multiline regular expressions (m//x)
" (The following probably needs modifying the perl syntax file)
" - qw() lists
" - Heredocs with terminators that don't match \I\i*

" Only load this indent file when no other was loaded.
if exists("b:did_indent")
  finish
endif
let b:did_indent = 1

" Is syntax highlighting active ?
let b:indent_use_syntax = has("syntax")

setlocal indentexpr=GetPerlIndent()
setlocal indentkeys+=0=,0),0=or,0=and
if !b:indent_use_syntax
  setlocal indentkeys+=0=EO
endif

" Only define the function once.
if exists("*GetPerlIndent")
  finish
endif

let s:cpo_save = &cpo
set cpo-=C

function GetPerlIndent()

  " Get the line to be indented
  let cline = getline(v:lnum)

  " Indent POD markers to column 0
  if cline =~ '^\s*=\L\@!'
    return 0
  endif

  " Don't reindent coments on first column
  if cline =~ '^#.'
    return 0
  endif

  " Get current syntax item at the line's first char
  let csynid = ''
  if b:indent_use_syntax
    let csynid = synIDattr(synID(v:lnum,1,0),"name")
  endif

  " Don't reindent POD and heredocs
  if csynid == "perlPOD" || csynid == "perlHereDoc" || csynid =~ "^pod"
    return indent(v:lnum)
  endif

  " Indent end-of-heredocs markers to column 0
  if b:indent_use_syntax
    " Assumes that an end-of-heredoc marker matches \I\i* to avoid
    " confusion with other types of strings
    if csynid == "perlStringStartEnd" && cline =~ '^\I\i*$'
      return 0
    endif
  else
    " Without syntax hints, assume that end-of-heredocs markers begin with EO
    if cline =~ '^\s*EO'
      return 0
    endif
  endif

  " Now get the indent of the previous perl line.

  " Find a non-blank line above the current line.
  let lnum = prevnonblank(v:lnum - 1)
  " Hit the start of the file, use zero indent.
  if lnum == 0
    return 0
  endif
  let line = getline(lnum)
  let ind = indent(lnum)
  " Skip heredocs, POD, and comments on 1st column
  if b:indent_use_syntax
    let skippin = 2
    while skippin
      let synid = synIDattr(synID(lnum,1,0),"name")
      if (synid == "perlStringStartEnd" && line =~ '^\I\i*$')
	    \ || (skippin != 2 && synid == "perlPOD")
	    \ || (skippin != 2 && synid == "perlHereDoc")
	    \ || synid == "perlComment"
	    \ || synid =~ "^pod"
	let lnum = prevnonblank(lnum - 1)
	if lnum == 0
	  return 0
	endif
	let line = getline(lnum)
	let ind = indent(lnum)
	let skippin = 1
      else
	let skippin = 0
      endif
    endwhile
  else
    if line =~ "^EO"
      let lnum = search("<<[\"']\\=EO", "bW")
      let line = getline(lnum)
      let ind = indent(lnum)
    endif
  endif

  " Indent blocks enclosed by {} or ()
  if b:indent_use_syntax
    " Find a real opening brace
    let bracepos = match(line, '[(){}]', matchend(line, '^\s*[)}]'))
    while bracepos != -1
      let synid = synIDattr(synID(lnum, bracepos + 1, 0), "name")
      " If the brace is highlighted in one of those groups, indent it.
      " 'perlHereDoc' is here only to handle the case '&foo(<<EOF)'.
      if synid == ""
	    \ || synid == "perlMatchStartEnd"
	    \ || synid == "perlHereDoc"
	    \ || synid =~ "^perlFiledescStatement"
	    \ || synid =~ '^perl\(Sub\|BEGINEND\|If\)Fold'
	let brace = strpart(line, bracepos, 1)
	if brace == '(' || brace == '{'
	  let ind = ind + &sw
	else
	  let ind = ind - &sw
	endif
      endif
      let bracepos = match(line, '[(){}]', bracepos + 1)
    endwhile
    let bracepos = matchend(cline, '^\s*[)}]')
    if bracepos != -1
      let synid = synIDattr(synID(v:lnum, bracepos, 0), "name")
      if synid == ""
	    \ || synid == "perlMatchStartEnd"
	    \ || synid =~ '^perl\(Sub\|BEGINEND\|If\)Fold'
	let ind = ind - &sw
      endif
    endif
  else
    if line =~ '[{(]\s*\(#[^)}]*\)\=$'
      let ind = ind + &sw
    endif
    if cline =~ '^\s*[)}]'
      let ind = ind - &sw
    endif
  endif

  " Indent lines that begin with 'or' or 'and'
  if cline =~ '^\s*\(or\|and\)\>'
    if line !~ '^\s*\(or\|and\)\>'
      let ind = ind + &sw
    endif
  elseif line =~ '^\s*\(or\|and\)\>'
    let ind = ind - &sw
  endif

  return ind

endfunction

let &cpo = s:cpo_save
unlet s:cpo_save

" vim:ts=8:sts=2:sw=2