diff options
Diffstat (limited to 'runtime/indent/odin.vim')
-rw-r--r-- | runtime/indent/odin.vim | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/runtime/indent/odin.vim b/runtime/indent/odin.vim new file mode 100644 index 0000000..e3318c4 --- /dev/null +++ b/runtime/indent/odin.vim @@ -0,0 +1,119 @@ +vim9script + +# Vim indent plugin file +# Language: Odin +# Maintainer: Maxim Kim <habamax@gmail.com> +# 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 |