blob: e3318c4d6ec93e4db1791bce71a0b08298790995 [file] [log] [blame]
Maxim Kim21121102024-01-17 03:33:51 +11001vim9script
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
9if exists("b:did_indent")
10 finish
11endif
12b:did_indent = 1
13
14b:undo_indent = 'setlocal cindent< cinoptions< cinkeys< indentexpr<'
15
16setlocal cindent
17setlocal cinoptions=L0,m1,(s,j1,J1,l1,+0,:0,#1
18setlocal cinkeys=0{,0},0),0],!^F,:,o,O
19
20setlocal indentexpr=GetOdinIndent(v:lnum)
21
22def 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
45enddef
46
47def 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
119enddef