123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 |
- " ABB Rapid Command indent file for Vim
- " Language: ABB Rapid Command
- " Maintainer: Patrick Meiser-Knosowski <knosowski@graeffrobotics.de>
- " Version: 2.2.7
- " Last Change: 12. May 2023
- " Credits: Based on indent/vim.vim
- "
- " Suggestions of improvement are very welcome. Please email me!
- "
- " Known bugs: ../doc/rapid.txt
- "
- " TODO
- " * indent wrapped lines which do not end with an ; or special key word,
- " maybe this is a better idea, but then () and [] has to be changed as
- " well
- "
- if exists("g:rapidNoSpaceIndent")
- if !exists("g:rapidSpaceIndent")
- let g:rapidSpaceIndent = !g:rapidNoSpaceIndent
- endif
- unlet g:rapidNoSpaceIndent
- endif
- " Only load this indent file when no other was loaded.
- if exists("b:did_indent") || get(g:,'rapidNoIndent',0)
- finish
- endif
- let b:did_indent = 1
- setlocal nolisp
- setlocal nosmartindent
- setlocal autoindent
- setlocal indentexpr=GetRapidIndent()
- if get(g:,'rapidNewStyleIndent',0)
- 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,:,<[>,<]>,<(>,<)>
- else
- 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,:
- endif
- let b:undo_indent="setlocal lisp< si< ai< inde< indk<"
- if get(g:,'rapidSpaceIndent',1)
- " Use spaces for indention, 2 is enough.
- " More or even tabs wastes space on the teach pendant.
- setlocal softtabstop=2
- setlocal shiftwidth=2
- setlocal expandtab
- setlocal shiftround
- let b:undo_indent = b:undo_indent." sts< sw< et< sr<"
- endif
- " Only define the function once.
- if exists("*GetRapidIndent")
- finish
- endif
- let s:keepcpo= &cpo
- set cpo&vim
- function GetRapidIndent()
- let ignorecase_save = &ignorecase
- try
- let &ignorecase = 0
- return s:GetRapidIndentIntern()
- finally
- let &ignorecase = ignorecase_save
- endtry
- endfunction
- function s:GetRapidIndentIntern() abort
- let l:currentLineNum = v:lnum
- let l:currentLine = getline(l:currentLineNum)
- if l:currentLine =~ '^!' && !get(g:,'rapidCommentIndent',0)
- " If current line is ! line comment, do not change indent
- " This may be useful if code is commented out at the first column.
- return 0
- endif
- " Find a non-blank line above the current line.
- let l:preNoneBlankLineNum = s:RapidPreNoneBlank(v:lnum - 1)
- if l:preNoneBlankLineNum == 0
- " At the start of the file use zero indent.
- return 0
- endif
- let l:preNoneBlankLine = getline(l:preNoneBlankLineNum)
- let l:ind = indent(l:preNoneBlankLineNum)
- " Define add a 'shiftwidth' pattern
- let l:addShiftwidthPattern = '\c\v^\s*('
- let l:addShiftwidthPattern .= '((local|task)\s+)?(module|record|proc|func|trap)\s+\k'
- let l:addShiftwidthPattern .= '|(backward|error|undo)>'
- let l:addShiftwidthPattern .= ')'
- "
- " Define Subtract 'shiftwidth' pattern
- let l:subtractShiftwidthPattern = '\c\v^\s*('
- let l:subtractShiftwidthPattern .= 'end(module|record|proc|func|trap)>'
- let l:subtractShiftwidthPattern .= '|(backward|error|undo)>'
- let l:subtractShiftwidthPattern .= ')'
- " Add shiftwidth
- if l:preNoneBlankLine =~ l:addShiftwidthPattern
- \|| s:RapidLenTilStr(l:preNoneBlankLineNum, "then", 0)>=0
- \|| s:RapidLenTilStr(l:preNoneBlankLineNum, "else", 0)>=0
- \|| s:RapidLenTilStr(l:preNoneBlankLineNum, "do", 0)>=0
- \|| s:RapidLenTilStr(l:preNoneBlankLineNum, "case", 0)>=0
- \|| s:RapidLenTilStr(l:preNoneBlankLineNum, "default", 0)>=0
- let l:ind += &sw
- endif
- " Subtract shiftwidth
- if l:currentLine =~ l:subtractShiftwidthPattern
- \|| s:RapidLenTilStr(l:currentLineNum, "endif", 0)>=0
- \|| s:RapidLenTilStr(l:currentLineNum, "endfor", 0)>=0
- \|| s:RapidLenTilStr(l:currentLineNum, "endwhile", 0)>=0
- \|| s:RapidLenTilStr(l:currentLineNum, "endtest", 0)>=0
- \|| s:RapidLenTilStr(l:currentLineNum, "else", 0)>=0
- \|| s:RapidLenTilStr(l:currentLineNum, "elseif", 0)>=0
- \|| s:RapidLenTilStr(l:currentLineNum, "case", 0)>=0
- \|| s:RapidLenTilStr(l:currentLineNum, "default", 0)>=0
- let l:ind = l:ind - &sw
- endif
- " First case (or default) after a test gets the indent of the test.
- if (s:RapidLenTilStr(l:currentLineNum, "case", 0)>=0 || s:RapidLenTilStr(l:currentLineNum, "default", 0)>=0) && s:RapidLenTilStr(l:preNoneBlankLineNum, "test", 0)>=0
- let l:ind += &sw
- endif
- " continued lines with () or []
- let l:OpenSum = s:RapidLoneParen(l:preNoneBlankLineNum,"(") + s:RapidLoneParen(l:preNoneBlankLineNum,"[")
- if get(g:,'rapidNewStyleIndent',0)
- let l:CloseSum = s:RapidLoneParen(l:preNoneBlankLineNum,")") + s:RapidLoneParen(l:currentLineNum,"]")
- else
- let l:CloseSum = s:RapidLoneParen(l:preNoneBlankLineNum,")") + s:RapidLoneParen(l:preNoneBlankLineNum,"]")
- endif
- if l:OpenSum > l:CloseSum
- let l:ind += (l:OpenSum * 4 * &sw)
- elseif l:OpenSum < l:CloseSum
- let l:ind -= (l:CloseSum * 4 * &sw)
- endif
- return l:ind
- endfunction
- " Returns the length of the line until a:str occur outside a string or
- " comment. Search starts at string index a:startIdx.
- " If a:str is a word also add word boundaries and case insensitivity.
- " Note: rapidTodoComment and rapidDebugComment are not taken into account.
- function s:RapidLenTilStr(lnum, str, startIdx) abort
- let l:line = getline(a:lnum)
- let l:len = strlen(l:line)
- let l:idx = a:startIdx
- let l:str = a:str
- if l:str =~ '^\k\+$'
- let l:str = '\c\<' . l:str . '\>'
- endif
- while l:len > l:idx
- let l:idx = match(l:line, l:str, l:idx)
- if l:idx < 0
- " a:str not found
- return -1
- endif
- let l:synName = synIDattr(synID(a:lnum,l:idx+1,0),"name")
- if l:synName != "rapidString"
- \&& l:synName != "rapidConcealableString"
- \&& (l:synName != "rapidComment" || l:str =~ '^!')
- " a:str found outside string or line comment
- return l:idx
- endif
- " a:str is part of string or line comment
- let l:idx += 1 " continue search for a:str
- endwhile
-
- " a:str not found or l:len <= a:startIdx
- return -1
- endfunction
- " a:lchar should be one of (, ), [, ], { or }
- " returns the number of opening/closing parentheses which have no
- " closing/opening match in getline(a:lnum)
- function s:RapidLoneParen(lnum,lchar) abort
- if a:lchar == "(" || a:lchar == ")"
- let l:opnParChar = "("
- let l:clsParChar = ")"
- elseif a:lchar == "[" || a:lchar == "]"
- let l:opnParChar = "["
- let l:clsParChar = "]"
- elseif a:lchar == "{" || a:lchar == "}"
- let l:opnParChar = "{"
- let l:clsParChar = "}"
- else
- return 0
- endif
- let l:line = getline(a:lnum)
- " look for the first ! which is not part of a string
- let l:len = s:RapidLenTilStr(a:lnum,"!",0)
- if l:len == 0
- return 0 " first char is !; ignored
- endif
- let l:opnParen = 0
- " count opening brackets
- let l:i = 0
- while l:i >= 0
- let l:i = s:RapidLenTilStr(a:lnum, l:opnParChar, l:i)
- if l:i >= 0
- let l:opnParen += 1
- let l:i += 1
- endif
- endwhile
- let l:clsParen = 0
- " count closing brackets
- let l:i = 0
- while l:i >= 0
- let l:i = s:RapidLenTilStr(a:lnum, l:clsParChar, l:i)
- if l:i >= 0
- let l:clsParen += 1
- let l:i += 1
- endif
- endwhile
- if (a:lchar == "(" || a:lchar == "[" || a:lchar == "{") && l:opnParen>l:clsParen
- return (l:opnParen-l:clsParen)
- elseif (a:lchar == ")" || a:lchar == "]" || a:lchar == "}") && l:clsParen>l:opnParen
- return (l:clsParen-l:opnParen)
- endif
- return 0
- endfunction
- " This function works almost like prevnonblank() but handles %%%-headers and
- " comments like blank lines
- function s:RapidPreNoneBlank(lnum) abort
- let nPreNoneBlank = prevnonblank(a:lnum)
- while nPreNoneBlank>0 && getline(nPreNoneBlank) =~ '\v\c^\s*(\%\%\%|!)'
- " Previous none blank line irrelevant. Look further aback.
- let nPreNoneBlank = prevnonblank(nPreNoneBlank - 1)
- endwhile
- return nPreNoneBlank
- endfunction
- let &cpo = s:keepcpo
- unlet s:keepcpo
- " vim:sw=2 sts=2 et
|