blob: f2fc1ab4b0dc4a1f4825ae4416717af94d9f3f20 [file] [log] [blame]
Bram Moolenaar9964e462007-05-05 17:54:07 +00001"------------------------------------------------------------------------------
2" Description: Vim Ada indent file
3" Language: Ada (2005)
4" $Id$
5" Copyright: Copyright (C) 2006 Martin Krischik
6" Maintainer: Martin Krischik
7" Neil Bird <neil@fnxweb.com>
8" $Author$
9" $Date$
10" Version: 4.2
11" $Revision$
12" $HeadURL: https://svn.sourceforge.net/svnroot/gnuada/trunk/tools/vim/indent/ada.vim $
13" History: 24.05.2006 MK Unified Headers
14" 16.07.2006 MK Ada-Mode as vim-ball
15" 15.10.2006 MK Bram's suggestion for runtime integration
16" 05.11.2006 MK Bram suggested to save on spaces
17" Help Page: ft-vim-indent
18"------------------------------------------------------------------------------
Bram Moolenaar071d4272004-06-13 20:20:40 +000019" ToDo:
20" Verify handling of multi-line exprs. and recovery upon the final ';'.
21" Correctly find comments given '"' and "" ==> " syntax.
22" Combine the two large block-indent functions into one?
Bram Moolenaar9964e462007-05-05 17:54:07 +000023"------------------------------------------------------------------------------
Bram Moolenaar071d4272004-06-13 20:20:40 +000024
25" Only load this indent file when no other was loaded.
Bram Moolenaar9964e462007-05-05 17:54:07 +000026if exists("b:did_indent") || version < 700
Bram Moolenaar071d4272004-06-13 20:20:40 +000027 finish
28endif
Bram Moolenaar9964e462007-05-05 17:54:07 +000029
Bram Moolenaar071d4272004-06-13 20:20:40 +000030let b:did_indent = 1
31
32setlocal indentexpr=GetAdaIndent()
33setlocal indentkeys-=0{,0}
34setlocal indentkeys+=0=~then,0=~end,0=~elsif,0=~when,0=~exception,0=~begin,0=~is,0=~record
35
36" Only define the functions once.
37if exists("*GetAdaIndent")
38 finish
39endif
40
Bram Moolenaar9964e462007-05-05 17:54:07 +000041if exists("g:ada_with_gnat_project_files")
42 let s:AdaBlockStart = '^\s*\(if\>\|while\>\|else\>\|elsif\>\|loop\>\|for\>.*\<\(loop\|use\)\>\|declare\>\|begin\>\|type\>.*\<is\>[^;]*$\|\(type\>.*\)\=\<record\>\|procedure\>\|function\>\|accept\>\|do\>\|task\>\|package\>\|project\>\|then\>\|when\>\|is\>\)'
43else
44 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\>\)'
45endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000046
Bram Moolenaar9964e462007-05-05 17:54:07 +000047" Section: s:MainBlockIndent {{{1
48"
Bram Moolenaar293ee4d2004-12-09 21:34:53 +000049" Try to find indent of the block we're in
Bram Moolenaar071d4272004-06-13 20:20:40 +000050" prev_indent = the previous line's indent
51" prev_lnum = previous line (to start looking on)
52" blockstart = expr. that indicates a possible start of this block
53" stop_at = if non-null, if a matching line is found, gives up!
54" No recursive previous block analysis: simply look for a valid line
55" with a lesser or equal indent than we currently (on prev_lnum) have.
56" This shouldn't work as well as it appears to with lines that are currently
57" nowhere near the correct indent (e.g., start of line)!
58" Seems to work OK as it 'starts' with the indent of the /previous/ line.
Bram Moolenaar9964e462007-05-05 17:54:07 +000059function s:MainBlockIndent (prev_indent, prev_lnum, blockstart, stop_at)
Bram Moolenaar071d4272004-06-13 20:20:40 +000060 let lnum = a:prev_lnum
Bram Moolenaar9964e462007-05-05 17:54:07 +000061 let line = substitute( getline(lnum), ada#Comment, '', '' )
Bram Moolenaar071d4272004-06-13 20:20:40 +000062 while lnum > 1
63 if a:stop_at != '' && line =~ '^\s*' . a:stop_at && indent(lnum) < a:prev_indent
Bram Moolenaarc9b4b052006-04-30 18:54:39 +000064 return a:prev_indent
Bram Moolenaar071d4272004-06-13 20:20:40 +000065 elseif line =~ '^\s*' . a:blockstart
Bram Moolenaarc9b4b052006-04-30 18:54:39 +000066 let ind = indent(lnum)
67 if ind < a:prev_indent
68 return ind
69 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000070 endif
71
72 let lnum = prevnonblank(lnum - 1)
73 " Get previous non-blank/non-comment-only line
74 while 1
Bram Moolenaar9964e462007-05-05 17:54:07 +000075 let line = substitute( getline(lnum), ada#Comment, '', '' )
Bram Moolenaarc9b4b052006-04-30 18:54:39 +000076 if line !~ '^\s*$' && line !~ '^\s*#'
77 break
78 endif
79 let lnum = prevnonblank(lnum - 1)
80 if lnum <= 0
81 return a:prev_indent
82 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000083 endwhile
84 endwhile
85 " Fallback - just move back one
86 return a:prev_indent - &sw
Bram Moolenaar9964e462007-05-05 17:54:07 +000087endfunction MainBlockIndent
Bram Moolenaar071d4272004-06-13 20:20:40 +000088
Bram Moolenaar9964e462007-05-05 17:54:07 +000089" Section: s:EndBlockIndent {{{1
90"
Bram Moolenaar071d4272004-06-13 20:20:40 +000091" Try to find indent of the block we're in (and about to complete),
92" including handling of nested blocks. Works on the 'end' of a block.
93" prev_indent = the previous line's indent
94" prev_lnum = previous line (to start looking on)
95" blockstart = expr. that indicates a possible start of this block
96" blockend = expr. that indicates a possible end of this block
97function s:EndBlockIndent( prev_indent, prev_lnum, blockstart, blockend )
98 let lnum = a:prev_lnum
99 let line = getline(lnum)
100 let ends = 0
101 while lnum > 1
102 if getline(lnum) =~ '^\s*' . a:blockstart
103 let ind = indent(lnum)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000104 if ends <= 0
105 if ind < a:prev_indent
Bram Moolenaar071d4272004-06-13 20:20:40 +0000106 return ind
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000107 endif
108 else
109 let ends = ends - 1
Bram Moolenaar071d4272004-06-13 20:20:40 +0000110 endif
111 elseif getline(lnum) =~ '^\s*' . a:blockend
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000112 let ends = ends + 1
Bram Moolenaar071d4272004-06-13 20:20:40 +0000113 endif
114
115 let lnum = prevnonblank(lnum - 1)
116 " Get previous non-blank/non-comment-only line
117 while 1
118 let line = getline(lnum)
Bram Moolenaar9964e462007-05-05 17:54:07 +0000119 let line = substitute( line, ada#Comment, '', '' )
Bram Moolenaar071d4272004-06-13 20:20:40 +0000120 if line !~ '^\s*$'
121 break
122 endif
123 let lnum = prevnonblank(lnum - 1)
124 if lnum <= 0
125 return a:prev_indent
126 endif
127 endwhile
128 endwhile
129 " Fallback - just move back one
130 return a:prev_indent - &sw
Bram Moolenaar9964e462007-05-05 17:54:07 +0000131endfunction EndBlockIndent
Bram Moolenaar071d4272004-06-13 20:20:40 +0000132
Bram Moolenaar9964e462007-05-05 17:54:07 +0000133" Section: s:StatementIndent {{{1
134"
Bram Moolenaar293ee4d2004-12-09 21:34:53 +0000135" Return indent of previous statement-start
Bram Moolenaar071d4272004-06-13 20:20:40 +0000136" (after we've indented due to multi-line statements).
137" This time, we start searching on the line *before* the one given (which is
138" the end of a statement - we want the previous beginning).
139function s:StatementIndent( current_indent, prev_lnum )
140 let lnum = a:prev_lnum
141 while lnum > 0
142 let prev_lnum = lnum
143 let lnum = prevnonblank(lnum - 1)
144 " Get previous non-blank/non-comment-only line
145 while 1
Bram Moolenaar9964e462007-05-05 17:54:07 +0000146 let line = substitute( getline(lnum), ada#Comment, '', '' )
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000147 if line !~ '^\s*$' && line !~ '^\s*#'
148 break
149 endif
150 let lnum = prevnonblank(lnum - 1)
151 if lnum <= 0
152 return a:current_indent
153 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000154 endwhile
155 " Leave indent alone if our ';' line is part of a ';'-delineated
156 " aggregate (e.g., procedure args.) or first line after a block start.
157 if line =~ s:AdaBlockStart || line =~ '(\s*$'
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000158 return a:current_indent
Bram Moolenaar071d4272004-06-13 20:20:40 +0000159 endif
160 if line !~ '[.=(]\s*$'
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000161 let ind = indent(prev_lnum)
162 if ind < a:current_indent
163 return ind
164 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000165 endif
166 endwhile
167 " Fallback - just use current one
168 return a:current_indent
Bram Moolenaar9964e462007-05-05 17:54:07 +0000169endfunction StatementIndent
Bram Moolenaar071d4272004-06-13 20:20:40 +0000170
171
Bram Moolenaar9964e462007-05-05 17:54:07 +0000172" Section: GetAdaIndent {{{1
173"
Bram Moolenaar071d4272004-06-13 20:20:40 +0000174" Find correct indent of a new line based upon what went before
Bram Moolenaar9964e462007-05-05 17:54:07 +0000175"
Bram Moolenaar071d4272004-06-13 20:20:40 +0000176function GetAdaIndent()
177 " Find a non-blank line above the current line.
178 let lnum = prevnonblank(v:lnum - 1)
179 let ind = indent(lnum)
180 let package_line = 0
181
182 " Get previous non-blank/non-comment-only/non-cpp line
183 while 1
Bram Moolenaar9964e462007-05-05 17:54:07 +0000184 let line = substitute( getline(lnum), g:ada#Comment, '', '' )
Bram Moolenaar071d4272004-06-13 20:20:40 +0000185 if line !~ '^\s*$' && line !~ '^\s*#'
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000186 break
Bram Moolenaar071d4272004-06-13 20:20:40 +0000187 endif
188 let lnum = prevnonblank(lnum - 1)
189 if lnum <= 0
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000190 return ind
Bram Moolenaar071d4272004-06-13 20:20:40 +0000191 endif
192 endwhile
193
194 " Get default indent (from prev. line)
195 let ind = indent(lnum)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +0000196 let initind = ind
Bram Moolenaar071d4272004-06-13 20:20:40 +0000197
198 " Now check what's on the previous line
199 if line =~ s:AdaBlockStart || line =~ '(\s*$'
200 " Check for false matches to AdaBlockStart
201 let false_match = 0
202 if line =~ '^\s*\(procedure\|function\|package\)\>.*\<is\s*new\>'
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000203 " Generic instantiation
204 let false_match = 1
Bram Moolenaar071d4272004-06-13 20:20:40 +0000205 elseif line =~ ')\s*;\s*$' || line =~ '^\([^(]*([^)]*)\)*[^(]*;\s*$'
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000206 " forward declaration
207 let false_match = 1
Bram Moolenaar071d4272004-06-13 20:20:40 +0000208 endif
209 " Move indent in
210 if ! false_match
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000211 let ind = ind + &sw
Bram Moolenaar071d4272004-06-13 20:20:40 +0000212 endif
213 elseif line =~ '^\s*\(case\|exception\)\>'
214 " Move indent in twice (next 'when' will move back)
215 let ind = ind + 2 * &sw
216 elseif line =~ '^\s*end\s*record\>'
217 " Move indent back to tallying 'type' preceeding the 'record'.
218 " Allow indent to be equal to 'end record's.
219 let ind = s:MainBlockIndent( ind+&sw, lnum, 'type\>', '' )
220 elseif line =~ '\(^\s*new\>.*\)\@<!)\s*[;,]\s*$'
221 " Revert to indent of line that started this parenthesis pair
222 exe lnum
223 exe 'normal! $F)%'
224 if getline('.') =~ '^\s*('
Bram Moolenaar9964e462007-05-05 17:54:07 +0000225 " Dire layout - use previous indent (could check for ada#Comment here)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000226 let ind = indent( prevnonblank( line('.')-1 ) )
Bram Moolenaar071d4272004-06-13 20:20:40 +0000227 else
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000228 let ind = indent('.')
Bram Moolenaar071d4272004-06-13 20:20:40 +0000229 endif
230 exe v:lnum
231 elseif line =~ '[.=(]\s*$'
232 " A statement continuation - move in one
233 let ind = ind + &sw
234 elseif line =~ '^\s*new\>'
235 " Multiple line generic instantiation ('package blah is\nnew thingy')
236 let ind = s:StatementIndent( ind - &sw, lnum )
237 elseif line =~ ';\s*$'
Bram Moolenaar293ee4d2004-12-09 21:34:53 +0000238 " Statement end (but not 'end' ) - try to find current statement-start indent
Bram Moolenaar071d4272004-06-13 20:20:40 +0000239 let ind = s:StatementIndent( ind, lnum )
240 endif
241
242 " Check for potential argument list on next line
243 let continuation = (line =~ '[A-Za-z0-9_]\s*$')
244
245
246 " Check current line; search for simplistic matching start-of-block
247 let line = getline(v:lnum)
248 if line =~ '^\s*#'
249 " Start of line for ada-pp
250 let ind = 0
251 elseif continuation && line =~ '^\s*('
Bram Moolenaar293ee4d2004-12-09 21:34:53 +0000252 " Don't do this if we've already indented due to the previous line
253 if ind == initind
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000254 let ind = ind + &sw
Bram Moolenaar293ee4d2004-12-09 21:34:53 +0000255 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000256 elseif line =~ '^\s*\(begin\|is\)\>'
257 let ind = s:MainBlockIndent( ind, lnum, '\(procedure\|function\|declare\|package\|task\)\>', 'begin\>' )
258 elseif line =~ '^\s*record\>'
Bram Moolenaar293ee4d2004-12-09 21:34:53 +0000259 let ind = s:MainBlockIndent( ind, lnum, 'type\>\|for\>.*\<use\>', '' ) + &sw
Bram Moolenaar071d4272004-06-13 20:20:40 +0000260 elseif line =~ '^\s*\(else\|elsif\)\>'
261 let ind = s:MainBlockIndent( ind, lnum, 'if\>', '' )
262 elseif line =~ '^\s*when\>'
263 " Align 'when' one /in/ from matching block start
264 let ind = s:MainBlockIndent( ind, lnum, '\(case\|exception\)\>', '' ) + &sw
265 elseif line =~ '^\s*end\>\s*\<if\>'
266 " End of if statements
267 let ind = s:EndBlockIndent( ind, lnum, 'if\>', 'end\>\s*\<if\>' )
268 elseif line =~ '^\s*end\>\s*\<loop\>'
269 " End of loops
270 let ind = s:EndBlockIndent( ind, lnum, '\(\(while\|for\)\>.*\)\?\<loop\>', 'end\>\s*\<loop\>' )
271 elseif line =~ '^\s*end\>\s*\<record\>'
272 " End of records
273 let ind = s:EndBlockIndent( ind, lnum, '\(type\>.*\)\=\<record\>', 'end\>\s*\<record\>' )
274 elseif line =~ '^\s*end\>\s*\<procedure\>'
275 " End of procedures
276 let ind = s:EndBlockIndent( ind, lnum, 'procedure\>.*\<is\>', 'end\>\s*\<procedure\>' )
277 elseif line =~ '^\s*end\>\s*\<case\>'
278 " End of case statement
279 let ind = s:EndBlockIndent( ind, lnum, 'case\>.*\<is\>', 'end\>\s*\<case\>' )
280 elseif line =~ '^\s*end\>'
281 " General case for end
Bram Moolenaar293ee4d2004-12-09 21:34:53 +0000282 let ind = s:MainBlockIndent( ind, lnum, '\(if\|while\|for\|loop\|accept\|begin\|record\|case\|exception\|package\)\>', '' )
Bram Moolenaar071d4272004-06-13 20:20:40 +0000283 elseif line =~ '^\s*exception\>'
284 let ind = s:MainBlockIndent( ind, lnum, 'begin\>', '' )
285 elseif line =~ '^\s*then\>'
286 let ind = s:MainBlockIndent( ind, lnum, 'if\>', '' )
287 endif
288
289 return ind
Bram Moolenaar9964e462007-05-05 17:54:07 +0000290endfunction GetAdaIndent
Bram Moolenaar071d4272004-06-13 20:20:40 +0000291
Bram Moolenaar9964e462007-05-05 17:54:07 +0000292finish " 1}}}
293
294"------------------------------------------------------------------------------
295" Copyright (C) 2006 Martin Krischik
296"
297" Vim is Charityware - see ":help license" or uganda.txt for licence details.
298"------------------------------------------------------------------------------
299" vim: textwidth=78 wrap tabstop=8 shiftwidth=3 softtabstop=3 noexpandtab
300" vim: foldmethod=marker