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