Update runtime files
[MacVim.git] / runtime / indent / vhdl.vim
blob9940cc5b5e86270f7c03be11a24f1b841ac30ec6
1 " VHDL indent ('93 syntax)
2 " Language:    VHDL
3 " Maintainer:  Gerald Lai <laigera+vim?gmail.com>
4 " Version:     1.54
5 " Last Change: 2007 Aug 17
6 " URL:         http://www.vim.org/scripts/script.php?script_id=1450
8 " only load this indent file when no other was loaded
9 if exists("b:did_indent")
10   finish
11 endif
12 let b:did_indent = 1
14 " setup indent options for local VHDL buffer
15 setlocal indentexpr=GetVHDLindent()
16 setlocal indentkeys=!^F,o,O,0(,0)
17 setlocal indentkeys+==~begin,=~end\ ,=~end\     ,=~is,=~select,=~when
18 setlocal indentkeys+==~if,=~then,=~elsif,=~else
19 setlocal indentkeys+==~case,=~loop,=~for,=~generate,=~record,=~units,=~process,=~block,=~function,=~component,=~procedure
20 setlocal indentkeys+==~architecture,=~configuration,=~entity,=~package
22 " constants
23 " not a comment
24 let s:NC = '\%(--.*\)\@<!'
25 " end of string
26 let s:ES = '\s*\%(--.*\)\=$'
27 " no "end" keyword in front
28 let s:NE = '\%(\<end\s\+\)\@<!'
30 " option to disable alignment of generic/port mappings
31 if !exists("g:vhdl_indent_genportmap")
32   let g:vhdl_indent_genportmap = 1
33 endif
35 " option to disable alignment of right-hand side assignment "<=" statements
36 if !exists("g:vhdl_indent_rhsassign")
37   let g:vhdl_indent_rhsassign = 1
38 endif
40 " only define indent function once
41 if exists("*GetVHDLindent")
42   finish
43 endif
45 function GetVHDLindent()
46   " store current line & string
47   let curn = v:lnum
48   let curs = getline(curn)
50   " find previous line that is not a comment
51   let prevn = prevnonblank(curn - 1)
52   let prevs = getline(prevn)
53   while prevn > 0 && prevs =~ '^\s*--'
54     let prevn = prevnonblank(prevn - 1)
55     let prevs = getline(prevn)
56   endwhile
57   let prevs_noi = substitute(prevs, '^\s*', '', '')
59   " default indent starts as previous non-comment line's indent
60   let ind = prevn > 0 ? indent(prevn) : 0
61   " backup default
62   let ind2 = ind
64   " indent:   special; kill string so it would not affect other filters
65   " keywords: "report" + string
66   " where:    anywhere in current or previous line
67   let s0 = s:NC.'\<report\>\s*".*"'
68   if curs =~? s0
69     let curs = ""
70   endif
71   if prevs =~? s0
72     let prevs = ""
73   endif
75   " indent:   previous line's comment position, otherwise follow next non-comment line if possible
76   " keyword:  "--"
77   " where:    start of current line
78   if curs =~ '^\s*--'
79     let pn = curn - 1
80     let ps = getline(pn)
81     if curs =~ '^\s*--\s' && ps =~ '--'
82       return indent(pn) + stridx(substitute(ps, '^\s*', '', ''), '--')
83     else
84       " find nextnonblank line that is not a comment
85       let nn = nextnonblank(curn + 1)
86       let ns = getline(nn)
87       while nn > 0 && ns =~ '^\s*--'
88         let nn = nextnonblank(nn + 1)
89         let ns = getline(nn)
90       endwhile
91       let n = indent(nn)
92       return n != -1 ? n : ind
93     endif
94   endif
96   " ****************************************************************************************
97   " indent:   align generic variables & port names
98   " keywords: "generic", "map", "port" + "(", provided current line is part of mapping
99   " where:    anywhere in previous 2 lines
100   " find following previous non-comment line
101   let pn = prevnonblank(prevn - 1)
102   let ps = getline(pn)
103   while pn > 0 && ps =~ '^\s*--'
104     let pn = prevnonblank(pn - 1)
105     let ps = getline(pn)
106   endwhile
107   if (curs =~ '^\s*)' || curs =~? '^\s*\%(\<\%(generic\|map\|port\)\>.*\)\@<!\S\+\s*\%(=>\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*('))
108     " align closing ")" with opening "("
109     if curs =~ '^\s*)'
110       return ind2 + stridx(prevs_noi, '(')
111     endif
112     let m = matchend(prevs_noi, '(\s*\ze\w')
113     if m != -1
114       return ind2 + m
115     else
116       if g:vhdl_indent_genportmap
117         return ind2 + stridx(prevs_noi, '(') + &sw
118       else
119         return ind2 + &sw
120       endif
121     endif
122   endif
124   " indent:   align conditional/select statement
125   " keywords: variable + "<=" without ";" ending
126   " where:    start of previous line
127   if prevs =~? '^\s*\S\+\s*<=[^;]*'.s:ES
128     if g:vhdl_indent_rhsassign
129       return ind2 + matchend(prevs_noi, '<=\s*\ze.')
130     else
131       return ind2 + &sw
132     endif
133   endif
135   " indent:   backtrace previous non-comment lines for next smaller or equal size indent
136   " keywords: "end" + "record", "units"
137   " where:    start of previous line
138   " keyword:  ")"
139   " where:    start of previous line
140   " keyword:  without "<=" + ";" ending
141   " where:    anywhere in previous line
142   " keyword:  "=>" + ")" ending, provided current line does not begin with ")"
143   " where:    anywhere in previous line
144   " _note_:   indent allowed to leave this filter
145   let m = 0
146   if prevs =~? '^\s*end\s\+\%(record\|units\)\>'
147     let m = 3
148   elseif prevs =~ '^\s*)'
149     let m = 1
150   elseif prevs =~ s:NC.'\%(<=.*\)\@<!;'.s:ES || (curs !~ '^\s*)' && prevs =~ s:NC.'=>.*'.s:NC.')'.s:ES)
151     let m = 2
152   endif
154   if m > 0
155     let pn = prevnonblank(prevn - 1)
156     let ps = getline(pn)
157     while pn > 0
158       let t = indent(pn)
159       if ps !~ '^\s*--' && t < ind
160         " make sure one of these is true
161         " keywords: variable + "<=" without ";" ending
162         " where:    start of previous non-comment line
163         " keywords: "generic", "map", "port"
164         " where:    anywhere in previous non-comment line
165         " keyword:  "("
166         " where:    start of previous non-comment line
167         if m < 3 && ps !~? '^\s*\S\+\s*<=[^;]*'.s:ES
168           if ps =~? s:NC.'\<\%(generic\|map\|port\)\>' || ps =~ '^\s*('
169             let ind = t
170           endif
171           break
172         endif
173         let ind = t
174         if m > 1
175           " find following previous non-comment line
176           let ppn = prevnonblank(pn - 1)
177           let pps = getline(ppn)
178           while ppn > 0 && pps =~ '^\s*--'
179             let ppn = prevnonblank(ppn - 1)
180             let pps = getline(ppn)
181           endwhile
182           " indent:   follow
183           " keyword:  "select"
184           " where:    end of following previous non-comment line
185           " keyword:  "type"
186           " where:    start of following previous non-comment line
187           if m == 2
188             let s1 = s:NC.'\<select'.s:ES
189             if ps !~? s1 && pps =~? s1
190               let ind = indent(ppn)
191             endif
192           elseif m == 3
193             let s1 = '^\s*type\>'
194             if ps !~? s1 && pps =~? s1
195               let ind = indent(ppn)
196             endif
197           endif
198         endif
199         break
200       endif
201       let pn = prevnonblank(pn - 1)
202       let ps = getline(pn)
203     endwhile
204   endif
206   " indent:   follow indent of previous opening statement, otherwise -sw
207   " keyword:  "begin"
208   " where:    anywhere in current line
209   if curs =~? s:NC.'\<begin\>'
210     let ind = ind - &sw
211     " find previous opening statement of
212     " keywords: "architecture", "block", "entity", "function", "generate", "procedure", "process"
213     let s2 = s:NC.s:NE.'\<\%(architecture\|block\|entity\|function\|generate\|procedure\|process\)\>'
214     if (curs !~? s2.'.*'.s:NC.'\<begin\>.*'.s:ES && prevs =~? s2) || m == 1
215       let ind = ind + &sw
216     endif
217     return ind
218   endif
220   " indent:   +sw if previous line is previous opening statement
221   " keywords: "record", "units"
222   " where:    anywhere in current line
223   if curs =~? s:NC.s:NE.'\<\%(record\|units\)\>'
224     " find previous opening statement of
225     " keyword: "type"
226     let s3 = s:NC.s:NE.'\<type\>'
227     if curs !~? s3.'.*'.s:NC.'\<\%(record\|units\)\>.*'.s:ES && prevs =~? s3
228       let ind = ind + &sw
229     endif
230     return ind
231   endif
233   " ****************************************************************************************
234   " indent:   0
235   " keywords: "architecture", "configuration", "entity", "library", "package"
236   " where:    start of current line
237   if curs =~? '^\s*\%(architecture\|configuration\|entity\|library\|package\)\>'
238     return 0
239   endif
241   " indent:   maintain indent of previous opening statement
242   " keyword:  "is"
243   " where:    start of current line
244   " find previous opening statement of
245   " keywords: "architecture", "block", "configuration", "entity", "function", "package", "procedure", "process", "type"
246   if curs =~? '^\s*\<is\>' && prevs =~? s:NC.s:NE.'\<\%(architecture\|block\|configuration\|entity\|function\|package\|procedure\|process\|type\)\>'
247     return ind2
248   endif
250   " indent:   maintain indent of previous opening statement
251   " keyword:  "then"
252   " where:    start of current line
253   " find previous opening statement of
254   " keywords: "elsif", "if"
255   if curs =~? '^\s*\<then\>' && prevs =~? s:NC.'\%(\<elsif\>\|'.s:NE.'\<if\>\)'
256     return ind2
257   endif
259   " indent:   maintain indent of previous opening statement
260   " keyword:  "generate"
261   " where:    start of current line
262   " find previous opening statement of
263   " keywords: "for", "if"
264   if curs =~? '^\s*\<generate\>' && prevs =~? s:NC.s:NE.'\%(\%(\<wait\s\+\)\@<!\<for\|\<if\)\>'
265     return ind2
266   endif
268   " indent:   +sw
269   " keywords: "block", "process"
270   " removed:  "begin", "case", "elsif", "if", "loop", "record", "units", "while"
271   " where:    anywhere in previous line
272   if prevs =~? s:NC.s:NE.'\<\%(block\|process\)\>'
273     return ind + &sw
274   endif
276   " indent:   +sw
277   " keywords: "architecture", "configuration", "entity", "package"
278   " removed:  "component", "for", "when", "with"
279   " where:    start of previous line
280   if prevs =~? '^\s*\%(architecture\|configuration\|entity\|package\)\>'
281     return ind + &sw
282   endif
284   " indent:   +sw
285   " keyword:  "select"
286   " removed:  "generate", "is", "=>"
287   " where:    end of previous line
288   if prevs =~? s:NC.'\<select'.s:ES
289     return ind + &sw
290   endif
292   " indent:   +sw
293   " keyword:  "begin", "loop", "record", "units"
294   " where:    anywhere in previous line
295   " keyword:  "component", "else", "for"
296   " where:    start of previous line
297   " keyword:  "generate", "is", "then", "=>"
298   " where:    end of previous line
299   " _note_:   indent allowed to leave this filter
300   if prevs =~? s:NC.'\%(\<begin\>\|'.s:NE.'\<\%(loop\|record\|units\)\>\)' || prevs =~? '^\s*\%(component\|else\|for\)\>' || prevs =~? s:NC.'\%('.s:NE.'\<generate\|\<\%(is\|then\)\|=>\)'.s:ES
301     let ind = ind + &sw
302   endif
304   " ****************************************************************************************
305   " indent:   -sw
306   " keywords: "when", provided previous line does not begin with "when", does not end with "is"
307   " where:    start of current line
308   let s4 = '^\s*when\>'
309   if curs =~? s4
310     if prevs =~? s:NC.'\<is'.s:ES
311       return ind
312     elseif prevs !~? s4
313       return ind - &sw
314     else
315       return ind2
316     endif
317   endif
319   " indent:   -sw
320   " keywords: "else", "elsif", "end" + "block", "for", "function", "generate", "if", "loop", "procedure", "process", "record", "units"
321   " where:    start of current line
322   if curs =~? '^\s*\%(else\|elsif\|end\s\+\%(block\|for\|function\|generate\|if\|loop\|procedure\|process\|record\|units\)\)\>'
323     return ind - &sw
324   endif
326   " indent:   backtrace previous non-comment lines
327   " keyword:  "end" + "case", "component"
328   " where:    start of current line
329   let m = 0
330   if curs =~? '^\s*end\s\+case\>'
331     let m = 1
332   elseif curs =~? '^\s*end\s\+component\>'
333     let m = 2
334   endif
336   if m > 0
337     " find following previous non-comment line
338     let pn = prevn
339     let ps = getline(pn)
340     while pn > 0
341       if ps !~ '^\s*--'
342         "indent:   -2sw
343         "keywords: "end" + "case"
344         "where:    start of previous non-comment line
345         "indent:   -sw
346         "keywords: "when"
347         "where:    start of previous non-comment line
348         "indent:   follow
349         "keywords: "case"
350         "where:    start of previous non-comment line
351         if m == 1
352           if ps =~? '^\s*end\s\+case\>'
353             return indent(pn) - 2 * &sw
354           elseif ps =~? '^\s*when\>'
355             return indent(pn) - &sw
356           elseif ps =~? '^\s*case\>'
357             return indent(pn)
358           endif
359         "indent:   follow
360         "keyword:  "component"
361         "where:    start of previous non-comment line
362         elseif m == 2
363           if ps =~? '^\s*component\>'
364             return indent(pn)
365           endif
366         endif
367       endif
368       let pn = prevnonblank(pn - 1)
369       let ps = getline(pn)
370     endwhile
371     return ind - &sw
372   endif
374   " indent:   -sw
375   " keyword:  ")"
376   " where:    start of current line
377   if curs =~ '^\s*)'
378     return ind - &sw
379   endif
381   " indent:   0
382   " keywords: "end" + "architecture", "configuration", "entity", "package"
383   " where:    start of current line
384   if curs =~? '^\s*end\s\+\%(architecture\|configuration\|entity\|package\)\>'
385     return 0
386   endif
388   " indent:   -sw
389   " keywords: "end" + identifier
390   " where:    start of current line
391   "if curs =~? '^\s*end\s\+\w\+\>'
392   if curs =~? '^\s*end\s'
393     return ind - &sw
394   endif
396   " ****************************************************************************************
397   " indent:   maintain indent of previous opening statement
398   " keywords: without "generic", "map", "port" + ":" but not ":=" + "in", "out", "inout", "buffer", "linkage", variable & ":="
399   " where:    start of current line
400   if curs =~? '^\s*\%(\<\%(generic\|map\|port\)\>.*\)\@<!\S\+\s*:[^=]\@=\s*\%(\%(in\|out\|inout\|buffer\|linkage\)\>\|\w\+\s\+:=\)'
401     return ind2
402   endif
404   " return leftover filtered indent
405   return ind
406 endfunction