blob: bad838a0779b21d44d3c31e15e059a158746085e [file] [log] [blame]
Bram Moolenaar280f1262006-01-30 00:14:18 +00001" VHDL indent ('93 syntax)
Bram Moolenaar51156d52006-01-26 22:17:47 +00002" Language: VHDL
3" Maintainer: Gerald Lai <laigera+vim?gmail.com>
Bram Moolenaar280f1262006-01-30 00:14:18 +00004" Version: 1.2
5" Last Change: 2006 Jan 26
6" URL: http://www.vim.org/scripts/script.php?script_id=1450
Bram Moolenaar51156d52006-01-26 22:17:47 +00007
8" only load this indent file when no other was loaded
9if exists("b:did_indent")
10 finish
11endif
12let b:did_indent = 1
13
14" setup indent options for local VHDL buffer
15setlocal indentexpr=GetVHDLindent()
16setlocal indentkeys=!^F,o,O,e,0(,0)
17setlocal indentkeys+==~if,=~then,=~elsif,=~else
18setlocal indentkeys+==~begin,=~is,=~select,=~--
19
20" move around
21" keywords: "architecture", "block", "configuration", "component", "entity", "function", "package", "procedure", "process", "record", "units"
22let b:vhdl_explore = '\%(architecture\|block\|configuration\|component\|entity\|function\|package\|procedure\|process\|record\|units\)'
23nnoremap <silent><buffer>[[ :cal search('\%(\<end\s\+\)\@<!\<'.b:vhdl_explore.'\>\c','bW')<CR>
24nnoremap <silent><buffer>]] :cal search('\%(\<end\s\+\)\@<!\<'.b:vhdl_explore.'\>\c','W')<CR>
25nnoremap <silent><buffer>[] :cal search('\<end\s\+'.b:vhdl_explore.'\>\c','bW')<CR>
26nnoremap <silent><buffer>][ :cal search('\<end\s\+'.b:vhdl_explore.'\>\c','W')<CR>
27
28" constants
29" not a comment
30let s:NC = '\%(--.*\)\@<!'
31" end of string
32let s:ES = '\s*\%(--.*\)\=$'
33" no "end" keyword in front
34let s:NE = '\%(\<end\s\+\)\@<!'
35
36" for matchit plugin
37if exists("loaded_matchit")
38 let b:match_ignorecase = 1
39 let b:match_words =
40 \ s:NE.'\<if\>:\<elsif\>:\<else\>:\<end\s\+if\>,'.
41 \ s:NE.'\<case\>:\<when\>:\<end\s\+case\>,'.
42 \ s:NE.'\<loop\>:\<end\s\+loop\>,'.
43 \ s:NE.'\<for\>:\<end\s\+for\>,'.
44 \ s:NE.'\<generate\>:\<end\s\+generate\>,'.
45 \ s:NE.'\<record\>:\<end\s\+record\>,'.
46 \ s:NE.'\<units\>:\<end\s\+units\>,'.
47 \ s:NE.'\<process\>:\<end\s\+process\>,'.
48 \ s:NE.'\<block\>:\<end\s\+block\>,'.
49 \ s:NE.'\<function\>:\<end\s\+function\>,'.
50 \ s:NE.'\<entity\>:\<end\s\+entity\>,'.
51 \ s:NE.'\<component\>:\<end\s\+component\>,'.
52 \ s:NE.'\<architecture\>:\<end\s\+architecture\>,'.
53 \ s:NE.'\<package\>:\<end\s\+package\>,'.
54 \ s:NE.'\<procedure\>:\<end\s\+procedure\>,'.
55 \ s:NE.'\<configuration\>:\<end\s\+configuration\>'
56endif
57
58" only define indent function once
59if exists("*GetVHDLindent")
60 finish
61endif
62
63function GetVHDLindent()
64 " store current line & string
65 let curn = v:lnum
66 let curs = getline(curn)
67
68 " find previous line that is not a comment
69 let prevn = prevnonblank(curn - 1)
70 let prevs = getline(prevn)
71 while prevn > 0 && prevs =~ '^\s*--'
72 let prevn = prevnonblank(prevn - 1)
73 let prevs = getline(prevn)
74 endwhile
75
76 " default indent starts as previous non-comment line's indent
77 let ind = prevn > 0 ? indent(prevn) : 0
78 " backup default
79 let ind2 = ind
80
Bram Moolenaar280f1262006-01-30 00:14:18 +000081 " indent: special; kill string so it would not affect other filters
82 " keywords: "report" + string
83 " where: anywhere in current or previous line
84 let s0 = s:NC.'\<report\>\s*".*"'
85 if curs =~? s0
86 let curs = ""
87 endif
88 if prevs =~? s0
89 let prevs = ""
90 endif
91
Bram Moolenaar51156d52006-01-26 22:17:47 +000092 " indent: previous line's comment position, otherwise follow next non-comment line if possible
93 " keyword: "--"
94 " where: start of current line
95 if curs =~ '^\s*--'
96 let pn = curn - 1
97 let ps = getline(pn)
98 if ps =~ '--'
99 return stridx(ps, '--')
100 else
101 " find nextnonblank line that is not a comment
102 let nn = nextnonblank(curn + 1)
103 let ns = getline(nn)
104 while nn > 0 && ns =~ '^\s*--'
105 let nn = nextnonblank(nn + 1)
106 let ns = getline(nn)
107 endwhile
108 let n = indent(nn)
109 return n != -1 ? n : ind
110 endif
111 endif
112
113 " ****************************************************************************************
114 " indent: align generic variables & port names
115 " keywords: "generic", "map", "port" + "(", provided current line is part of mapping
116 " where: anywhere in previous 2 lines
117 " find following previous non-comment line
118 let pn = prevnonblank(prevn - 1)
119 let ps = getline(pn)
120 while pn > 0 && ps =~ '^\s*--'
121 let pn = prevnonblank(pn - 1)
122 let ps = getline(pn)
123 endwhile
124 if (curs =~ '^\s*)' || curs =~? s:NC.'\%(\<\%(generic\|map\|port\)\>.*\)\@<!\%(=>\s*\S\+\|:[^=]\@=\s*\%(\%(in\|out\|inout\|buffer\|linkage\)\>\|\w\+\s\+:=\)\)') && (prevs =~? s:NC.'\<\%(generic\|map\|port\)\s*(\%(\s*\w\)\=' || (ps =~? s:NC.'\<\%(generic\|map\|port\)'.s:ES && prevs =~ '^\s*('))
125 " align closing ")" with opening "("
126 if curs =~ '^\s*)'
127 return stridx(prevs, '(')
128 endif
129 let m = matchend(prevs, '(\s*\ze\w')
130 if m != -1
131 return m
132 else
133 return stridx(prevs, '(') + &sw
134 endif
135 endif
136
137 " indent: align conditional/select statement
Bram Moolenaar280f1262006-01-30 00:14:18 +0000138 " keywords: variable + "<=" without ";" ending
139 " where: start of previous line
140 if prevs =~? '^\s*\S\+\s*<=[^;]*'.s:ES
Bram Moolenaar51156d52006-01-26 22:17:47 +0000141 return matchend(prevs, '<=\s*\ze.')
142 endif
143
144 " indent: backtrace previous non-comment lines for next smaller or equal size indent
145 " keywords: "end" + "record", "units"
146 " where: start of previous line
147 " keyword: ")"
148 " where: start of previous line
149 " keyword: without "<=" + ";" ending
150 " where: anywhere in previous line
151 " keyword: "=>" + ")" ending, provided current line does not begin with ")"
152 " where: anywhere in previous line
153 " _note_: indent allowed to leave this filter
154 let m = 0
155 if prevs =~? '^\s*end\s\+\%(record\|units\)\>'
156 let m = 3
157 elseif prevs =~ '^\s*)'
158 let m = 1
159 elseif prevs =~ s:NC.'\%(<=.*\)\@<!;'.s:ES || (curs !~ '^\s*)' && prevs =~ s:NC.'=>.*'.s:NC.')'.s:ES)
160 let m = 2
161 endif
162
163 if m > 0
164 let pn = prevnonblank(prevn - 1)
165 let ps = getline(pn)
166 while pn > 0
167 let t = indent(pn)
168 if ps !~ '^\s*--' && t < ind
169 " make sure one of these is true
Bram Moolenaar280f1262006-01-30 00:14:18 +0000170 " keywords: variable + "<=" without ";" ending
171 " where: start of previous non-comment line
Bram Moolenaar51156d52006-01-26 22:17:47 +0000172 " keywords: "generic", "map", "port"
173 " where: anywhere in previous non-comment line
174 " keyword: "("
175 " where: start of previous non-comment line
Bram Moolenaar280f1262006-01-30 00:14:18 +0000176 if m < 3 && ps !~? '^\s*\S\+\s*<=[^;]*'.s:ES
Bram Moolenaar51156d52006-01-26 22:17:47 +0000177 if ps =~? s:NC.'\<\%(generic\|map\|port\)\>' || ps =~ '^\s*('
178 let ind = t
179 endif
180 break
181 endif
182 let ind = t
183 if m > 1
184 " find following previous non-comment line
185 let ppn = prevnonblank(pn - 1)
186 let pps = getline(ppn)
187 while ppn > 0 && pps =~ '^\s*--'
188 let ppn = prevnonblank(ppn - 1)
189 let pps = getline(ppn)
190 endwhile
191 " indent: follow
192 " keyword: "select"
193 " where: end of following previous non-comment line
194 " keyword: "type"
195 " where: start of following previous non-comment line
196 if m == 2
197 let s1 = s:NC.'\<select'.s:ES
198 if ps !~? s1 && pps =~? s1
199 let ind = indent(ppn)
200 endif
201 elseif m == 3
202 let s1 = '^\s*type\>'
203 if ps !~? s1 && pps =~? s1
204 let ind = indent(ppn)
205 endif
206 endif
207 endif
208 break
209 endif
210 let pn = prevnonblank(pn - 1)
211 let ps = getline(pn)
212 endwhile
213 endif
214
215 " indent: follow indent of previous opening statement, otherwise -sw
216 " keyword: "begin"
217 " where: anywhere in current line
218 if curs =~? s:NC.'\<begin\>'
219 let ind = ind - &sw
220 " find previous opening statement of
221 " keywords: "architecture", "block", "entity", "function", "generate", "procedure", "process"
222 let s2 = s:NC.s:NE.'\<\%(architecture\|block\|entity\|function\|generate\|procedure\|process\)\>'
223 if curs !~? s2.'.*'.s:NC.'\<begin\>.*'.s:ES && prevs =~? s2
224 let ind = ind + &sw
225 endif
226 return ind
227 endif
228
229 " indent: +sw if previous line is previous opening statement
230 " keywords: "record", "units"
231 " where: anywhere in current line
232 if curs =~? s:NC.s:NE.'\<\%(record\|units\)\>'
233 " find previous opening statement of
234 " keyword: "type"
235 let s3 = s:NC.s:NE.'\<type\>'
236 if curs !~? s3.'.*'.s:NC.'\<\%(record\|units\)\>.*'.s:ES && prevs =~? s3
237 let ind = ind + &sw
238 endif
239 return ind
240 endif
241
242 " ****************************************************************************************
243 " indent: 0
244 " keywords: "architecture", "configuration", "entity", "library", "package"
245 " where: start of current line
246 if curs =~? '^\s*\%(architecture\|configuration\|entity\|library\|package\)\>'
247 return 0
248 endif
249
Bram Moolenaar280f1262006-01-30 00:14:18 +0000250 " indent: maintain indent of previous opening statement
Bram Moolenaar51156d52006-01-26 22:17:47 +0000251 " keyword: "is"
252 " where: start of current line
253 " find previous opening statement of
254 " keywords: "architecture", "block", "configuration", "entity", "function", "package", "procedure", "process", "type"
255 if curs =~? '^\s*\<is\>' && prevs =~? s:NC.s:NE.'\<\%(architecture\|block\|configuration\|entity\|function\|package\|procedure\|process\|type\)\>'
Bram Moolenaar280f1262006-01-30 00:14:18 +0000256 return ind2
Bram Moolenaar51156d52006-01-26 22:17:47 +0000257 endif
258
Bram Moolenaar280f1262006-01-30 00:14:18 +0000259 " indent: maintain indent of previous opening statement
Bram Moolenaar51156d52006-01-26 22:17:47 +0000260 " keyword: "then"
261 " where: start of current line
262 " find previous opening statement of
263 " keywords: "elsif", "if"
264 if curs =~? '^\s*\<then\>' && (prevs =~? s:NC.'\<elsif\>' || prevs =~? s:NC.s:NE.'\<if\>')
Bram Moolenaar280f1262006-01-30 00:14:18 +0000265 return ind2
Bram Moolenaar51156d52006-01-26 22:17:47 +0000266 endif
267
Bram Moolenaar280f1262006-01-30 00:14:18 +0000268 " indent: maintain indent of previous opening statement
Bram Moolenaar51156d52006-01-26 22:17:47 +0000269 " keyword: "generate"
270 " where: start of current line
271 " find previous opening statement of
272 " keywords: "for", "if"
Bram Moolenaar280f1262006-01-30 00:14:18 +0000273 if curs =~? '^\s*\<generate\>' && (prevs =~? s:NC.s:NE.'\%(\<wait\s\+\)\@<!\<for\>' || prevs =~? s:NC.s:NE.'\<if\>')
274 return ind2
Bram Moolenaar51156d52006-01-26 22:17:47 +0000275 endif
276
277 " indent: +sw
Bram Moolenaar280f1262006-01-30 00:14:18 +0000278 " keywords: "block", "loop", "process", "record", "units"
Bram Moolenaar51156d52006-01-26 22:17:47 +0000279 " removed: "case", "if"
280 " where: anywhere in previous line
Bram Moolenaar280f1262006-01-30 00:14:18 +0000281 if prevs =~? s:NC.s:NE.'\<\%(block\|loop\|process\|record\|units\)\>'
Bram Moolenaar51156d52006-01-26 22:17:47 +0000282 return ind + &sw
283 endif
284
285 " indent: +sw
286 " keywords: "begin"
287 " removed: "elsif", "while"
288 " where: anywhere in previous line
289 if prevs =~? s:NC.'\<begin\>'
290 return ind + &sw
291 endif
292
293 " indent: +sw
Bram Moolenaar280f1262006-01-30 00:14:18 +0000294 " keywords: "architecture", "component", "configuration", "entity", "for", "package"
295 " removed: "when", "with"
Bram Moolenaar51156d52006-01-26 22:17:47 +0000296 " where: start of previous line
Bram Moolenaar280f1262006-01-30 00:14:18 +0000297 if prevs =~? '^\s*\%(architecture\|component\|configuration\|entity\|for\|package\)\>'
Bram Moolenaar51156d52006-01-26 22:17:47 +0000298 return ind + &sw
299 endif
300
301 " indent: +sw
302 " keyword: "generate", "is", "select", "=>"
303 " where: end of previous line
304 if prevs =~? s:NC.'\<\%(generate\|is\|select\)'.s:ES || prevs =~? s:NC.'=>'.s:ES
305 return ind + &sw
306 endif
307
308 " indent: +sw
309 " keyword: "else", "then"
310 " where: end of previous line
311 " _note_: indent allowed to leave this filter
312 if prevs =~? s:NC.'\<\%(else\|then\)'.s:ES
313 let ind = ind + &sw
314 endif
315
316 " ****************************************************************************************
317 " indent: -sw if previous line does not begin with "when"
318 " keywords: "when"
319 " where: start of current line
320 let s4 = '^\s*when\>'
321 if curs =~? s4 && prevs !~? s4
322 return ind - &sw
323 endif
324
325 " indent: -sw
326 " keywords: "else", "elsif"
327 " where: start of current line
328 if curs =~? '^\s*\%(else\|elsif\)\>'
329 return ind - &sw
330 endif
331
332 " indent: -sw
Bram Moolenaar280f1262006-01-30 00:14:18 +0000333 " keywords: "end" + "block", "for", "function", "generate", "if", "loop", "procedure", "process", "record", "units"
Bram Moolenaar51156d52006-01-26 22:17:47 +0000334 " where: start of current line
335 " keyword: ")"
336 " where: start of current line
Bram Moolenaar280f1262006-01-30 00:14:18 +0000337 if curs =~? '^\s*end\s\+\%(block\|for\|function\|generate\|if\|loop\|procedure\|process\|record\|units\)\>' || curs =~ '^\s*)'
Bram Moolenaar51156d52006-01-26 22:17:47 +0000338 return ind - &sw
339 endif
340
Bram Moolenaar280f1262006-01-30 00:14:18 +0000341 " indent: backtrace previous non-comment lines
342 " keyword: "end" + "case", "component"
Bram Moolenaar51156d52006-01-26 22:17:47 +0000343 " where: start of current line
Bram Moolenaar280f1262006-01-30 00:14:18 +0000344 let m = 0
Bram Moolenaar51156d52006-01-26 22:17:47 +0000345 if curs =~? '^\s*end\s\+case\>'
Bram Moolenaar280f1262006-01-30 00:14:18 +0000346 let m = 1
347 elseif curs =~? '^\s*end\s\+component\>'
348 let m = 2
349 endif
350
351 if m > 0
Bram Moolenaar51156d52006-01-26 22:17:47 +0000352 " find following previous non-comment line
353 let pn = prevn
354 let ps = getline(pn)
355 while pn > 0
356 if ps !~ '^\s*--'
Bram Moolenaar280f1262006-01-30 00:14:18 +0000357 "indent: -2sw
358 "keywords: "end" + "case"
359 "where: start of previous non-comment line
360 "indent: -sw
361 "keywords: "when"
362 "where: start of previous non-comment line
363 "indent: follow
364 "keywords: "case"
365 "where: start of previous non-comment line
366 if m == 1
367 if ps =~? '^\s*end\s\+case\>'
368 return indent(pn) - 2 * &sw
369 elseif ps =~? '^\s*when\>'
370 return indent(pn) - &sw
371 elseif ps =~? '^\s*case\>'
372 return indent(pn)
373 endif
374 "indent: follow
375 "keyword: "component"
376 "where: anywhere in previous non-comment line
377 elseif m == 2
378 if ps =~? s:NC.s:NE.'\<component\>'
379 return indent(pn)
380 endif
Bram Moolenaar51156d52006-01-26 22:17:47 +0000381 endif
382 endif
383 let pn = prevnonblank(pn - 1)
384 let ps = getline(pn)
385 endwhile
Bram Moolenaar280f1262006-01-30 00:14:18 +0000386 return ind - &sw
Bram Moolenaar51156d52006-01-26 22:17:47 +0000387 endif
388
389 " indent: 0
390 " keywords: "end" + "architecture", "configuration", "entity", "package"
391 " where: start of current line
392 if curs =~? '^\s*end\s\+\%(architecture\|configuration\|entity\|package\)\>'
393 return 0
394 endif
395
396 " indent: -sw
397 " keywords: "end" + identifier
398 " where: start of current line
399 if curs =~? '^\s*end\s\+\w\+\>'
400 return ind - &sw
401 endif
402
403 " ****************************************************************************************
Bram Moolenaar280f1262006-01-30 00:14:18 +0000404 " indent: maintain indent of previous opening statement
Bram Moolenaar51156d52006-01-26 22:17:47 +0000405 " keywords: without "generic", "map", "port" + ":" but not ":=" + "in", "out", "inout", "buffer", "linkage", variable & ":="
406 " where: anywhere in current line
407 if curs =~? s:NC.'\%(\<\%(generic\|map\|port\)\>.*\)\@<!:[^=]\@=\s*\%(\%(in\|out\|inout\|buffer\|linkage\)\>\|\w\+\s\+:=\)'
408 return ind2
409 endif
410
411 " return leftover filtered indent
412 return ind
413endfunction