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