neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

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