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