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