comparison runtime/indent/r.vim @ 3082:3502a7f991fc

Updated runtime files.
author Bram Moolenaar <bram@vim.org>
date Wed, 14 Sep 2011 17:55:08 +0200
parents
children 37ecb8ff4560
comparison
equal deleted inserted replaced
3081:1e50bdaa24f8 3082:3502a7f991fc
1 " Vim indent file
2 " Language: R
3 " Author: Jakson Alves de Aquino <jalvesaq@gmail.com>
4 " Last Change: Wed Aug 31, 2011 12:24AM
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
458 if ind == pind || (ind == (pind + &sw) && pline =~ '{$' && ppost_else == 0)
459 return ind
460 endif
461
462 while pind < ind && plnum > 0 && ppb == 0
463 let ind = pind
464 let plnum = s:Get_prev_line(plnum)
465 let pline = getline(plnum)
466 let ppb = s:Get_paren_balance(pline, '(', ')')
467 while pline =~ '^\s*else'
468 let plnum = s:Get_matching_if(plnum, 1)
469 let pline = getline(plnum)
470 let ppb = s:Get_paren_balance(pline, '(', ')')
471 endwhile
472 let pind = indent(plnum)
473 if ind == (pind + &sw) && pline =~ '{$'
474 return ind
475 endif
476 endwhile
477
478 return ind
479
480 endfunction
481
482 " vim: sw=4