blob: a9b461ccc5d9e1ae074164a50185312dda415964 [file] [log] [blame]
Bram Moolenaar9964e462007-05-05 17:54:07 +00001"------------------------------------------------------------------------------
2" Description: Vim Ada indent file
3" Language: Ada (2005)
Bram Moolenaar5c736222010-01-06 20:54:52 +01004" $Id: ada.vim 887 2008-07-08 14:29:01Z krischik $
Bram Moolenaar9964e462007-05-05 17:54:07 +00005" Copyright: Copyright (C) 2006 Martin Krischik
Bram Moolenaarc236c162008-07-13 17:41:49 +00006" Maintainer: Martin Krischik <krischik@users.sourceforge.net>
Bram Moolenaar9964e462007-05-05 17:54:07 +00007" Neil Bird <neil@fnxweb.com>
Bram Moolenaarc236c162008-07-13 17:41:49 +00008" Ned Okie <nokie@radford.edu>
Bram Moolenaar5c736222010-01-06 20:54:52 +01009" $Author: krischik $
10" $Date: 2008-07-08 16:29:01 +0200 (Di, 08 Jul 2008) $
Bram Moolenaarc236c162008-07-13 17:41:49 +000011" Version: 4.6
Bram Moolenaar5c736222010-01-06 20:54:52 +010012" $Revision: 887 $
Bram Moolenaarc236c162008-07-13 17:41:49 +000013" $HeadURL: https://gnuada.svn.sourceforge.net/svnroot/gnuada/trunk/tools/vim/indent/ada.vim $
Bram Moolenaar9964e462007-05-05 17:54:07 +000014" History: 24.05.2006 MK Unified Headers
15" 16.07.2006 MK Ada-Mode as vim-ball
16" 15.10.2006 MK Bram's suggestion for runtime integration
17" 05.11.2006 MK Bram suggested to save on spaces
Bram Moolenaarc236c162008-07-13 17:41:49 +000018" 19.09.2007 NO g: missing before ada#Comment
Bram Moolenaar9964e462007-05-05 17:54:07 +000019" Help Page: ft-vim-indent
20"------------------------------------------------------------------------------
Bram Moolenaar071d4272004-06-13 20:20:40 +000021" ToDo:
22" Verify handling of multi-line exprs. and recovery upon the final ';'.
23" Correctly find comments given '"' and "" ==> " syntax.
24" Combine the two large block-indent functions into one?
Bram Moolenaar9964e462007-05-05 17:54:07 +000025"------------------------------------------------------------------------------
Bram Moolenaar071d4272004-06-13 20:20:40 +000026
27" Only load this indent file when no other was loaded.
Bram Moolenaar9964e462007-05-05 17:54:07 +000028if exists("b:did_indent") || version < 700
Bram Moolenaar071d4272004-06-13 20:20:40 +000029 finish
30endif
Bram Moolenaar9964e462007-05-05 17:54:07 +000031
Bram Moolenaarc236c162008-07-13 17:41:49 +000032let b:did_indent = 45
Bram Moolenaar071d4272004-06-13 20:20:40 +000033
34setlocal indentexpr=GetAdaIndent()
35setlocal indentkeys-=0{,0}
36setlocal indentkeys+=0=~then,0=~end,0=~elsif,0=~when,0=~exception,0=~begin,0=~is,0=~record
37
38" Only define the functions once.
39if exists("*GetAdaIndent")
40 finish
41endif
42
Bram Moolenaar9964e462007-05-05 17:54:07 +000043if exists("g:ada_with_gnat_project_files")
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\>\|project\>\|then\>\|when\>\|is\>\)'
45else
46 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\>\)'
47endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000048
Bram Moolenaar9964e462007-05-05 17:54:07 +000049" Section: s:MainBlockIndent {{{1
50"
Bram Moolenaar293ee4d2004-12-09 21:34:53 +000051" Try to find indent of the block we're in
Bram Moolenaar071d4272004-06-13 20:20:40 +000052" prev_indent = the previous line's indent
53" prev_lnum = previous line (to start looking on)
54" blockstart = expr. that indicates a possible start of this block
55" stop_at = if non-null, if a matching line is found, gives up!
56" No recursive previous block analysis: simply look for a valid line
57" with a lesser or equal indent than we currently (on prev_lnum) have.
58" This shouldn't work as well as it appears to with lines that are currently
59" nowhere near the correct indent (e.g., start of line)!
60" Seems to work OK as it 'starts' with the indent of the /previous/ line.
Bram Moolenaar9964e462007-05-05 17:54:07 +000061function s:MainBlockIndent (prev_indent, prev_lnum, blockstart, stop_at)
Bram Moolenaar071d4272004-06-13 20:20:40 +000062 let lnum = a:prev_lnum
Bram Moolenaarc236c162008-07-13 17:41:49 +000063 let line = substitute( getline(lnum), g:ada#Comment, '', '' )
Bram Moolenaar071d4272004-06-13 20:20:40 +000064 while lnum > 1
65 if a:stop_at != '' && line =~ '^\s*' . a:stop_at && indent(lnum) < a:prev_indent
Bram Moolenaarc9b4b052006-04-30 18:54:39 +000066 return a:prev_indent
Bram Moolenaar071d4272004-06-13 20:20:40 +000067 elseif line =~ '^\s*' . a:blockstart
Bram Moolenaarc9b4b052006-04-30 18:54:39 +000068 let ind = indent(lnum)
69 if ind < a:prev_indent
70 return ind
71 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000072 endif
73
74 let lnum = prevnonblank(lnum - 1)
75 " Get previous non-blank/non-comment-only line
76 while 1
Bram Moolenaarc236c162008-07-13 17:41:49 +000077 let line = substitute( getline(lnum), g:ada#Comment, '', '' )
Bram Moolenaarc9b4b052006-04-30 18:54:39 +000078 if line !~ '^\s*$' && line !~ '^\s*#'
79 break
80 endif
81 let lnum = prevnonblank(lnum - 1)
82 if lnum <= 0
83 return a:prev_indent
84 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000085 endwhile
86 endwhile
87 " Fallback - just move back one
88 return a:prev_indent - &sw
Bram Moolenaar9964e462007-05-05 17:54:07 +000089endfunction MainBlockIndent
Bram Moolenaar071d4272004-06-13 20:20:40 +000090
Bram Moolenaar9964e462007-05-05 17:54:07 +000091" Section: s:EndBlockIndent {{{1
92"
Bram Moolenaar071d4272004-06-13 20:20:40 +000093" Try to find indent of the block we're in (and about to complete),
94" including handling of nested blocks. Works on the 'end' of a block.
95" prev_indent = the previous line's indent
96" prev_lnum = previous line (to start looking on)
97" blockstart = expr. that indicates a possible start of this block
98" blockend = expr. that indicates a possible end of this block
99function s:EndBlockIndent( prev_indent, prev_lnum, blockstart, blockend )
100 let lnum = a:prev_lnum
101 let line = getline(lnum)
102 let ends = 0
103 while lnum > 1
104 if getline(lnum) =~ '^\s*' . a:blockstart
105 let ind = indent(lnum)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000106 if ends <= 0
107 if ind < a:prev_indent
Bram Moolenaar071d4272004-06-13 20:20:40 +0000108 return ind
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000109 endif
110 else
111 let ends = ends - 1
Bram Moolenaar071d4272004-06-13 20:20:40 +0000112 endif
113 elseif getline(lnum) =~ '^\s*' . a:blockend
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000114 let ends = ends + 1
Bram Moolenaar071d4272004-06-13 20:20:40 +0000115 endif
116
117 let lnum = prevnonblank(lnum - 1)
118 " Get previous non-blank/non-comment-only line
119 while 1
120 let line = getline(lnum)
Bram Moolenaarc236c162008-07-13 17:41:49 +0000121 let line = substitute( line, g:ada#Comment, '', '' )
Bram Moolenaar071d4272004-06-13 20:20:40 +0000122 if line !~ '^\s*$'
123 break
124 endif
125 let lnum = prevnonblank(lnum - 1)
126 if lnum <= 0
127 return a:prev_indent
128 endif
129 endwhile
130 endwhile
131 " Fallback - just move back one
132 return a:prev_indent - &sw
Bram Moolenaar9964e462007-05-05 17:54:07 +0000133endfunction EndBlockIndent
Bram Moolenaar071d4272004-06-13 20:20:40 +0000134
Bram Moolenaar9964e462007-05-05 17:54:07 +0000135" Section: s:StatementIndent {{{1
136"
Bram Moolenaar293ee4d2004-12-09 21:34:53 +0000137" Return indent of previous statement-start
Bram Moolenaar071d4272004-06-13 20:20:40 +0000138" (after we've indented due to multi-line statements).
139" This time, we start searching on the line *before* the one given (which is
140" the end of a statement - we want the previous beginning).
141function s:StatementIndent( current_indent, prev_lnum )
142 let lnum = a:prev_lnum
143 while lnum > 0
144 let prev_lnum = lnum
145 let lnum = prevnonblank(lnum - 1)
146 " Get previous non-blank/non-comment-only line
147 while 1
Bram Moolenaarc236c162008-07-13 17:41:49 +0000148 let line = substitute( getline(lnum), g:ada#Comment, '', '' )
149
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000150 if line !~ '^\s*$' && line !~ '^\s*#'
151 break
152 endif
153 let lnum = prevnonblank(lnum - 1)
154 if lnum <= 0
155 return a:current_indent
156 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000157 endwhile
158 " Leave indent alone if our ';' line is part of a ';'-delineated
159 " aggregate (e.g., procedure args.) or first line after a block start.
160 if line =~ s:AdaBlockStart || line =~ '(\s*$'
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000161 return a:current_indent
Bram Moolenaar071d4272004-06-13 20:20:40 +0000162 endif
163 if line !~ '[.=(]\s*$'
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000164 let ind = indent(prev_lnum)
165 if ind < a:current_indent
166 return ind
167 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000168 endif
169 endwhile
170 " Fallback - just use current one
171 return a:current_indent
Bram Moolenaar9964e462007-05-05 17:54:07 +0000172endfunction StatementIndent
Bram Moolenaar071d4272004-06-13 20:20:40 +0000173
174
Bram Moolenaar9964e462007-05-05 17:54:07 +0000175" Section: GetAdaIndent {{{1
176"
Bram Moolenaar071d4272004-06-13 20:20:40 +0000177" Find correct indent of a new line based upon what went before
Bram Moolenaar9964e462007-05-05 17:54:07 +0000178"
Bram Moolenaar071d4272004-06-13 20:20:40 +0000179function GetAdaIndent()
180 " Find a non-blank line above the current line.
181 let lnum = prevnonblank(v:lnum - 1)
182 let ind = indent(lnum)
183 let package_line = 0
184
185 " Get previous non-blank/non-comment-only/non-cpp line
186 while 1
Bram Moolenaar9964e462007-05-05 17:54:07 +0000187 let line = substitute( getline(lnum), g:ada#Comment, '', '' )
Bram Moolenaar071d4272004-06-13 20:20:40 +0000188 if line !~ '^\s*$' && line !~ '^\s*#'
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000189 break
Bram Moolenaar071d4272004-06-13 20:20:40 +0000190 endif
191 let lnum = prevnonblank(lnum - 1)
192 if lnum <= 0
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000193 return ind
Bram Moolenaar071d4272004-06-13 20:20:40 +0000194 endif
195 endwhile
196
197 " Get default indent (from prev. line)
198 let ind = indent(lnum)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +0000199 let initind = ind
Bram Moolenaar071d4272004-06-13 20:20:40 +0000200
201 " Now check what's on the previous line
202 if line =~ s:AdaBlockStart || line =~ '(\s*$'
203 " Check for false matches to AdaBlockStart
204 let false_match = 0
205 if line =~ '^\s*\(procedure\|function\|package\)\>.*\<is\s*new\>'
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000206 " Generic instantiation
207 let false_match = 1
Bram Moolenaar071d4272004-06-13 20:20:40 +0000208 elseif line =~ ')\s*;\s*$' || line =~ '^\([^(]*([^)]*)\)*[^(]*;\s*$'
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000209 " forward declaration
210 let false_match = 1
Bram Moolenaar071d4272004-06-13 20:20:40 +0000211 endif
212 " Move indent in
213 if ! false_match
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000214 let ind = ind + &sw
Bram Moolenaar071d4272004-06-13 20:20:40 +0000215 endif
216 elseif line =~ '^\s*\(case\|exception\)\>'
217 " Move indent in twice (next 'when' will move back)
218 let ind = ind + 2 * &sw
219 elseif line =~ '^\s*end\s*record\>'
220 " Move indent back to tallying 'type' preceeding the 'record'.
221 " Allow indent to be equal to 'end record's.
222 let ind = s:MainBlockIndent( ind+&sw, lnum, 'type\>', '' )
223 elseif line =~ '\(^\s*new\>.*\)\@<!)\s*[;,]\s*$'
224 " Revert to indent of line that started this parenthesis pair
225 exe lnum
226 exe 'normal! $F)%'
227 if getline('.') =~ '^\s*('
Bram Moolenaarc236c162008-07-13 17:41:49 +0000228 " Dire layout - use previous indent (could check for g:ada#Comment here)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000229 let ind = indent( prevnonblank( line('.')-1 ) )
Bram Moolenaar071d4272004-06-13 20:20:40 +0000230 else
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000231 let ind = indent('.')
Bram Moolenaar071d4272004-06-13 20:20:40 +0000232 endif
233 exe v:lnum
234 elseif line =~ '[.=(]\s*$'
235 " A statement continuation - move in one
236 let ind = ind + &sw
237 elseif line =~ '^\s*new\>'
238 " Multiple line generic instantiation ('package blah is\nnew thingy')
239 let ind = s:StatementIndent( ind - &sw, lnum )
240 elseif line =~ ';\s*$'
Bram Moolenaar293ee4d2004-12-09 21:34:53 +0000241 " Statement end (but not 'end' ) - try to find current statement-start indent
Bram Moolenaar071d4272004-06-13 20:20:40 +0000242 let ind = s:StatementIndent( ind, lnum )
243 endif
244
245 " Check for potential argument list on next line
246 let continuation = (line =~ '[A-Za-z0-9_]\s*$')
247
248
249 " Check current line; search for simplistic matching start-of-block
250 let line = getline(v:lnum)
251 if line =~ '^\s*#'
252 " Start of line for ada-pp
253 let ind = 0
254 elseif continuation && line =~ '^\s*('
Bram Moolenaar293ee4d2004-12-09 21:34:53 +0000255 " Don't do this if we've already indented due to the previous line
256 if ind == initind
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000257 let ind = ind + &sw
Bram Moolenaar293ee4d2004-12-09 21:34:53 +0000258 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000259 elseif line =~ '^\s*\(begin\|is\)\>'
260 let ind = s:MainBlockIndent( ind, lnum, '\(procedure\|function\|declare\|package\|task\)\>', 'begin\>' )
261 elseif line =~ '^\s*record\>'
Bram Moolenaar293ee4d2004-12-09 21:34:53 +0000262 let ind = s:MainBlockIndent( ind, lnum, 'type\>\|for\>.*\<use\>', '' ) + &sw
Bram Moolenaar071d4272004-06-13 20:20:40 +0000263 elseif line =~ '^\s*\(else\|elsif\)\>'
264 let ind = s:MainBlockIndent( ind, lnum, 'if\>', '' )
265 elseif line =~ '^\s*when\>'
266 " Align 'when' one /in/ from matching block start
267 let ind = s:MainBlockIndent( ind, lnum, '\(case\|exception\)\>', '' ) + &sw
268 elseif line =~ '^\s*end\>\s*\<if\>'
269 " End of if statements
270 let ind = s:EndBlockIndent( ind, lnum, 'if\>', 'end\>\s*\<if\>' )
271 elseif line =~ '^\s*end\>\s*\<loop\>'
272 " End of loops
273 let ind = s:EndBlockIndent( ind, lnum, '\(\(while\|for\)\>.*\)\?\<loop\>', 'end\>\s*\<loop\>' )
274 elseif line =~ '^\s*end\>\s*\<record\>'
275 " End of records
276 let ind = s:EndBlockIndent( ind, lnum, '\(type\>.*\)\=\<record\>', 'end\>\s*\<record\>' )
277 elseif line =~ '^\s*end\>\s*\<procedure\>'
278 " End of procedures
279 let ind = s:EndBlockIndent( ind, lnum, 'procedure\>.*\<is\>', 'end\>\s*\<procedure\>' )
280 elseif line =~ '^\s*end\>\s*\<case\>'
281 " End of case statement
282 let ind = s:EndBlockIndent( ind, lnum, 'case\>.*\<is\>', 'end\>\s*\<case\>' )
283 elseif line =~ '^\s*end\>'
284 " General case for end
Bram Moolenaar293ee4d2004-12-09 21:34:53 +0000285 let ind = s:MainBlockIndent( ind, lnum, '\(if\|while\|for\|loop\|accept\|begin\|record\|case\|exception\|package\)\>', '' )
Bram Moolenaar071d4272004-06-13 20:20:40 +0000286 elseif line =~ '^\s*exception\>'
287 let ind = s:MainBlockIndent( ind, lnum, 'begin\>', '' )
288 elseif line =~ '^\s*then\>'
289 let ind = s:MainBlockIndent( ind, lnum, 'if\>', '' )
290 endif
291
292 return ind
Bram Moolenaar9964e462007-05-05 17:54:07 +0000293endfunction GetAdaIndent
Bram Moolenaar071d4272004-06-13 20:20:40 +0000294
Bram Moolenaar9964e462007-05-05 17:54:07 +0000295finish " 1}}}
296
297"------------------------------------------------------------------------------
298" Copyright (C) 2006 Martin Krischik
299"
300" Vim is Charityware - see ":help license" or uganda.txt for licence details.
301"------------------------------------------------------------------------------
302" vim: textwidth=78 wrap tabstop=8 shiftwidth=3 softtabstop=3 noexpandtab
303" vim: foldmethod=marker