Integration prefs pane update
[MacVim.git] / runtime / indent / vhdl.vim
blobd288be4ceb113e9d4415609e21e4b4c841aaf847
1 " VHDL indent ('93 syntax)
2 " Language:    VHDL
3 " Maintainer:  Gerald Lai <laigera+vim?gmail.com>
4 " Version:     1.50
5 " Last Change: 2007 Jan 29
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_align_genportmap")
32   let g:vhdl_align_genportmap = 1
33 endif
35 " option to disable alignment of right-hand side assignment "<=" statements
36 if !exists("g:vhdl_align_rhsassign")
37   let g:vhdl_align_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
58   " default indent starts as previous non-comment line's indent
59   let ind = prevn > 0 ? indent(prevn) : 0
60   " backup default
61   let ind2 = ind
63   " indent:   special; kill string so it would not affect other filters
64   " keywords: "report" + string
65   " where:    anywhere in current or previous line
66   let s0 = s:NC.'\<report\>\s*".*"'
67   if curs =~? s0
68     let curs = ""
69   endif
70   if prevs =~? s0
71     let prevs = ""
72   endif
74   " indent:   previous line's comment position, otherwise follow next non-comment line if possible
75   " keyword:  "--"
76   " where:    start of current line
77   if curs =~ '^\s*--'
78     let pn = curn - 1
79     let ps = getline(pn)
80     if ps =~ '--'
81       return stridx(ps, '--')
82     else
83       " find nextnonblank line that is not a comment
84       let nn = nextnonblank(curn + 1)
85       let ns = getline(nn)
86       while nn > 0 && ns =~ '^\s*--'
87         let nn = nextnonblank(nn + 1)
88         let ns = getline(nn)
89       endwhile
90       let n = indent(nn)
91       return n != -1 ? n : ind
92     endif
93   endif
95   " ****************************************************************************************
96   " indent:   align generic variables & port names
97   " keywords: "generic", "map", "port" + "(", provided current line is part of mapping
98   " where:    anywhere in previous 2 lines
99   " find following previous non-comment line
100   let pn = prevnonblank(prevn - 1)
101   let ps = getline(pn)
102   while pn > 0 && ps =~ '^\s*--'
103     let pn = prevnonblank(pn - 1)
104     let ps = getline(pn)
105   endwhile
106   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*('))
107     " align closing ")" with opening "("
108     if curs =~ '^\s*)'
109       return stridx(prevs, '(')
110     endif
111     let m = matchend(prevs, '(\s*\ze\w')
112     if m != -1
113       return m
114     else
115       if g:vhdl_align_genportmap
116         return stridx(prevs, '(') + &sw
117       else
118         return ind2 + &sw
119       endif
120     endif
121   endif
123   " indent:   align conditional/select statement
124   " keywords: variable + "<=" without ";" ending
125   " where:    start of previous line
126   if prevs =~? '^\s*\S\+\s*<=[^;]*'.s:ES
127     if g:vhdl_align_rhsassign
128       return matchend(prevs, '<=\s*\ze.')
129     else
130       return ind2 + &sw
131     endif
132   endif
134   " indent:   backtrace previous non-comment lines for next smaller or equal size indent
135   " keywords: "end" + "record", "units"
136   " where:    start of previous line
137   " keyword:  ")"
138   " where:    start of previous line
139   " keyword:  without "<=" + ";" ending
140   " where:    anywhere in previous line
141   " keyword:  "=>" + ")" ending, provided current line does not begin with ")"
142   " where:    anywhere in previous line
143   " _note_:   indent allowed to leave this filter
144   let m = 0
145   if prevs =~? '^\s*end\s\+\%(record\|units\)\>'
146     let m = 3
147   elseif prevs =~ '^\s*)'
148     let m = 1
149   elseif prevs =~ s:NC.'\%(<=.*\)\@<!;'.s:ES || (curs !~ '^\s*)' && prevs =~ s:NC.'=>.*'.s:NC.')'.s:ES)
150     let m = 2
151   endif
153   if m > 0
154     let pn = prevnonblank(prevn - 1)
155     let ps = getline(pn)
156     while pn > 0
157       let t = indent(pn)
158       if ps !~ '^\s*--' && t < ind
159         " make sure one of these is true
160         " keywords: variable + "<=" without ";" ending
161         " where:    start of previous non-comment line
162         " keywords: "generic", "map", "port"
163         " where:    anywhere in previous non-comment line
164         " keyword:  "("
165         " where:    start of previous non-comment line
166         if m < 3 && ps !~? '^\s*\S\+\s*<=[^;]*'.s:ES
167           if ps =~? s:NC.'\<\%(generic\|map\|port\)\>' || ps =~ '^\s*('
168             let ind = t
169           endif
170           break
171         endif
172         let ind = t
173         if m > 1
174           " find following previous non-comment line
175           let ppn = prevnonblank(pn - 1)
176           let pps = getline(ppn)
177           while ppn > 0 && pps =~ '^\s*--'
178             let ppn = prevnonblank(ppn - 1)
179             let pps = getline(ppn)
180           endwhile
181           " indent:   follow
182           " keyword:  "select"
183           " where:    end of following previous non-comment line
184           " keyword:  "type"
185           " where:    start of following previous non-comment line
186           if m == 2
187             let s1 = s:NC.'\<select'.s:ES
188             if ps !~? s1 && pps =~? s1
189               let ind = indent(ppn)
190             endif
191           elseif m == 3
192             let s1 = '^\s*type\>'
193             if ps !~? s1 && pps =~? s1
194               let ind = indent(ppn)
195             endif
196           endif
197         endif
198         break
199       endif
200       let pn = prevnonblank(pn - 1)
201       let ps = getline(pn)
202     endwhile
203   endif
205   " indent:   follow indent of previous opening statement, otherwise -sw
206   " keyword:  "begin"
207   " where:    anywhere in current line
208   if curs =~? s:NC.'\<begin\>'
209     let ind = ind - &sw
210     " find previous opening statement of
211     " keywords: "architecture", "block", "entity", "function", "generate", "procedure", "process"
212     let s2 = s:NC.s:NE.'\<\%(architecture\|block\|entity\|function\|generate\|procedure\|process\)\>'
213     if (curs !~? s2.'.*'.s:NC.'\<begin\>.*'.s:ES && prevs =~? s2) || m == 1
214       let ind = ind + &sw
215     endif
216     return ind
217   endif
219   " indent:   +sw if previous line is previous opening statement
220   " keywords: "record", "units"
221   " where:    anywhere in current line
222   if curs =~? s:NC.s:NE.'\<\%(record\|units\)\>'
223     " find previous opening statement of
224     " keyword: "type"
225     let s3 = s:NC.s:NE.'\<type\>'
226     if curs !~? s3.'.*'.s:NC.'\<\%(record\|units\)\>.*'.s:ES && prevs =~? s3
227       let ind = ind + &sw
228     endif
229     return ind
230   endif
232   " ****************************************************************************************
233   " indent:   0
234   " keywords: "architecture", "configuration", "entity", "library", "package"
235   " where:    start of current line
236   if curs =~? '^\s*\%(architecture\|configuration\|entity\|library\|package\)\>'
237     return 0
238   endif
240   " indent:   maintain indent of previous opening statement
241   " keyword:  "is"
242   " where:    start of current line
243   " find previous opening statement of
244   " keywords: "architecture", "block", "configuration", "entity", "function", "package", "procedure", "process", "type"
245   if curs =~? '^\s*\<is\>' && prevs =~? s:NC.s:NE.'\<\%(architecture\|block\|configuration\|entity\|function\|package\|procedure\|process\|type\)\>'
246     return ind2
247   endif
249   " indent:   maintain indent of previous opening statement
250   " keyword:  "then"
251   " where:    start of current line
252   " find previous opening statement of
253   " keywords: "elsif", "if"
254   if curs =~? '^\s*\<then\>' && prevs =~? s:NC.'\%(\<elsif\>\|'.s:NE.'\<if\>\)'
255     return ind2
256   endif
258   " indent:   maintain indent of previous opening statement
259   " keyword:  "generate"
260   " where:    start of current line
261   " find previous opening statement of
262   " keywords: "for", "if"
263   if curs =~? '^\s*\<generate\>' && prevs =~? s:NC.s:NE.'\%(\%(\<wait\s\+\)\@<!\<for\|\<if\)\>'
264     return ind2
265   endif
267   " indent:   +sw
268   " keywords: "block", "process"
269   " removed:  "begin", "case", "elsif", "if", "loop", "record", "units", "while"
270   " where:    anywhere in previous line
271   if prevs =~? s:NC.s:NE.'\<\%(block\|process\)\>'
272     return ind + &sw
273   endif
275   " indent:   +sw
276   " keywords: "architecture", "configuration", "entity", "package"
277   " removed:  "component", "for", "when", "with"
278   " where:    start of previous line
279   if prevs =~? '^\s*\%(architecture\|configuration\|entity\|package\)\>'
280     return ind + &sw
281   endif
283   " indent:   +sw
284   " keyword:  "select"
285   " removed:  "generate", "is", "=>"
286   " where:    end of previous line
287   if prevs =~? s:NC.'\<select'.s:ES
288     return ind + &sw
289   endif
291   " indent:   +sw
292   " keyword:  "begin", "loop", "record", "units"
293   " where:    anywhere in previous line
294   " keyword:  "component", "else", "for"
295   " where:    start of previous line
296   " keyword:  "generate", "is", "then", "=>"
297   " where:    end of previous line
298   " _note_:   indent allowed to leave this filter
299   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
300     let ind = ind + &sw
301   endif
303   " ****************************************************************************************
304   " indent:   -sw
305   " keywords: "when", provided previous line does not begin with "when", does not end with "is"
306   " where:    start of current line
307   let s4 = '^\s*when\>'
308   if curs =~? s4
309     if prevs =~? s:NC.'\<is'.s:ES
310       return ind
311     elseif prevs !~? s4
312       return ind - &sw
313     else
314       return ind2
315     endif
316   endif
318   " indent:   -sw
319   " keywords: "else", "elsif", "end" + "block", "for", "function", "generate", "if", "loop", "procedure", "process", "record", "units"
320   " where:    start of current line
321   if curs =~? '^\s*\%(else\|elsif\|end\s\+\%(block\|for\|function\|generate\|if\|loop\|procedure\|process\|record\|units\)\)\>'
322     return ind - &sw
323   endif
325   " indent:   backtrace previous non-comment lines
326   " keyword:  "end" + "case", "component"
327   " where:    start of current line
328   let m = 0
329   if curs =~? '^\s*end\s\+case\>'
330     let m = 1
331   elseif curs =~? '^\s*end\s\+component\>'
332     let m = 2
333   endif
335   if m > 0
336     " find following previous non-comment line
337     let pn = prevn
338     let ps = getline(pn)
339     while pn > 0
340       if ps !~ '^\s*--'
341         "indent:   -2sw
342         "keywords: "end" + "case"
343         "where:    start of previous non-comment line
344         "indent:   -sw
345         "keywords: "when"
346         "where:    start of previous non-comment line
347         "indent:   follow
348         "keywords: "case"
349         "where:    start of previous non-comment line
350         if m == 1
351           if ps =~? '^\s*end\s\+case\>'
352             return indent(pn) - 2 * &sw
353           elseif ps =~? '^\s*when\>'
354             return indent(pn) - &sw
355           elseif ps =~? '^\s*case\>'
356             return indent(pn)
357           endif
358         "indent:   follow
359         "keyword:  "component"
360         "where:    start of previous non-comment line
361         elseif m == 2
362           if ps =~? '^\s*component\>'
363             return indent(pn)
364           endif
365         endif
366       endif
367       let pn = prevnonblank(pn - 1)
368       let ps = getline(pn)
369     endwhile
370     return ind - &sw
371   endif
373   " indent:   -sw
374   " keyword:  ")"
375   " where:    start of current line
376   if curs =~ '^\s*)'
377     return ind - &sw
378   endif
380   " indent:   0
381   " keywords: "end" + "architecture", "configuration", "entity", "package"
382   " where:    start of current line
383   if curs =~? '^\s*end\s\+\%(architecture\|configuration\|entity\|package\)\>'
384     return 0
385   endif
387   " indent:   -sw
388   " keywords: "end" + identifier
389   " where:    start of current line
390   "if curs =~? '^\s*end\s\+\w\+\>'
391   if curs =~? '^\s*end\s'
392     return ind - &sw
393   endif
395   " ****************************************************************************************
396   " indent:   maintain indent of previous opening statement
397   " keywords: without "generic", "map", "port" + ":" but not ":=" + "in", "out", "inout", "buffer", "linkage", variable & ":="
398   " where:    start of current line
399   if curs =~? '^\s*\%(\<\%(generic\|map\|port\)\>.*\)\@<!\S\+\s*:[^=]\@=\s*\%(\%(in\|out\|inout\|buffer\|linkage\)\>\|\w\+\s\+:=\)'
400     return ind2
401   endif
403   " return leftover filtered indent
404   return ind
405 endfunction