pov.vim (2770B)
1 " Vim indent file 2 " Language: PoV-Ray Scene Description Language 3 " Maintainer: David Necas (Yeti) <yeti@physics.muni.cz> 4 " Last Change: 2017 Jun 13 5 " 2022 April: b:undo_indent added by Doug Kearns 6 " URI: http://trific.ath.cx/Ftp/vim/indent/pov.vim 7 8 " Only load this indent file when no other was loaded. 9 if exists("b:did_indent") 10 finish 11 endif 12 let b:did_indent = 1 13 14 " Some preliminary settings. 15 setlocal nolisp " Make sure lisp indenting doesn't supersede us. 16 17 setlocal indentexpr=GetPoVRayIndent() 18 setlocal indentkeys+==else,=end,0] 19 20 let b:undo_indent = "setl inde< indk< lisp<" 21 22 " Only define the function once. 23 if exists("*GetPoVRayIndent") 24 finish 25 endif 26 27 " Counts matches of a regexp <rexp> in line number <line>. 28 " Doesn't count matches inside strings and comments (as defined by current 29 " syntax). 30 function! s:MatchCount(line, rexp) 31 let str = getline(a:line) 32 let i = 0 33 let n = 0 34 while i >= 0 35 let i = matchend(str, a:rexp, i) 36 if i >= 0 && synIDattr(synID(a:line, i, 0), "name") !~? "string\|comment" 37 let n = n + 1 38 endif 39 endwhile 40 return n 41 endfunction 42 43 " The main function. Returns indent amount. 44 function GetPoVRayIndent() 45 " If we are inside a comment (may be nested in obscure ways), give up 46 if synIDattr(synID(v:lnum, indent(v:lnum)+1, 0), "name") =~? "string\|comment" 47 return -1 48 endif 49 50 " Search backwards for the first non-empty, non-comment line. 51 let plnum = prevnonblank(v:lnum - 1) 52 let plind = indent(plnum) 53 while plnum > 0 && synIDattr(synID(plnum, plind+1, 0), "name") =~? "comment" 54 let plnum = prevnonblank(plnum - 1) 55 let plind = indent(plnum) 56 endwhile 57 58 " Start indenting from zero 59 if plnum == 0 60 return 0 61 endif 62 63 " Analyse previous nonempty line. 64 let chg = 0 65 let chg = chg + s:MatchCount(plnum, '[[{(]') 66 let chg = chg + s:MatchCount(plnum, '#\s*\%(if\|ifdef\|ifndef\|switch\|while\|macro\|else\)\>') 67 let chg = chg - s:MatchCount(plnum, '#\s*end\>') 68 let chg = chg - s:MatchCount(plnum, '[]})]') 69 " Dirty hack for people writing #if and #else on the same line. 70 let chg = chg - s:MatchCount(plnum, '#\s*\%(if\|ifdef\|ifndef\|switch\)\>.*#\s*else\>') 71 " When chg > 0, then we opened groups and we should indent more, but when 72 " chg < 0, we closed groups and this already affected the previous line, 73 " so we should not dedent. And when everything else fails, scream. 74 let chg = chg > 0 ? chg : 0 75 76 " Analyse current line 77 " FIXME: If we have to dedent, we should try to find the indentation of the 78 " opening line. 79 let cur = s:MatchCount(v:lnum, '^\s*\%(#\s*\%(end\|else\)\>\|[]})]\)') 80 if cur > 0 81 let final = plind + (chg - cur) * shiftwidth() 82 else 83 let final = plind + chg * shiftwidth() 84 endif 85 86 return final < 0 ? 0 : final 87 endfunction