odin.vim 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. " Vim indent plugin file
  2. " Language: Odin
  3. " Maintainer: Maxim Kim <habamax@gmail.com>
  4. " Website: https://github.com/habamax/vim-odin
  5. " Last Change: 2024-01-15
  6. "
  7. " This file has been manually translated from Vim9 script.
  8. if exists("b:did_indent")
  9. finish
  10. endif
  11. let b:did_indent = 1
  12. let s:cpo_save = &cpo
  13. set cpo&vim
  14. let b:undo_indent = 'setlocal cindent< cinoptions< cinkeys< indentexpr<'
  15. setlocal cindent
  16. setlocal cinoptions=L0,m1,(s,j1,J1,l1,+0,:0,#1
  17. setlocal cinkeys=0{,0},0),0],!^F,:,o,O
  18. setlocal indentexpr=s:GetOdinIndent(v:lnum)
  19. function s:PrevLine(lnum) abort
  20. let plnum = a:lnum - 1
  21. while plnum > 1
  22. let plnum = prevnonblank(plnum)
  23. let pline = getline(plnum)
  24. " XXX: take into account nested multiline /* /* */ */ comments
  25. if pline =~# '\*/\s*$'
  26. while getline(plnum) !~# '/\*' && plnum > 1
  27. let plnum -= 1
  28. endwhile
  29. if getline(plnum) =~# '^\s*/\*'
  30. let plnum -= 1
  31. else
  32. break
  33. endif
  34. elseif pline =~# '^\s*//'
  35. let plnum -= 1
  36. else
  37. break
  38. endif
  39. endwhile
  40. return plnum
  41. endfunction
  42. function s:GetOdinIndent(lnum) abort
  43. let plnum = s:PrevLine(a:lnum)
  44. let pline = getline(plnum)
  45. let pindent = indent(plnum)
  46. " workaround of cindent "hang"
  47. " if the previous line looks like:
  48. " : #{}
  49. " : #whatever{whateverelse}
  50. " and variations where : # { } are in the string
  51. " cindent(lnum) hangs
  52. if pline =~# ':\s\+#.*{.*}'
  53. return pindent
  54. endif
  55. let indent = cindent(a:lnum)
  56. let line = getline(a:lnum)
  57. if line =~# '^\s*#\k\+'
  58. if pline =~# '[{:]\s*$'
  59. let indent = pindent + shiftwidth()
  60. else
  61. let indent = pindent
  62. endif
  63. elseif pline =~# 'switch\s.*{\s*$'
  64. let indent = pindent
  65. elseif pline =~# 'case\s*.*,\s*\(//.*\)\?$' " https://github.com/habamax/vim-odin/issues/8
  66. let indent = pindent + matchstr(pline, 'case\s*')->strcharlen()
  67. elseif line =~# '^\s*case\s\+.*,\s*$'
  68. let indent = pindent - shiftwidth()
  69. elseif pline =~# 'case\s*.*:\s*\(//.*\)\?$'
  70. if line !~# '^\s*}\s*$' && line !~# '^\s*case[[:space:]:]'
  71. let indent = pindent + shiftwidth()
  72. endif
  73. elseif pline =~# '^\s*@.*' && line !~# '^\s*}'
  74. let indent = pindent
  75. elseif pline =~# ':[:=].*}\s*$'
  76. let indent = pindent
  77. elseif pline =~# '^\s*}\s*$'
  78. if line !~# '^\s*}' && line !~# 'case\s*.*:\s*$'
  79. let indent = pindent
  80. else
  81. let indent = pindent - shiftwidth()
  82. endif
  83. elseif pline =~# '\S:\s*$'
  84. " looking up for a case something,
  85. " whatever,
  86. " anything:
  87. " ... 20 lines before
  88. for idx in range(plnum - 1, plnum - 21, -1)
  89. if plnum < 1
  90. break
  91. endif
  92. if getline(idx) =~# '^\s*case\s.*,\s*$'
  93. let indent = indent(idx) + shiftwidth()
  94. break
  95. endif
  96. endfor
  97. elseif pline =~# '{[^{]*}\s*$' && line !~# '^\s*[})]\s*$' " https://github.com/habamax/vim-odin/issues/2
  98. let indent = pindent
  99. elseif pline =~# '^\s*}\s*$' " https://github.com/habamax/vim-odin/issues/3
  100. " Find line with opening { and check if there is a label:
  101. " If there is, return indent of the closing }
  102. call cursor(plnum, 1)
  103. silent normal! %
  104. let brlnum = line('.')
  105. let brline = getline('.')
  106. if plnum != brlnum && (brline =~# '^\s*\k\+:\s\+for' || brline =~# '^\s*\k\+\s*:=')
  107. let indent = pindent
  108. endif
  109. endif
  110. return indent
  111. endfunction
  112. let &cpo = s:cpo_save
  113. unlet s:cpo_save