pov.vim 2.6 KB

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