vim9script # Vim indent plugin file # Language: Odin # Maintainer: Maxim Kim # Website: https://github.com/habamax/vim-odin # Last Change: 2024-01-15 if exists("b:did_indent") finish endif b:did_indent = 1 b:undo_indent = 'setlocal cindent< cinoptions< cinkeys< indentexpr<' setlocal cindent setlocal cinoptions=L0,m1,(s,j1,J1,l1,+0,:0,#1 setlocal cinkeys=0{,0},0),0],!^F,:,o,O setlocal indentexpr=GetOdinIndent(v:lnum) def PrevLine(lnum: number): number var plnum = lnum - 1 var pline: string while plnum > 1 plnum = prevnonblank(plnum) pline = getline(plnum) # XXX: take into account nested multiline /* /* */ */ comments if pline =~ '\*/\s*$' while getline(plnum) !~ '/\*' && plnum > 1 plnum -= 1 endwhile if getline(plnum) =~ '^\s*/\*' plnum -= 1 else break endif elseif pline =~ '^\s*//' plnum -= 1 else break endif endwhile return plnum enddef def GetOdinIndent(lnum: number): number var plnum = PrevLine(lnum) var pline = getline(plnum) var pindent = indent(plnum) # workaround of cindent "hang" # if the previous line looks like: # : #{} # : #whatever{whateverelse} # and variations where : # { } are in the string # cindent(lnum) hangs if pline =~ ':\s\+#.*{.*}' return pindent endif var indent = cindent(lnum) var line = getline(lnum) if line =~ '^\s*#\k\+' if pline =~ '[{:]\s*$' indent = pindent + shiftwidth() else indent = pindent endif elseif pline =~ 'switch\s.*{\s*$' indent = pindent elseif pline =~ 'case\s*.*,\s*\(//.*\)\?$' # https://github.com/habamax/vim-odin/issues/8 indent = pindent + matchstr(pline, 'case\s*')->strcharlen() elseif line =~ '^\s*case\s\+.*,\s*$' indent = pindent - shiftwidth() elseif pline =~ 'case\s*.*:\s*\(//.*\)\?$' if line !~ '^\s*}\s*$' && line !~ '^\s*case[[:space:]:]' indent = pindent + shiftwidth() endif elseif pline =~ '^\s*@.*' && line !~ '^\s*}' indent = pindent elseif pline =~ ':[:=].*}\s*$' indent = pindent elseif pline =~ '^\s*}\s*$' if line !~ '^\s*}' && line !~ 'case\s*.*:\s*$' indent = pindent else indent = pindent - shiftwidth() endif elseif pline =~ '\S:\s*$' # looking up for a case something, # whatever, # anything: # ... 20 lines before for idx in range(plnum - 1, plnum - 21, -1) if plnum < 1 break endif if getline(idx) =~ '^\s*case\s.*,\s*$' indent = indent(idx) + shiftwidth() break endif endfor elseif pline =~ '{[^{]*}\s*$' && line !~ '^\s*[})]\s*$' # https://github.com/habamax/vim-odin/issues/2 indent = pindent elseif pline =~ '^\s*}\s*$' # https://github.com/habamax/vim-odin/issues/3 # Find line with opening { and check if there is a label: # If there is, return indent of the closing } cursor(plnum, 1) silent normal! % var brlnum = line('.') var brline = getline('.') if plnum != brlnum && (brline =~ '^\s*\k\+:\s\+for' || brline =~ '^\s*\k\+\s*:=') indent = pindent endif endif return indent enddef