blob: 5ce3f82e0e1139cef2fc40282483db7eca086f13 [file] [log] [blame]
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00001" Vim indent file
2" Language: Erlang
3" Maintainer: Csaba Hoch <csaba.hoch@gmail.com>
4" Contributor: Edwin Fine <efine145_nospam01 at usa dot net>
5" Last Change: 2008 Mar 12
6
7" Only load this indent file when no other was loaded.
8if exists("b:did_indent")
9 finish
10endif
11let b:did_indent = 1
12
13setlocal indentexpr=ErlangIndent()
14setlocal indentkeys+==after,=end,=catch,=),=],=}
15
16" Only define the functions once.
17if exists("*ErlangIndent")
18 finish
19endif
20
21" The function go through the whole line, analyses it and sets the indentation
22" (ind variable).
23" l: the number of the line to be examined.
24function s:ErlangIndentAtferLine(l)
25 let i = 0 " the index of the current character in the line
26 let length = strlen(a:l) " the length of the line
27 let ind = 0 " how much should be the difference between the indentation of
28 " the current line and the indentation of the next line?
29 " e.g. +1: the indentation of the next line should be equal to
30 " the indentation of the current line plus one shiftwidth
31 let lastFun = 0 " the last token was a 'fun'
32 let lastReceive = 0 " the last token was a 'receive'; needed for 'after'
33 let lastHashMark = 0 " the last token was a 'hashmark'
34
35 while 0<= i && i < length
36
37 " m: the next value of the i
38 if a:l[i] == '%'
39 break
40 elseif a:l[i] == '"'
41 let m = matchend(a:l,'"\%([^"\\]\|\\.\)*"',i)
42 let lastReceive = 0
43 elseif a:l[i] == "'"
44 let m = matchend(a:l,"'[^']*'",i)
45 let lastReceive = 0
46 elseif a:l[i] =~# "[a-z]"
47 let m = matchend(a:l,".[[:alnum:]_]*",i)
48 if lastFun
49 let ind = ind - 1
50 let lastFun = 0
51 let lastReceive = 0
52 elseif a:l[(i):(m-1)] =~# '^\%(case\|if\|try\)$'
53 let ind = ind + 1
54 elseif a:l[(i):(m-1)] =~# '^receive$'
55 let ind = ind + 1
56 let lastReceive = 1
57 elseif a:l[(i):(m-1)] =~# '^begin$'
58 let ind = ind + 2
59 let lastReceive = 0
60 elseif a:l[(i):(m-1)] =~# '^end$'
61 let ind = ind - 2
62 let lastReceive = 0
63 elseif a:l[(i):(m-1)] =~# '^after$'
64 if lastReceive == 0
65 let ind = ind - 1
66 else
67 let ind = ind + 0
68 end
69 let lastReceive = 0
70 elseif a:l[(i):(m-1)] =~# '^fun$'
71 let ind = ind + 1
72 let lastFun = 1
73 let lastReceive = 0
74 endif
75 elseif a:l[i] =~# "[A-Z_]"
76 let m = matchend(a:l,".[[:alnum:]_]*",i)
77 let lastReceive = 0
78 elseif a:l[i] == '$'
79 let m = i+2
80 let lastReceive = 0
81 elseif a:l[i] == "." && (i+1>=length || a:l[i+1]!~ "[0-9]")
82 let m = i+1
83 if lastHashMark
84 let lastHashMark = 0
85 else
86 let ind = ind - 1
87 end
88 let lastReceive = 0
89 elseif a:l[i] == '-' && (i+1<length && a:l[i+1]=='>')
90 let m = i+2
91 let ind = ind + 1
92 let lastReceive = 0
93 elseif a:l[i] == ';'
94 let m = i+1
95 let ind = ind - 1
96 let lastReceive = 0
97 elseif a:l[i] == '#'
98 let m = i+1
99 let lastHashMark = 1
100 elseif a:l[i] =~# '[({[]'
101 let m = i+1
102 let ind = ind + 1
103 let lastFun = 0
104 let lastReceive = 0
105 let lastHashMark = 0
106 elseif a:l[i] =~# '[)}\]]'
107 let m = i+1
108 let ind = ind - 1
109 let lastReceive = 0
110 else
111 let m = i+1
112 endif
113
114 let i = m
115
116 endwhile
117
118 return ind
119
120endfunction
121
122function s:FindPrevNonBlankNonComment(lnum)
123 let lnum = prevnonblank(a:lnum)
124 let line = getline(lnum)
125 " continue to search above if the current line begins with a '%'
126 while line =~# '^\s*%.*$'
127 let lnum = prevnonblank(lnum - 1)
128 if 0 == lnum
129 return 0
130 endif
131 let line = getline(lnum)
132 endwhile
133 return lnum
134endfunction
135
136function ErlangIndent()
137
138 " Find a non-blank line above the current line.
139 let lnum = prevnonblank(v:lnum - 1)
140
141 " Hit the start of the file, use zero indent.
142 if lnum == 0
143 return 0
144 endif
145
146 let prevline = getline(lnum)
147 let currline = getline(v:lnum)
148
149 let ind = indent(lnum) + &sw * s:ErlangIndentAtferLine(prevline)
150
151 " special cases:
152 if prevline =~# '^\s*\%(after\|end\)\>'
153 let ind = ind + 2*&sw
154 endif
155 if currline =~# '^\s*end\>'
156 let ind = ind - 2*&sw
157 endif
158 if currline =~# '^\s*after\>'
159 let plnum = s:FindPrevNonBlankNonComment(v:lnum-1)
160 if getline(plnum) =~# '^[^%]*\<receive\>\s*\%(%.*\)\=$'
161 let ind = ind - 1*&sw
162 " If the 'receive' is not in the same line as the 'after'
163 else
164 let ind = ind - 2*&sw
165 endif
166 endif
167 if prevline =~# '^\s*[)}\]]'
168 let ind = ind + 1*&sw
169 endif
170 if currline =~# '^\s*[)}\]]'
171 let ind = ind - 1*&sw
172 endif
173 if prevline =~# '^\s*\%(catch\)\s*\%(%\|$\)'
174 let ind = ind + 1*&sw
175 endif
176 if currline =~# '^\s*\%(catch\)\s*\%(%\|$\)'
177 let ind = ind - 1*&sw
178 endif
179
180 if ind<0
181 let ind = 0
182 endif
183 return ind
184
185endfunction
186
187" TODO:
188"
189" f() ->
190" x("foo
191" bar")
192" ,
193" bad_indent.
194"
195" fun
196" init/0,
197" bad_indent
198"
199" #rec
200" .field,
201" bad_indent
202"
203" case X of
204" 1 when A; B ->
205" bad_indent
206