Mercurial > vim
comparison runtime/indent/awk.vim @ 7:3fc0f57ecb91 v7.0001
updated for version 7.0001
author | vimboss |
---|---|
date | Sun, 13 Jun 2004 20:20:40 +0000 |
parents | |
children | 3502a7f991fc |
comparison
equal
deleted
inserted
replaced
6:c2daee826b8f | 7:3fc0f57ecb91 |
---|---|
1 " vim: set sw=3 sts=3: | |
2 | |
3 " Awk indent script. It can handle multi-line statements and expressions. | |
4 " It works up to the point where the distinction between correct/incorrect | |
5 " and personal taste gets fuzzy. Drop me an e-mail for bug reports and | |
6 " reasonable style suggestions. | |
7 " | |
8 " Bugs: | |
9 " ===== | |
10 " - Some syntax errors may cause erratic indentation. | |
11 " - Same for very unusual but syntacticly correct use of { } | |
12 " - In some cases it's confused by the use of ( and { in strings constants | |
13 " - This version likes the closing brace of a multiline pattern-action be on | |
14 " character position 1 before the following pattern-action combination is | |
15 " formatted | |
16 | |
17 " Author: | |
18 " ======= | |
19 " Erik Janssen, ejanssen@itmatters.nl | |
20 " | |
21 " History: | |
22 " ======== | |
23 " 26-04-2002 Got initial version working reasonably well | |
24 " 29-04-2002 Fixed problems in function headers and max line width | |
25 " Added support for two-line if's without curly braces | |
26 | |
27 " Only load this indent file when no other was loaded. | |
28 if exists("b:did_indent") | |
29 finish | |
30 endif | |
31 | |
32 let b:did_indent = 1 | |
33 | |
34 setlocal indentexpr=GetAwkIndent() | |
35 " Mmm, copied from the tcl indent program. Is this okay? | |
36 setlocal indentkeys-=:,0# | |
37 | |
38 " Only define the function once. | |
39 if exists("*GetAwkIndent") | |
40 finish | |
41 endif | |
42 | |
43 " This function contains a lot of exit points. It checks for simple cases | |
44 " first to get out of the function as soon as possible, thereby reducing the | |
45 " number of possibilities later on in the difficult parts | |
46 | |
47 function! GetAwkIndent() | |
48 | |
49 " Find previous line and get it's indentation | |
50 let prev_lineno = s:Get_prev_line( v:lnum ) | |
51 if prev_lineno == 0 | |
52 return 0 | |
53 endif | |
54 let prev_data = getline( prev_lineno ) | |
55 let ind = indent( prev_lineno ) | |
56 | |
57 " Increase indent if the previous line contains an opening brace. Search | |
58 " for this brace the hard way to prevent errors if the previous line is a | |
59 " 'pattern { action }' (simple check match on /{/ increases the indent then) | |
60 | |
61 if s:Get_brace_balance( prev_data, '{', '}' ) > 0 | |
62 return ind + &sw | |
63 endif | |
64 | |
65 let brace_balance = s:Get_brace_balance( prev_data, '(', ')' ) | |
66 | |
67 " If prev line has positive brace_balance and starts with a word (keyword | |
68 " or function name), align the current line on the first '(' of the prev | |
69 " line | |
70 | |
71 if brace_balance > 0 && s:Starts_with_word( prev_data ) | |
72 return s:Safe_indent( ind, s:First_word_len(prev_data), getline(v:lnum)) | |
73 endif | |
74 | |
75 " If this line starts with an open brace bail out now before the line | |
76 " continuation checks. | |
77 | |
78 if getline( v:lnum ) =~ '^\s*{' | |
79 return ind | |
80 endif | |
81 | |
82 " If prev line seems to be part of multiline statement: | |
83 " 1. Prev line is first line of a multiline statement | |
84 " -> attempt to indent on first ' ' or '(' of prev line, just like we | |
85 " indented the positive brace balance case above | |
86 " 2. Prev line is not first line of a multiline statement | |
87 " -> copy indent of prev line | |
88 | |
89 let continue_mode = s:Seems_continuing( prev_data ) | |
90 if continue_mode > 0 | |
91 if s:Seems_continuing( getline(s:Get_prev_line( prev_lineno )) ) | |
92 " Case 2 | |
93 return ind | |
94 else | |
95 " Case 1 | |
96 if continue_mode == 1 | |
97 " Need continuation due to comma, backslash, etc | |
98 return s:Safe_indent( ind, s:First_word_len(prev_data), getline(v:lnum)) | |
99 else | |
100 " if/for/while without '{' | |
101 return ind + &sw | |
102 endif | |
103 endif | |
104 endif | |
105 | |
106 " If the previous line doesn't need continuation on the current line we are | |
107 " on the start of a new statement. We have to make sure we align with the | |
108 " previous statement instead of just the previous line. This is a bit | |
109 " complicated because the previous statement might be multi-line. | |
110 " | |
111 " The start of a multiline statement can be found by: | |
112 " | |
113 " 1 If the previous line contains closing braces and has negative brace | |
114 " balance, search backwards until cumulative brace balance becomes zero, | |
115 " take indent of that line | |
116 " 2 If the line before the previous needs continuation search backward | |
117 " until that's not the case anymore. Take indent of one line down. | |
118 | |
119 " Case 1 | |
120 if prev_data =~ ')' && brace_balance < 0 | |
121 while brace_balance != 0 | |
122 let prev_lineno = s:Get_prev_line( prev_lineno ) | |
123 let prev_data = getline( prev_lineno ) | |
124 let brace_balance=brace_balance+s:Get_brace_balance(prev_data,'(',')' ) | |
125 endwhile | |
126 let ind = indent( prev_lineno ) | |
127 else | |
128 " Case 2 | |
129 if s:Seems_continuing( getline( prev_lineno - 1 ) ) | |
130 let prev_lineno = prev_lineno - 2 | |
131 let prev_data = getline( prev_lineno ) | |
132 while prev_lineno > 0 && (s:Seems_continuing( prev_data ) > 0) | |
133 let prev_lineno = s:Get_prev_line( prev_lineno ) | |
134 let prev_data = getline( prev_lineno ) | |
135 endwhile | |
136 let ind = indent( prev_lineno + 1 ) | |
137 endif | |
138 endif | |
139 | |
140 " Decrease indent if this line contains a '}'. | |
141 if getline(v:lnum) =~ '^\s*}' | |
142 let ind = ind - &sw | |
143 endif | |
144 | |
145 return ind | |
146 endfunction | |
147 | |
148 " Find the open and close braces in this line and return how many more open- | |
149 " than close braces there are. It's also used to determine cumulative balance | |
150 " across multiple lines. | |
151 | |
152 function! s:Get_brace_balance( line, b_open, b_close ) | |
153 let line2 = substitute( a:line, a:b_open, "", "g" ) | |
154 let openb = strlen( a:line ) - strlen( line2 ) | |
155 let line3 = substitute( line2, a:b_close, "", "g" ) | |
156 let closeb = strlen( line2 ) - strlen( line3 ) | |
157 return openb - closeb | |
158 endfunction | |
159 | |
160 " Find out whether the line starts with a word (i.e. keyword or function | |
161 " call). Might need enhancements here. | |
162 | |
163 function! s:Starts_with_word( line ) | |
164 if a:line =~ '^\s*[a-zA-Z_0-9]\+\s*(' | |
165 return 1 | |
166 endif | |
167 return 0 | |
168 endfunction | |
169 | |
170 " Find the length of the first word in a line. This is used to be able to | |
171 " align a line relative to the 'print ' or 'if (' on the previous line in case | |
172 " such a statement spans multiple lines. | |
173 " Precondition: only to be used on lines where 'Starts_with_word' returns 1. | |
174 | |
175 function! s:First_word_len( line ) | |
176 let white_end = matchend( a:line, '^\s*' ) | |
177 if match( a:line, '^\s*func' ) != -1 | |
178 let word_end = matchend( a:line, '[a-z]\+\s\+[a-zA-Z_0-9]\+[ (]*' ) | |
179 else | |
180 let word_end = matchend( a:line, '[a-zA-Z_0-9]\+[ (]*' ) | |
181 endif | |
182 return word_end - white_end | |
183 endfunction | |
184 | |
185 " Determine if 'line' completes a statement or is continued on the next line. | |
186 " This one is far from complete and accepts illegal code. Not important for | |
187 " indenting, however. | |
188 | |
189 function! s:Seems_continuing( line ) | |
190 " Unfinished lines | |
191 if a:line =~ '[\\,\|\&\+\-\*\%\^]\s*$' | |
192 return 1 | |
193 endif | |
194 " if/for/while (cond) eol | |
195 if a:line =~ '^\s*\(if\|while\|for\)\s*(.*)\s*$' || a:line =~ '^\s*else\s*' | |
196 return 2 | |
197 endif | |
198 return 0 | |
199 endfunction | |
200 | |
201 " Get previous relevant line. Search back until a line is that is no | |
202 " comment or blank and return the line number | |
203 | |
204 function! s:Get_prev_line( lineno ) | |
205 let lnum = a:lineno - 1 | |
206 let data = getline( lnum ) | |
207 while lnum > 0 && (data =~ '^\s*#' || data =~ '^\s*$') | |
208 let lnum = lnum - 1 | |
209 let data = getline( lnum ) | |
210 endwhile | |
211 return lnum | |
212 endfunction | |
213 | |
214 " This function checks whether an indented line exceeds a maximum linewidth | |
215 " (hardcoded 80). If so and it is possible to stay within 80 positions (or | |
216 " limit num of characters beyond linewidth) by decreasing the indent (keeping | |
217 " it > base_indent), do so. | |
218 | |
219 function! s:Safe_indent( base, wordlen, this_line ) | |
220 let line_base = matchend( a:this_line, '^\s*' ) | |
221 let line_len = strlen( a:this_line ) - line_base | |
222 let indent = a:base | |
223 if (indent + a:wordlen + line_len) > 80 | |
224 " Simple implementation good enough for the time being | |
225 let indent = indent + 3 | |
226 endif | |
227 return indent + a:wordlen | |
228 endfunction |