7
|
1 " Vim indent file
|
|
2 " Language: Ada
|
|
3 " Maintainer: Neil Bird <neil@fnxweb.com>
|
856
|
4 " Last Change: 2006 Apr 30
|
7
|
5 " Version: $Id$
|
|
6 " Look for the latest version at http://vim.sourceforge.net/
|
|
7 "
|
|
8 " ToDo:
|
|
9 " Verify handling of multi-line exprs. and recovery upon the final ';'.
|
|
10 " Correctly find comments given '"' and "" ==> " syntax.
|
|
11 " Combine the two large block-indent functions into one?
|
|
12
|
|
13 " Only load this indent file when no other was loaded.
|
|
14 if exists("b:did_indent")
|
|
15 finish
|
|
16 endif
|
|
17 let b:did_indent = 1
|
|
18
|
|
19 setlocal indentexpr=GetAdaIndent()
|
|
20 setlocal indentkeys-=0{,0}
|
|
21 setlocal indentkeys+=0=~then,0=~end,0=~elsif,0=~when,0=~exception,0=~begin,0=~is,0=~record
|
|
22
|
|
23 " Only define the functions once.
|
|
24 if exists("*GetAdaIndent")
|
|
25 finish
|
|
26 endif
|
|
27
|
36
|
28 let s:AdaBlockStart = '^\s*\(if\>\|while\>\|else\>\|elsif\>\|loop\>\|for\>.*\<\(loop\|use\)\>\|declare\>\|begin\>\|type\>.*\<is\>[^;]*$\|\(type\>.*\)\=\<record\>\|procedure\>\|function\>\|accept\>\|do\>\|task\>\|package\>\|then\>\|when\>\|is\>\)'
|
7
|
29 let s:AdaComment = "\\v^(\"[^\"]*\"|'.'|[^\"']){-}\\zs\\s*--.*"
|
|
30
|
|
31
|
36
|
32 " Try to find indent of the block we're in
|
7
|
33 " prev_indent = the previous line's indent
|
|
34 " prev_lnum = previous line (to start looking on)
|
|
35 " blockstart = expr. that indicates a possible start of this block
|
|
36 " stop_at = if non-null, if a matching line is found, gives up!
|
|
37 " No recursive previous block analysis: simply look for a valid line
|
|
38 " with a lesser or equal indent than we currently (on prev_lnum) have.
|
|
39 " This shouldn't work as well as it appears to with lines that are currently
|
|
40 " nowhere near the correct indent (e.g., start of line)!
|
|
41 " Seems to work OK as it 'starts' with the indent of the /previous/ line.
|
|
42 function s:MainBlockIndent( prev_indent, prev_lnum, blockstart, stop_at )
|
|
43 let lnum = a:prev_lnum
|
|
44 let line = substitute( getline(lnum), s:AdaComment, '', '' )
|
|
45 while lnum > 1
|
|
46 if a:stop_at != '' && line =~ '^\s*' . a:stop_at && indent(lnum) < a:prev_indent
|
856
|
47 return a:prev_indent
|
7
|
48 elseif line =~ '^\s*' . a:blockstart
|
856
|
49 let ind = indent(lnum)
|
|
50 if ind < a:prev_indent
|
|
51 return ind
|
|
52 endif
|
7
|
53 endif
|
|
54
|
|
55 let lnum = prevnonblank(lnum - 1)
|
|
56 " Get previous non-blank/non-comment-only line
|
|
57 while 1
|
856
|
58 let line = substitute( getline(lnum), s:AdaComment, '', '' )
|
|
59 if line !~ '^\s*$' && line !~ '^\s*#'
|
|
60 break
|
|
61 endif
|
|
62 let lnum = prevnonblank(lnum - 1)
|
|
63 if lnum <= 0
|
|
64 return a:prev_indent
|
|
65 endif
|
7
|
66 endwhile
|
|
67 endwhile
|
|
68 " Fallback - just move back one
|
|
69 return a:prev_indent - &sw
|
|
70 endfunction
|
|
71
|
|
72 " Try to find indent of the block we're in (and about to complete),
|
|
73 " including handling of nested blocks. Works on the 'end' of a block.
|
|
74 " prev_indent = the previous line's indent
|
|
75 " prev_lnum = previous line (to start looking on)
|
|
76 " blockstart = expr. that indicates a possible start of this block
|
|
77 " blockend = expr. that indicates a possible end of this block
|
|
78 function s:EndBlockIndent( prev_indent, prev_lnum, blockstart, blockend )
|
|
79 let lnum = a:prev_lnum
|
|
80 let line = getline(lnum)
|
|
81 let ends = 0
|
|
82 while lnum > 1
|
|
83 if getline(lnum) =~ '^\s*' . a:blockstart
|
|
84 let ind = indent(lnum)
|
856
|
85 if ends <= 0
|
|
86 if ind < a:prev_indent
|
7
|
87 return ind
|
856
|
88 endif
|
|
89 else
|
|
90 let ends = ends - 1
|
7
|
91 endif
|
|
92 elseif getline(lnum) =~ '^\s*' . a:blockend
|
856
|
93 let ends = ends + 1
|
7
|
94 endif
|
|
95
|
|
96 let lnum = prevnonblank(lnum - 1)
|
|
97 " Get previous non-blank/non-comment-only line
|
|
98 while 1
|
|
99 let line = getline(lnum)
|
|
100 let line = substitute( line, s:AdaComment, '', '' )
|
|
101 if line !~ '^\s*$'
|
|
102 break
|
|
103 endif
|
|
104 let lnum = prevnonblank(lnum - 1)
|
|
105 if lnum <= 0
|
|
106 return a:prev_indent
|
|
107 endif
|
|
108 endwhile
|
|
109 endwhile
|
|
110 " Fallback - just move back one
|
|
111 return a:prev_indent - &sw
|
|
112 endfunction
|
|
113
|
36
|
114 " Return indent of previous statement-start
|
7
|
115 " (after we've indented due to multi-line statements).
|
|
116 " This time, we start searching on the line *before* the one given (which is
|
|
117 " the end of a statement - we want the previous beginning).
|
|
118 function s:StatementIndent( current_indent, prev_lnum )
|
|
119 let lnum = a:prev_lnum
|
|
120 while lnum > 0
|
|
121 let prev_lnum = lnum
|
|
122 let lnum = prevnonblank(lnum - 1)
|
|
123 " Get previous non-blank/non-comment-only line
|
|
124 while 1
|
856
|
125 let line = substitute( getline(lnum), s:AdaComment, '', '' )
|
|
126 if line !~ '^\s*$' && line !~ '^\s*#'
|
|
127 break
|
|
128 endif
|
|
129 let lnum = prevnonblank(lnum - 1)
|
|
130 if lnum <= 0
|
|
131 return a:current_indent
|
|
132 endif
|
7
|
133 endwhile
|
|
134 " Leave indent alone if our ';' line is part of a ';'-delineated
|
|
135 " aggregate (e.g., procedure args.) or first line after a block start.
|
|
136 if line =~ s:AdaBlockStart || line =~ '(\s*$'
|
856
|
137 return a:current_indent
|
7
|
138 endif
|
|
139 if line !~ '[.=(]\s*$'
|
856
|
140 let ind = indent(prev_lnum)
|
|
141 if ind < a:current_indent
|
|
142 return ind
|
|
143 endif
|
7
|
144 endif
|
|
145 endwhile
|
|
146 " Fallback - just use current one
|
|
147 return a:current_indent
|
|
148 endfunction
|
|
149
|
|
150
|
|
151 " Find correct indent of a new line based upon what went before
|
|
152 function GetAdaIndent()
|
|
153 " Find a non-blank line above the current line.
|
|
154 let lnum = prevnonblank(v:lnum - 1)
|
|
155 let ind = indent(lnum)
|
|
156 let package_line = 0
|
|
157
|
|
158 " Get previous non-blank/non-comment-only/non-cpp line
|
|
159 while 1
|
|
160 let line = substitute( getline(lnum), s:AdaComment, '', '' )
|
|
161 if line !~ '^\s*$' && line !~ '^\s*#'
|
856
|
162 break
|
7
|
163 endif
|
|
164 let lnum = prevnonblank(lnum - 1)
|
|
165 if lnum <= 0
|
856
|
166 return ind
|
7
|
167 endif
|
|
168 endwhile
|
|
169
|
|
170 " Get default indent (from prev. line)
|
|
171 let ind = indent(lnum)
|
36
|
172 let initind = ind
|
7
|
173
|
|
174 " Now check what's on the previous line
|
|
175 if line =~ s:AdaBlockStart || line =~ '(\s*$'
|
|
176 " Check for false matches to AdaBlockStart
|
|
177 let false_match = 0
|
|
178 if line =~ '^\s*\(procedure\|function\|package\)\>.*\<is\s*new\>'
|
856
|
179 " Generic instantiation
|
|
180 let false_match = 1
|
7
|
181 elseif line =~ ')\s*;\s*$' || line =~ '^\([^(]*([^)]*)\)*[^(]*;\s*$'
|
856
|
182 " forward declaration
|
|
183 let false_match = 1
|
7
|
184 endif
|
|
185 " Move indent in
|
|
186 if ! false_match
|
856
|
187 let ind = ind + &sw
|
7
|
188 endif
|
|
189 elseif line =~ '^\s*\(case\|exception\)\>'
|
|
190 " Move indent in twice (next 'when' will move back)
|
|
191 let ind = ind + 2 * &sw
|
|
192 elseif line =~ '^\s*end\s*record\>'
|
|
193 " Move indent back to tallying 'type' preceeding the 'record'.
|
|
194 " Allow indent to be equal to 'end record's.
|
|
195 let ind = s:MainBlockIndent( ind+&sw, lnum, 'type\>', '' )
|
|
196 elseif line =~ '\(^\s*new\>.*\)\@<!)\s*[;,]\s*$'
|
|
197 " Revert to indent of line that started this parenthesis pair
|
|
198 exe lnum
|
|
199 exe 'normal! $F)%'
|
|
200 if getline('.') =~ '^\s*('
|
856
|
201 " Dire layout - use previous indent (could check for AdaComment here)
|
|
202 let ind = indent( prevnonblank( line('.')-1 ) )
|
7
|
203 else
|
856
|
204 let ind = indent('.')
|
7
|
205 endif
|
|
206 exe v:lnum
|
|
207 elseif line =~ '[.=(]\s*$'
|
|
208 " A statement continuation - move in one
|
|
209 let ind = ind + &sw
|
|
210 elseif line =~ '^\s*new\>'
|
|
211 " Multiple line generic instantiation ('package blah is\nnew thingy')
|
|
212 let ind = s:StatementIndent( ind - &sw, lnum )
|
|
213 elseif line =~ ';\s*$'
|
36
|
214 " Statement end (but not 'end' ) - try to find current statement-start indent
|
7
|
215 let ind = s:StatementIndent( ind, lnum )
|
|
216 endif
|
|
217
|
|
218 " Check for potential argument list on next line
|
|
219 let continuation = (line =~ '[A-Za-z0-9_]\s*$')
|
|
220
|
|
221
|
|
222 " Check current line; search for simplistic matching start-of-block
|
|
223 let line = getline(v:lnum)
|
|
224 if line =~ '^\s*#'
|
|
225 " Start of line for ada-pp
|
|
226 let ind = 0
|
|
227 elseif continuation && line =~ '^\s*('
|
36
|
228 " Don't do this if we've already indented due to the previous line
|
|
229 if ind == initind
|
856
|
230 let ind = ind + &sw
|
36
|
231 endif
|
7
|
232 elseif line =~ '^\s*\(begin\|is\)\>'
|
|
233 let ind = s:MainBlockIndent( ind, lnum, '\(procedure\|function\|declare\|package\|task\)\>', 'begin\>' )
|
|
234 elseif line =~ '^\s*record\>'
|
36
|
235 let ind = s:MainBlockIndent( ind, lnum, 'type\>\|for\>.*\<use\>', '' ) + &sw
|
7
|
236 elseif line =~ '^\s*\(else\|elsif\)\>'
|
|
237 let ind = s:MainBlockIndent( ind, lnum, 'if\>', '' )
|
|
238 elseif line =~ '^\s*when\>'
|
|
239 " Align 'when' one /in/ from matching block start
|
|
240 let ind = s:MainBlockIndent( ind, lnum, '\(case\|exception\)\>', '' ) + &sw
|
|
241 elseif line =~ '^\s*end\>\s*\<if\>'
|
|
242 " End of if statements
|
|
243 let ind = s:EndBlockIndent( ind, lnum, 'if\>', 'end\>\s*\<if\>' )
|
|
244 elseif line =~ '^\s*end\>\s*\<loop\>'
|
|
245 " End of loops
|
|
246 let ind = s:EndBlockIndent( ind, lnum, '\(\(while\|for\)\>.*\)\?\<loop\>', 'end\>\s*\<loop\>' )
|
|
247 elseif line =~ '^\s*end\>\s*\<record\>'
|
|
248 " End of records
|
|
249 let ind = s:EndBlockIndent( ind, lnum, '\(type\>.*\)\=\<record\>', 'end\>\s*\<record\>' )
|
|
250 elseif line =~ '^\s*end\>\s*\<procedure\>'
|
|
251 " End of procedures
|
|
252 let ind = s:EndBlockIndent( ind, lnum, 'procedure\>.*\<is\>', 'end\>\s*\<procedure\>' )
|
|
253 elseif line =~ '^\s*end\>\s*\<case\>'
|
|
254 " End of case statement
|
|
255 let ind = s:EndBlockIndent( ind, lnum, 'case\>.*\<is\>', 'end\>\s*\<case\>' )
|
|
256 elseif line =~ '^\s*end\>'
|
|
257 " General case for end
|
36
|
258 let ind = s:MainBlockIndent( ind, lnum, '\(if\|while\|for\|loop\|accept\|begin\|record\|case\|exception\|package\)\>', '' )
|
7
|
259 elseif line =~ '^\s*exception\>'
|
|
260 let ind = s:MainBlockIndent( ind, lnum, 'begin\>', '' )
|
|
261 elseif line =~ '^\s*then\>'
|
|
262 let ind = s:MainBlockIndent( ind, lnum, 'if\>', '' )
|
|
263 endif
|
|
264
|
|
265 return ind
|
|
266 endfunction
|
|
267
|
|
268 " vim: set sw=3 sts=3 :
|