Mercurial > vim
annotate runtime/indent/awk.vim @ 29663:5009fd4e3de6
Added tag v9.0.0171 for changeset b03c47618895fa9b5e712709457fa17b691e2ab9
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Mon, 08 Aug 2022 17:15:04 +0200 |
parents | 6dd88e45d47d |
children |
rev | line source |
---|---|
7 | 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 | |
3082 | 26 " Fixed hang: 2011 Aug 31 |
28379 | 27 " 2022 April: b:undo_indent added by Doug Kearns |
7 | 28 |
29 " Only load this indent file when no other was loaded. | |
30 if exists("b:did_indent") | |
31 finish | |
32 endif | |
33 | |
34 let b:did_indent = 1 | |
35 | |
36 setlocal indentexpr=GetAwkIndent() | |
37 " Mmm, copied from the tcl indent program. Is this okay? | |
38 setlocal indentkeys-=:,0# | |
39 | |
28379 | 40 let b:undo_indent = "setl inde< indk<" |
41 | |
7 | 42 " Only define the function once. |
43 if exists("*GetAwkIndent") | |
44 finish | |
45 endif | |
46 | |
47 " This function contains a lot of exit points. It checks for simple cases | |
48 " first to get out of the function as soon as possible, thereby reducing the | |
49 " number of possibilities later on in the difficult parts | |
50 | |
51 function! GetAwkIndent() | |
52 | |
16610 | 53 " Find previous line and get its indentation |
7 | 54 let prev_lineno = s:Get_prev_line( v:lnum ) |
55 if prev_lineno == 0 | |
56 return 0 | |
57 endif | |
58 let prev_data = getline( prev_lineno ) | |
59 let ind = indent( prev_lineno ) | |
60 | |
61 " Increase indent if the previous line contains an opening brace. Search | |
62 " for this brace the hard way to prevent errors if the previous line is a | |
63 " 'pattern { action }' (simple check match on /{/ increases the indent then) | |
64 | |
65 if s:Get_brace_balance( prev_data, '{', '}' ) > 0 | |
11518 | 66 return ind + shiftwidth() |
7 | 67 endif |
68 | |
69 let brace_balance = s:Get_brace_balance( prev_data, '(', ')' ) | |
70 | |
71 " If prev line has positive brace_balance and starts with a word (keyword | |
72 " or function name), align the current line on the first '(' of the prev | |
73 " line | |
74 | |
75 if brace_balance > 0 && s:Starts_with_word( prev_data ) | |
76 return s:Safe_indent( ind, s:First_word_len(prev_data), getline(v:lnum)) | |
77 endif | |
78 | |
79 " If this line starts with an open brace bail out now before the line | |
80 " continuation checks. | |
81 | |
82 if getline( v:lnum ) =~ '^\s*{' | |
83 return ind | |
84 endif | |
85 | |
86 " If prev line seems to be part of multiline statement: | |
87 " 1. Prev line is first line of a multiline statement | |
88 " -> attempt to indent on first ' ' or '(' of prev line, just like we | |
89 " indented the positive brace balance case above | |
90 " 2. Prev line is not first line of a multiline statement | |
91 " -> copy indent of prev line | |
92 | |
93 let continue_mode = s:Seems_continuing( prev_data ) | |
94 if continue_mode > 0 | |
95 if s:Seems_continuing( getline(s:Get_prev_line( prev_lineno )) ) | |
96 " Case 2 | |
97 return ind | |
98 else | |
99 " Case 1 | |
100 if continue_mode == 1 | |
101 " Need continuation due to comma, backslash, etc | |
102 return s:Safe_indent( ind, s:First_word_len(prev_data), getline(v:lnum)) | |
103 else | |
104 " if/for/while without '{' | |
11518 | 105 return ind + shiftwidth() |
7 | 106 endif |
107 endif | |
108 endif | |
109 | |
110 " If the previous line doesn't need continuation on the current line we are | |
111 " on the start of a new statement. We have to make sure we align with the | |
112 " previous statement instead of just the previous line. This is a bit | |
113 " complicated because the previous statement might be multi-line. | |
114 " | |
115 " The start of a multiline statement can be found by: | |
116 " | |
117 " 1 If the previous line contains closing braces and has negative brace | |
118 " balance, search backwards until cumulative brace balance becomes zero, | |
119 " take indent of that line | |
120 " 2 If the line before the previous needs continuation search backward | |
121 " until that's not the case anymore. Take indent of one line down. | |
122 | |
123 " Case 1 | |
124 if prev_data =~ ')' && brace_balance < 0 | |
3082 | 125 while brace_balance != 0 && prev_lineno > 0 |
7 | 126 let prev_lineno = s:Get_prev_line( prev_lineno ) |
127 let prev_data = getline( prev_lineno ) | |
128 let brace_balance=brace_balance+s:Get_brace_balance(prev_data,'(',')' ) | |
129 endwhile | |
130 let ind = indent( prev_lineno ) | |
131 else | |
132 " Case 2 | |
133 if s:Seems_continuing( getline( prev_lineno - 1 ) ) | |
134 let prev_lineno = prev_lineno - 2 | |
135 let prev_data = getline( prev_lineno ) | |
136 while prev_lineno > 0 && (s:Seems_continuing( prev_data ) > 0) | |
137 let prev_lineno = s:Get_prev_line( prev_lineno ) | |
138 let prev_data = getline( prev_lineno ) | |
139 endwhile | |
140 let ind = indent( prev_lineno + 1 ) | |
141 endif | |
142 endif | |
143 | |
144 " Decrease indent if this line contains a '}'. | |
145 if getline(v:lnum) =~ '^\s*}' | |
11518 | 146 let ind = ind - shiftwidth() |
7 | 147 endif |
148 | |
149 return ind | |
150 endfunction | |
151 | |
152 " Find the open and close braces in this line and return how many more open- | |
153 " than close braces there are. It's also used to determine cumulative balance | |
154 " across multiple lines. | |
155 | |
156 function! s:Get_brace_balance( line, b_open, b_close ) | |
157 let line2 = substitute( a:line, a:b_open, "", "g" ) | |
158 let openb = strlen( a:line ) - strlen( line2 ) | |
159 let line3 = substitute( line2, a:b_close, "", "g" ) | |
160 let closeb = strlen( line2 ) - strlen( line3 ) | |
161 return openb - closeb | |
162 endfunction | |
163 | |
164 " Find out whether the line starts with a word (i.e. keyword or function | |
165 " call). Might need enhancements here. | |
166 | |
167 function! s:Starts_with_word( line ) | |
168 if a:line =~ '^\s*[a-zA-Z_0-9]\+\s*(' | |
169 return 1 | |
170 endif | |
171 return 0 | |
172 endfunction | |
173 | |
174 " Find the length of the first word in a line. This is used to be able to | |
175 " align a line relative to the 'print ' or 'if (' on the previous line in case | |
176 " such a statement spans multiple lines. | |
177 " Precondition: only to be used on lines where 'Starts_with_word' returns 1. | |
178 | |
179 function! s:First_word_len( line ) | |
180 let white_end = matchend( a:line, '^\s*' ) | |
181 if match( a:line, '^\s*func' ) != -1 | |
182 let word_end = matchend( a:line, '[a-z]\+\s\+[a-zA-Z_0-9]\+[ (]*' ) | |
183 else | |
184 let word_end = matchend( a:line, '[a-zA-Z_0-9]\+[ (]*' ) | |
185 endif | |
186 return word_end - white_end | |
187 endfunction | |
188 | |
189 " Determine if 'line' completes a statement or is continued on the next line. | |
190 " This one is far from complete and accepts illegal code. Not important for | |
191 " indenting, however. | |
192 | |
193 function! s:Seems_continuing( line ) | |
194 " Unfinished lines | |
3099
887d6d91882e
Updated a few runtime files.
Bram Moolenaar <bram@vim.org>
parents:
3082
diff
changeset
|
195 if a:line =~ '\(--\|++\)\s*$' |
887d6d91882e
Updated a few runtime files.
Bram Moolenaar <bram@vim.org>
parents:
3082
diff
changeset
|
196 return 0 |
887d6d91882e
Updated a few runtime files.
Bram Moolenaar <bram@vim.org>
parents:
3082
diff
changeset
|
197 endif |
7 | 198 if a:line =~ '[\\,\|\&\+\-\*\%\^]\s*$' |
199 return 1 | |
200 endif | |
201 " if/for/while (cond) eol | |
202 if a:line =~ '^\s*\(if\|while\|for\)\s*(.*)\s*$' || a:line =~ '^\s*else\s*' | |
203 return 2 | |
204 endif | |
205 return 0 | |
206 endfunction | |
207 | |
208 " Get previous relevant line. Search back until a line is that is no | |
209 " comment or blank and return the line number | |
210 | |
211 function! s:Get_prev_line( lineno ) | |
212 let lnum = a:lineno - 1 | |
213 let data = getline( lnum ) | |
214 while lnum > 0 && (data =~ '^\s*#' || data =~ '^\s*$') | |
215 let lnum = lnum - 1 | |
216 let data = getline( lnum ) | |
217 endwhile | |
218 return lnum | |
219 endfunction | |
220 | |
221 " This function checks whether an indented line exceeds a maximum linewidth | |
222 " (hardcoded 80). If so and it is possible to stay within 80 positions (or | |
223 " limit num of characters beyond linewidth) by decreasing the indent (keeping | |
224 " it > base_indent), do so. | |
225 | |
226 function! s:Safe_indent( base, wordlen, this_line ) | |
227 let line_base = matchend( a:this_line, '^\s*' ) | |
228 let line_len = strlen( a:this_line ) - line_base | |
229 let indent = a:base | |
230 if (indent + a:wordlen + line_len) > 80 | |
231 " Simple implementation good enough for the time being | |
232 let indent = indent + 3 | |
233 endif | |
234 return indent + a:wordlen | |
235 endfunction |