3082
|
1 " Vim indent file
|
|
2 " Language: R
|
|
3 " Author: Jakson Alves de Aquino <jalvesaq@gmail.com>
|
3153
|
4 " Last Change: Fri Oct 14, 2011 09:50PM
|
3082
|
5
|
|
6
|
|
7 " Only load this indent file when no other was loaded.
|
|
8 if exists("b:did_r_indent")
|
|
9 finish
|
|
10 endif
|
|
11 let b:did_r_indent = 1
|
|
12
|
|
13 setlocal indentkeys=0{,0},:,!^F,o,O,e
|
|
14 setlocal indentexpr=GetRIndent()
|
|
15
|
|
16 " Only define the function once.
|
|
17 if exists("*GetRIndent")
|
|
18 finish
|
|
19 endif
|
|
20
|
|
21 " Options to make the indentation more similar to Emacs/ESS:
|
|
22 if !exists("g:r_indent_align_args")
|
|
23 let g:r_indent_align_args = 1
|
|
24 endif
|
|
25 if !exists("g:r_indent_ess_comments")
|
|
26 let g:r_indent_ess_comments = 0
|
|
27 endif
|
|
28 if !exists("g:r_indent_comment_column")
|
|
29 let g:r_indent_comment_column = 40
|
|
30 endif
|
|
31 if ! exists("g:r_indent_ess_compatible")
|
|
32 let g:r_indent_ess_compatible = 0
|
|
33 endif
|
|
34
|
|
35 function s:RDelete_quotes(line)
|
|
36 let i = 0
|
|
37 let j = 0
|
|
38 let line1 = ""
|
|
39 let llen = strlen(a:line)
|
|
40 while i < llen
|
|
41 if a:line[i] == '"'
|
|
42 let i += 1
|
|
43 let line1 = line1 . 's'
|
|
44 while !(a:line[i] == '"' && ((i > 1 && a:line[i-1] == '\' && a:line[i-2] == '\') || a:line[i-1] != '\')) && i < llen
|
|
45 let i += 1
|
|
46 endwhile
|
|
47 if a:line[i] == '"'
|
|
48 let i += 1
|
|
49 endif
|
|
50 else
|
|
51 if a:line[i] == "'"
|
|
52 let i += 1
|
|
53 let line1 = line1 . 's'
|
|
54 while !(a:line[i] == "'" && ((i > 1 && a:line[i-1] == '\' && a:line[i-2] == '\') || a:line[i-1] != '\')) && i < llen
|
|
55 let i += 1
|
|
56 endwhile
|
|
57 if a:line[i] == "'"
|
|
58 let i += 1
|
|
59 endif
|
|
60 else
|
|
61 if a:line[i] == "`"
|
|
62 let i += 1
|
|
63 let line1 = line1 . 's'
|
|
64 while a:line[i] != "`" && i < llen
|
|
65 let i += 1
|
|
66 endwhile
|
|
67 if a:line[i] == "`"
|
|
68 let i += 1
|
|
69 endif
|
|
70 endif
|
|
71 endif
|
|
72 endif
|
|
73 if i == llen
|
|
74 break
|
|
75 endif
|
|
76 let line1 = line1 . a:line[i]
|
|
77 let j += 1
|
|
78 let i += 1
|
|
79 endwhile
|
|
80 return line1
|
|
81 endfunction
|
|
82
|
|
83 " Convert foo(bar()) int foo()
|
|
84 function s:RDelete_parens(line)
|
|
85 if s:Get_paren_balance(a:line, "(", ")") != 0
|
|
86 return a:line
|
|
87 endif
|
|
88 let i = 0
|
|
89 let j = 0
|
|
90 let line1 = ""
|
|
91 let llen = strlen(a:line)
|
|
92 while i < llen
|
|
93 let line1 = line1 . a:line[i]
|
|
94 if a:line[i] == '('
|
|
95 let nop = 1
|
|
96 while nop > 0 && i < llen
|
|
97 let i += 1
|
|
98 if a:line[i] == ')'
|
|
99 let nop -= 1
|
|
100 else
|
|
101 if a:line[i] == '('
|
|
102 let nop += 1
|
|
103 endif
|
|
104 endif
|
|
105 endwhile
|
|
106 let line1 = line1 . a:line[i]
|
|
107 endif
|
|
108 let i += 1
|
|
109 endwhile
|
|
110 return line1
|
|
111 endfunction
|
|
112
|
|
113 function! s:Get_paren_balance(line, o, c)
|
|
114 let line2 = substitute(a:line, a:o, "", "g")
|
|
115 let openp = strlen(a:line) - strlen(line2)
|
|
116 let line3 = substitute(line2, a:c, "", "g")
|
|
117 let closep = strlen(line2) - strlen(line3)
|
|
118 return openp - closep
|
|
119 endfunction
|
|
120
|
|
121 function! s:Get_matching_brace(linenr, o, c, delbrace)
|
|
122 let line = SanitizeRLine(getline(a:linenr))
|
|
123 if a:delbrace == 1
|
|
124 let line = substitute(line, '{$', "", "")
|
|
125 endif
|
|
126 let pb = s:Get_paren_balance(line, a:o, a:c)
|
|
127 let i = a:linenr
|
|
128 while pb != 0 && i > 1
|
|
129 let i -= 1
|
|
130 let pb += s:Get_paren_balance(SanitizeRLine(getline(i)), a:o, a:c)
|
|
131 endwhile
|
|
132 return i
|
|
133 endfunction
|
|
134
|
|
135 " This function is buggy because there 'if's without 'else'
|
|
136 " It must be rewritten relying more on indentation
|
|
137 function! s:Get_matching_if(linenr, delif)
|
|
138 " let filenm = expand("%")
|
|
139 " call writefile([filenm], "/tmp/matching_if_" . a:linenr)
|
|
140 let line = SanitizeRLine(getline(a:linenr))
|
|
141 if a:delif
|
|
142 let line = substitute(line, "if", "", "g")
|
|
143 endif
|
|
144 let elsenr = 0
|
|
145 let i = a:linenr
|
|
146 let ifhere = 0
|
|
147 while i > 0
|
|
148 let line2 = substitute(line, '\<else\>', "xxx", "g")
|
|
149 let elsenr += strlen(line) - strlen(line2)
|
|
150 if line =~ '.*\s*if\s*()' || line =~ '.*\s*if\s*()'
|
|
151 let elsenr -= 1
|
|
152 if elsenr == 0
|
|
153 let ifhere = i
|
|
154 break
|
|
155 endif
|
|
156 endif
|
|
157 let i -= 1
|
|
158 let line = SanitizeRLine(getline(i))
|
|
159 endwhile
|
|
160 if ifhere
|
|
161 return ifhere
|
|
162 else
|
|
163 return a:linenr
|
|
164 endif
|
|
165 endfunction
|
|
166
|
|
167 function! s:Get_last_paren_idx(line, o, c, pb)
|
|
168 let blc = a:pb
|
|
169 let line = substitute(a:line, '\t', s:curtabstop, "g")
|
|
170 let theidx = -1
|
|
171 let llen = strlen(line)
|
|
172 let idx = 0
|
|
173 while idx < llen
|
|
174 if line[idx] == a:o
|
|
175 let blc -= 1
|
|
176 if blc == 0
|
|
177 let theidx = idx
|
|
178 endif
|
|
179 else
|
|
180 if line[idx] == a:c
|
|
181 let blc += 1
|
|
182 endif
|
|
183 endif
|
|
184 let idx += 1
|
|
185 endwhile
|
|
186 return theidx + 1
|
|
187 endfunction
|
|
188
|
|
189 " Get previous relevant line. Search back until getting a line that isn't
|
|
190 " comment or blank
|
|
191 function s:Get_prev_line(lineno)
|
|
192 let lnum = a:lineno - 1
|
|
193 let data = getline( lnum )
|
|
194 while lnum > 0 && (data =~ '^\s*#' || data =~ '^\s*$')
|
|
195 let lnum = lnum - 1
|
|
196 let data = getline( lnum )
|
|
197 endwhile
|
|
198 return lnum
|
|
199 endfunction
|
|
200
|
|
201 " This function is also used by r-plugin/common_global.vim
|
|
202 " Delete from '#' to the end of the line, unless the '#' is inside a string.
|
|
203 function SanitizeRLine(line)
|
|
204 let newline = s:RDelete_quotes(a:line)
|
|
205 let newline = s:RDelete_parens(newline)
|
|
206 let newline = substitute(newline, '#.*', "", "")
|
|
207 let newline = substitute(newline, '\s*$', "", "")
|
|
208 return newline
|
|
209 endfunction
|
|
210
|
|
211 function GetRIndent()
|
|
212
|
|
213 let clnum = line(".") " current line
|
|
214
|
|
215 let cline = getline(clnum)
|
|
216 if cline =~ '^\s*#'
|
|
217 if g:r_indent_ess_comments == 1
|
|
218 if cline =~ '^\s*###'
|
|
219 return 0
|
|
220 endif
|
|
221 if cline !~ '^\s*##'
|
|
222 return g:r_indent_comment_column
|
|
223 endif
|
|
224 endif
|
|
225 endif
|
|
226
|
|
227 let cline = SanitizeRLine(cline)
|
|
228
|
|
229 if cline =~ '^\s*}' || cline =~ '^\s*}\s*)$'
|
|
230 let indline = s:Get_matching_brace(clnum, '{', '}', 1)
|
|
231 if indline > 0 && indline != clnum
|
|
232 let iline = SanitizeRLine(getline(indline))
|
|
233 if s:Get_paren_balance(iline, "(", ")") == 0 || iline =~ '(\s*{$'
|
|
234 return indent(indline)
|
|
235 else
|
|
236 let indline = s:Get_matching_brace(indline, '(', ')', 1)
|
|
237 return indent(indline)
|
|
238 endif
|
|
239 endif
|
|
240 endif
|
|
241
|
|
242 " Find the first non blank line above the current line
|
|
243 let lnum = s:Get_prev_line(clnum)
|
|
244 " Hit the start of the file, use zero indent.
|
|
245 if lnum == 0
|
|
246 return 0
|
|
247 endif
|
|
248
|
|
249 let line = SanitizeRLine(getline(lnum))
|
|
250
|
|
251 if &filetype == "rhelp"
|
|
252 if cline =~ '^\\dontshow{' || cline =~ '^\\dontrun{' || cline =~ '^\\donttest{' || cline =~ '^\\testonly{'
|
|
253 return 0
|
|
254 endif
|
|
255 if line =~ '^\\examples{' || line =~ '^\\usage{' || line =~ '^\\dontshow{' || line =~ '^\\dontrun{' || line =~ '^\\donttest{' || line =~ '^\\testonly{'
|
|
256 return 0
|
|
257 endif
|
|
258 if line =~ '^\\method{.*}{.*}(.*'
|
|
259 let line = substitute(line, '^\\method{\(.*\)}{.*}', '\1', "")
|
|
260 endif
|
|
261 endif
|
|
262
|
|
263 if cline =~ '^\s*{'
|
|
264 if g:r_indent_ess_compatible && line =~ ')$'
|
|
265 let nlnum = lnum
|
|
266 let nline = line
|
|
267 while s:Get_paren_balance(nline, '(', ')') < 0
|
|
268 let nlnum = s:Get_prev_line(nlnum)
|
|
269 let nline = SanitizeRLine(getline(nlnum)) . nline
|
|
270 endwhile
|
|
271 if nline =~ '^\s*function\s*(' && indent(nlnum) == &sw
|
|
272 return 0
|
|
273 endif
|
|
274 endif
|
|
275 if s:Get_paren_balance(line, "(", ")") == 0
|
|
276 return indent(lnum)
|
|
277 endif
|
|
278 endif
|
|
279
|
|
280 " line is an incomplete command:
|
|
281 if line =~ '\<\(if\|while\|for\|function\)\s*()$' || line =~ '\<else$' || line =~ '<-$'
|
|
282 return indent(lnum) + &sw
|
|
283 endif
|
|
284
|
|
285 " Deal with () and []
|
|
286
|
|
287 let pb = s:Get_paren_balance(line, '(', ')')
|
|
288
|
|
289 if line =~ '^\s*{$' || line =~ '(\s*{' || (pb == 0 && (line =~ '{$' || line =~ '(\s*{$'))
|
|
290 return indent(lnum) + &sw
|
|
291 endif
|
|
292
|
|
293 let bb = s:Get_paren_balance(line, '[', ']')
|
|
294
|
|
295 let s:curtabstop = repeat(' ', &tabstop)
|
|
296 if g:r_indent_align_args == 1
|
|
297
|
|
298 if pb == 0 && bb == 0 && (line =~ '.*[,&|\-\*+<>]$' || cline =~ '^\s*[,&|\-\*+<>]')
|
|
299 return indent(lnum)
|
|
300 endif
|
|
301
|
|
302 if pb > 0
|
|
303 if &filetype == "rhelp"
|
|
304 let ind = s:Get_last_paren_idx(line, '(', ')', pb)
|
|
305 else
|
|
306 let ind = s:Get_last_paren_idx(getline(lnum), '(', ')', pb)
|
|
307 endif
|
|
308 return ind
|
|
309 endif
|
|
310
|
|
311 if pb < 0 && line =~ '.*[,&|\-\*+<>]$'
|
|
312 let lnum = s:Get_prev_line(lnum)
|
|
313 while pb < 1 && lnum > 0
|
|
314 let line = SanitizeRLine(getline(lnum))
|
|
315 let line = substitute(line, '\t', s:curtabstop, "g")
|
|
316 let ind = strlen(line)
|
|
317 while ind > 0
|
|
318 if line[ind] == ')'
|
|
319 let pb -= 1
|
|
320 else
|
|
321 if line[ind] == '('
|
|
322 let pb += 1
|
|
323 endif
|
|
324 endif
|
|
325 if pb == 1
|
|
326 return ind + 1
|
|
327 endif
|
|
328 let ind -= 1
|
|
329 endwhile
|
|
330 let lnum -= 1
|
|
331 endwhile
|
|
332 return 0
|
|
333 endif
|
|
334
|
|
335 if bb > 0
|
|
336 let ind = s:Get_last_paren_idx(getline(lnum), '[', ']', bb)
|
|
337 return ind
|
|
338 endif
|
|
339 endif
|
|
340
|
|
341 let post_block = 0
|
|
342 if line =~ '}$'
|
|
343 let lnum = s:Get_matching_brace(lnum, '{', '}', 0)
|
|
344 let line = SanitizeRLine(getline(lnum))
|
|
345 if lnum > 0 && line =~ '^\s*{'
|
|
346 let lnum = s:Get_prev_line(lnum)
|
|
347 let line = SanitizeRLine(getline(lnum))
|
|
348 endif
|
|
349 let pb = s:Get_paren_balance(line, '(', ')')
|
|
350 let post_block = 1
|
|
351 endif
|
|
352
|
|
353 let post_fun = 0
|
|
354 if pb < 0 && line !~ ')\s*[,&|\-\*+<>]$'
|
|
355 let post_fun = 1
|
|
356 while pb < 0 && lnum > 0
|
|
357 let lnum -= 1
|
|
358 let linepiece = SanitizeRLine(getline(lnum))
|
|
359 let pb += s:Get_paren_balance(linepiece, "(", ")")
|
|
360 let line = linepiece . line
|
|
361 endwhile
|
|
362 if line =~ '{$' && post_block == 0
|
|
363 return indent(lnum) + &sw
|
|
364 endif
|
|
365
|
|
366 " Now we can do some tests again
|
|
367 if cline =~ '^\s*{'
|
|
368 return indent(lnum)
|
|
369 endif
|
|
370 if post_block == 0
|
|
371 let newl = SanitizeRLine(line)
|
|
372 if newl =~ '\<\(if\|while\|for\|function\)\s*()$' || newl =~ '\<else$' || newl =~ '<-$'
|
|
373 return indent(lnum) + &sw
|
|
374 endif
|
|
375 endif
|
|
376 endif
|
|
377
|
|
378 if cline =~ '^\s*else'
|
|
379 if line =~ '<-\s*if\s*()'
|
|
380 return indent(lnum) + &sw
|
|
381 else
|
|
382 if line =~ '\<if\s*()'
|
|
383 return indent(lnum)
|
|
384 else
|
|
385 return indent(lnum) - &sw
|
|
386 endif
|
|
387 endif
|
|
388 endif
|
|
389
|
|
390 if bb < 0 && line =~ '.*]'
|
|
391 while bb < 0 && lnum > 0
|
|
392 let lnum -= 1
|
|
393 let linepiece = SanitizeRLine(getline(lnum))
|
|
394 let bb += s:Get_paren_balance(linepiece, "[", "]")
|
|
395 let line = linepiece . line
|
|
396 endwhile
|
|
397 let line = s:RDelete_parens(line)
|
|
398 endif
|
|
399
|
|
400 let plnum = s:Get_prev_line(lnum)
|
|
401 let ppost_else = 0
|
|
402 if plnum > 0
|
|
403 let pline = SanitizeRLine(getline(plnum))
|
|
404 let ppost_block = 0
|
|
405 if pline =~ '}$'
|
|
406 let ppost_block = 1
|
|
407 let plnum = s:Get_matching_brace(plnum, '{', '}', 0)
|
|
408 let pline = SanitizeRLine(getline(plnum))
|
|
409 if pline =~ '^\s*{$' && plnum > 0
|
|
410 let plnum = s:Get_prev_line(plnum)
|
|
411 let pline = SanitizeRLine(getline(plnum))
|
|
412 endif
|
|
413 endif
|
|
414
|
|
415 if pline =~ 'else$'
|
|
416 let ppost_else = 1
|
|
417 let plnum = s:Get_matching_if(plnum, 0)
|
|
418 let pline = SanitizeRLine(getline(plnum))
|
|
419 endif
|
|
420
|
|
421 if pline =~ '^\s*else\s*if\s*('
|
|
422 let pplnum = s:Get_prev_line(plnum)
|
|
423 let ppline = SanitizeRLine(getline(pplnum))
|
|
424 while ppline =~ '^\s*else\s*if\s*(' || ppline =~ '^\s*if\s*()\s*\S$'
|
|
425 let plnum = pplnum
|
|
426 let pline = ppline
|
|
427 let pplnum = s:Get_prev_line(plnum)
|
|
428 let ppline = SanitizeRLine(getline(pplnum))
|
|
429 endwhile
|
|
430 while ppline =~ '\<\(if\|while\|for\|function\)\s*()$' || ppline =~ '\<else$' || ppline =~ '<-$'
|
|
431 let plnum = pplnum
|
|
432 let pline = ppline
|
|
433 let pplnum = s:Get_prev_line(plnum)
|
|
434 let ppline = SanitizeRLine(getline(pplnum))
|
|
435 endwhile
|
|
436 endif
|
|
437
|
|
438 let ppb = s:Get_paren_balance(pline, '(', ')')
|
|
439 if ppb < 0 && (pline =~ ')\s*{$' || pline =~ ')$')
|
|
440 while ppb < 0 && plnum > 0
|
|
441 let plnum -= 1
|
|
442 let linepiece = SanitizeRLine(getline(plnum))
|
|
443 let ppb += s:Get_paren_balance(linepiece, "(", ")")
|
|
444 let pline = linepiece . pline
|
|
445 endwhile
|
|
446 let pline = s:RDelete_parens(pline)
|
|
447 endif
|
|
448 endif
|
|
449
|
|
450 let ind = indent(lnum)
|
|
451 let pind = indent(plnum)
|
|
452
|
|
453 if g:r_indent_align_args == 0 && pb != 0
|
|
454 let ind += pb * &sw
|
|
455 return ind
|
|
456 endif
|
|
457
|
3153
|
458 if g:r_indent_align_args == 0 && bb != 0
|
|
459 let ind += bb * &sw
|
|
460 return ind
|
|
461 endif
|
|
462
|
3082
|
463 if ind == pind || (ind == (pind + &sw) && pline =~ '{$' && ppost_else == 0)
|
|
464 return ind
|
|
465 endif
|
|
466
|
3153
|
467 let pline = getline(plnum)
|
|
468 let pbb = s:Get_paren_balance(pline, '[', ']')
|
|
469
|
|
470 while pind < ind && plnum > 0 && ppb == 0 && pbb == 0
|
3082
|
471 let ind = pind
|
|
472 let plnum = s:Get_prev_line(plnum)
|
|
473 let pline = getline(plnum)
|
|
474 let ppb = s:Get_paren_balance(pline, '(', ')')
|
3153
|
475 let pbb = s:Get_paren_balance(pline, '[', ']')
|
3082
|
476 while pline =~ '^\s*else'
|
|
477 let plnum = s:Get_matching_if(plnum, 1)
|
|
478 let pline = getline(plnum)
|
|
479 let ppb = s:Get_paren_balance(pline, '(', ')')
|
3153
|
480 let pbb = s:Get_paren_balance(pline, '[', ']')
|
3082
|
481 endwhile
|
|
482 let pind = indent(plnum)
|
|
483 if ind == (pind + &sw) && pline =~ '{$'
|
|
484 return ind
|
|
485 endif
|
|
486 endwhile
|
|
487
|
|
488 return ind
|
|
489
|
|
490 endfunction
|
|
491
|
|
492 " vim: sw=4
|