neovim

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

rapid.vim (8166B)


      1 " ABB Rapid Command indent file for Vim
      2 " Language: ABB Rapid Command
      3 " Maintainer: Patrick Meiser-Knosowski <knosowski@graeffrobotics.de>
      4 " Version: 2.2.7
      5 " Last Change: 12. May 2023
      6 " Credits: Based on indent/vim.vim
      7 "
      8 " Suggestions of improvement are very welcome. Please email me!
      9 "
     10 " Known bugs: ../doc/rapid.txt
     11 "
     12 " TODO
     13 " * indent wrapped lines which do not end with an ; or special key word,
     14 "     maybe this is a better idea, but then () and [] has to be changed as
     15 "     well
     16 "
     17 
     18 if exists("g:rapidNoSpaceIndent")
     19  if !exists("g:rapidSpaceIndent")
     20    let g:rapidSpaceIndent = !g:rapidNoSpaceIndent
     21  endif
     22  unlet g:rapidNoSpaceIndent
     23 endif
     24 
     25 " Only load this indent file when no other was loaded.
     26 if exists("b:did_indent") || get(g:,'rapidNoIndent',0)
     27  finish
     28 endif
     29 let b:did_indent = 1
     30 
     31 setlocal nolisp
     32 setlocal nosmartindent
     33 setlocal autoindent
     34 setlocal indentexpr=GetRapidIndent()
     35 if get(g:,'rapidNewStyleIndent',0)
     36  setlocal indentkeys=!^F,o,O,0=~endmodule,0=~error,0=~undo,0=~backward,0=~endproc,0=~endrecord,0=~endtrap,0=~endfunc,0=~else,0=~endif,0=~endtest,0=~endfor,0=~endwhile,:,<[>,<]>,<(>,<)>
     37 else
     38  setlocal indentkeys=!^F,o,O,0=~endmodule,0=~error,0=~undo,0=~backward,0=~endproc,0=~endrecord,0=~endtrap,0=~endfunc,0=~else,0=~endif,0=~endtest,0=~endfor,0=~endwhile,:
     39 endif
     40 let b:undo_indent="setlocal lisp< si< ai< inde< indk<"
     41 
     42 if get(g:,'rapidSpaceIndent',1)
     43  " Use spaces for indention, 2 is enough. 
     44  " More or even tabs wastes space on the teach pendant.
     45  setlocal softtabstop=2
     46  setlocal shiftwidth=2
     47  setlocal expandtab
     48  setlocal shiftround
     49  let b:undo_indent = b:undo_indent." sts< sw< et< sr<"
     50 endif
     51 
     52 " Only define the function once.
     53 if exists("*GetRapidIndent")
     54  finish
     55 endif
     56 
     57 let s:keepcpo= &cpo
     58 set cpo&vim
     59 
     60 function GetRapidIndent()
     61  let ignorecase_save = &ignorecase
     62  try
     63    let &ignorecase = 0
     64    return s:GetRapidIndentIntern()
     65  finally
     66    let &ignorecase = ignorecase_save
     67  endtry
     68 endfunction
     69 
     70 function s:GetRapidIndentIntern() abort
     71 
     72  let l:currentLineNum = v:lnum
     73  let l:currentLine = getline(l:currentLineNum)
     74 
     75  if  l:currentLine =~ '^!' && !get(g:,'rapidCommentIndent',0)
     76    " If current line is ! line comment, do not change indent
     77    " This may be useful if code is commented out at the first column.
     78    return 0
     79  endif
     80 
     81  " Find a non-blank line above the current line.
     82  let l:preNoneBlankLineNum = s:RapidPreNoneBlank(v:lnum - 1)
     83  if  l:preNoneBlankLineNum == 0
     84    " At the start of the file use zero indent.
     85    return 0
     86  endif
     87 
     88  let l:preNoneBlankLine = getline(l:preNoneBlankLineNum)
     89  let l:ind = indent(l:preNoneBlankLineNum)
     90 
     91  " Define add a 'shiftwidth' pattern
     92  let l:addShiftwidthPattern  = '\c\v^\s*('
     93  let l:addShiftwidthPattern .=           '((local|task)\s+)?(module|record|proc|func|trap)\s+\k'
     94  let l:addShiftwidthPattern .=           '|(backward|error|undo)>'
     95  let l:addShiftwidthPattern .=         ')'
     96  "
     97  " Define Subtract 'shiftwidth' pattern
     98  let l:subtractShiftwidthPattern  = '\c\v^\s*('
     99  let l:subtractShiftwidthPattern .=           'end(module|record|proc|func|trap)>'
    100  let l:subtractShiftwidthPattern .=           '|(backward|error|undo)>'
    101  let l:subtractShiftwidthPattern .=         ')'
    102 
    103  " Add shiftwidth
    104  if l:preNoneBlankLine =~ l:addShiftwidthPattern
    105        \|| s:RapidLenTilStr(l:preNoneBlankLineNum, "then",     0)>=0
    106        \|| s:RapidLenTilStr(l:preNoneBlankLineNum, "else",     0)>=0
    107        \|| s:RapidLenTilStr(l:preNoneBlankLineNum, "do",       0)>=0
    108        \|| s:RapidLenTilStr(l:preNoneBlankLineNum, "case",     0)>=0
    109        \|| s:RapidLenTilStr(l:preNoneBlankLineNum, "default",  0)>=0
    110    let l:ind += &sw
    111  endif
    112 
    113  " Subtract shiftwidth
    114  if l:currentLine =~ l:subtractShiftwidthPattern
    115        \|| s:RapidLenTilStr(l:currentLineNum, "endif",     0)>=0
    116        \|| s:RapidLenTilStr(l:currentLineNum, "endfor",    0)>=0
    117        \|| s:RapidLenTilStr(l:currentLineNum, "endwhile",  0)>=0
    118        \|| s:RapidLenTilStr(l:currentLineNum, "endtest",   0)>=0
    119        \|| s:RapidLenTilStr(l:currentLineNum, "else",      0)>=0
    120        \|| s:RapidLenTilStr(l:currentLineNum, "elseif",    0)>=0
    121        \|| s:RapidLenTilStr(l:currentLineNum, "case",      0)>=0
    122        \|| s:RapidLenTilStr(l:currentLineNum, "default",   0)>=0
    123    let l:ind = l:ind - &sw
    124  endif
    125 
    126  " First case (or default) after a test gets the indent of the test.
    127  if (s:RapidLenTilStr(l:currentLineNum, "case", 0)>=0 || s:RapidLenTilStr(l:currentLineNum, "default", 0)>=0) && s:RapidLenTilStr(l:preNoneBlankLineNum, "test", 0)>=0
    128    let l:ind += &sw
    129  endif
    130 
    131  " continued lines with () or []
    132  let l:OpenSum  = s:RapidLoneParen(l:preNoneBlankLineNum,"(") + s:RapidLoneParen(l:preNoneBlankLineNum,"[")
    133  if get(g:,'rapidNewStyleIndent',0)
    134    let l:CloseSum = s:RapidLoneParen(l:preNoneBlankLineNum,")") + s:RapidLoneParen(l:currentLineNum,"]")
    135  else
    136    let l:CloseSum = s:RapidLoneParen(l:preNoneBlankLineNum,")") + s:RapidLoneParen(l:preNoneBlankLineNum,"]")
    137  endif
    138  if l:OpenSum > l:CloseSum
    139    let l:ind += (l:OpenSum * 4 * &sw)
    140  elseif l:OpenSum < l:CloseSum
    141    let l:ind -= (l:CloseSum * 4 * &sw)
    142  endif
    143 
    144  return l:ind
    145 endfunction
    146 
    147 " Returns the length of the line until a:str occur outside a string or
    148 " comment. Search starts at string index a:startIdx.
    149 " If a:str is a word also add word boundaries and case insensitivity.
    150 " Note: rapidTodoComment and rapidDebugComment are not taken into account.
    151 function s:RapidLenTilStr(lnum, str, startIdx) abort
    152 
    153  let l:line = getline(a:lnum)
    154  let l:len  = strlen(l:line)
    155  let l:idx  = a:startIdx
    156  let l:str  = a:str
    157  if l:str =~ '^\k\+$'
    158    let l:str = '\c\<' . l:str . '\>'
    159  endif
    160 
    161  while l:len > l:idx
    162    let l:idx = match(l:line, l:str, l:idx)
    163    if l:idx < 0
    164      " a:str not found
    165      return -1
    166    endif
    167    let l:synName = synIDattr(synID(a:lnum,l:idx+1,0),"name")
    168    if         l:synName != "rapidString"
    169          \&&  l:synName != "rapidConcealableString"
    170          \&& (l:synName != "rapidComment" || l:str =~ '^!')
    171      " a:str found outside string or line comment
    172      return l:idx
    173    endif
    174    " a:str is part of string or line comment
    175    let l:idx += 1 " continue search for a:str
    176  endwhile
    177  
    178  " a:str not found or l:len <= a:startIdx
    179  return -1
    180 endfunction
    181 
    182 " a:lchar should be one of (, ), [, ], { or }
    183 " returns the number of opening/closing parentheses which have no
    184 " closing/opening match in getline(a:lnum)
    185 function s:RapidLoneParen(lnum,lchar) abort
    186  if a:lchar == "(" || a:lchar == ")"
    187    let l:opnParChar = "("
    188    let l:clsParChar = ")"
    189  elseif a:lchar == "[" || a:lchar == "]"
    190    let l:opnParChar = "["
    191    let l:clsParChar = "]"
    192  elseif a:lchar == "{" || a:lchar == "}"
    193    let l:opnParChar = "{"
    194    let l:clsParChar = "}"
    195  else
    196    return 0
    197  endif
    198 
    199  let l:line = getline(a:lnum)
    200 
    201  " look for the first ! which is not part of a string 
    202  let l:len = s:RapidLenTilStr(a:lnum,"!",0)
    203  if l:len == 0
    204    return 0 " first char is !; ignored
    205  endif
    206 
    207  let l:opnParen = 0
    208  " count opening brackets
    209  let l:i = 0
    210  while l:i >= 0
    211    let l:i = s:RapidLenTilStr(a:lnum, l:opnParChar, l:i)
    212    if l:i >= 0
    213      let l:opnParen += 1
    214      let l:i += 1
    215    endif
    216  endwhile
    217 
    218  let l:clsParen = 0
    219  " count closing brackets
    220  let l:i = 0
    221  while l:i >= 0
    222    let l:i = s:RapidLenTilStr(a:lnum, l:clsParChar, l:i)
    223    if l:i >= 0
    224      let l:clsParen += 1
    225      let l:i += 1
    226    endif
    227  endwhile
    228 
    229  if (a:lchar == "(" || a:lchar == "[" || a:lchar == "{") && l:opnParen>l:clsParen
    230    return (l:opnParen-l:clsParen)
    231  elseif (a:lchar == ")" || a:lchar == "]" || a:lchar == "}") && l:clsParen>l:opnParen
    232    return (l:clsParen-l:opnParen)
    233  endif
    234 
    235  return 0
    236 endfunction
    237 
    238 " This function works almost like prevnonblank() but handles %%%-headers and
    239 " comments like blank lines
    240 function s:RapidPreNoneBlank(lnum) abort
    241 
    242  let nPreNoneBlank = prevnonblank(a:lnum)
    243 
    244  while nPreNoneBlank>0 && getline(nPreNoneBlank) =~ '\v\c^\s*(\%\%\%|!)'
    245    " Previous none blank line irrelevant. Look further aback.
    246    let nPreNoneBlank = prevnonblank(nPreNoneBlank - 1)
    247  endwhile
    248 
    249  return nPreNoneBlank
    250 endfunction
    251 
    252 let &cpo = s:keepcpo
    253 unlet s:keepcpo
    254 
    255 " vim:sw=2 sts=2 et