1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
|
" Vim indent file
" Language: Luau
" Maintainer: Lopy (@lopi-py)
" Last Change: 2026 Jun 17
" only load this indent file when no other was loaded
if exists("b:did_indent")
finish
endif
let b:did_indent = 1
let s:cpo_save = &cpo
set cpo&vim
setlocal indentexpr=GetLuauIndent()
" make Vim call GetLuauIndent() when it finds a closing keyword or delimiter
setlocal indentkeys+=0=end,0=until,0=else,0=elseif,0=},0=),0=]
setlocal autoindent
let b:undo_indent = "setlocal autoindent< indentexpr< indentkeys<"
" only define the function once
if exists("*GetLuauIndent")
let &cpo = s:cpo_save
unlet s:cpo_save
finish
endif
function GetLuauIndent() abort
let ignorecase_save = &ignorecase
try
let &ignorecase = 0
return s:GetLuauIndentIntern()
finally
let &ignorecase = ignorecase_save
endtry
endfunction
function s:InDeclareClass(lnum) abort
let save_cursor = getcurpos()
call cursor(a:lnum - 1, 1)
let lnum = search('^\s*\%(end\>\|declare\s\+class\>\)', 'bcnW')
call setpos('.', save_cursor)
return lnum > 0 && getline(lnum) =~# '^\s*declare\s\+class\>'
endfunction
function s:IsStringOrComment(lnum, col) abort
let name = synIDattr(synID(a:lnum, a:col, 1), "name")
return name =~# '^luau\%(Comment\|.*String\)'
endfunction
function s:LineCommentStart(lnum) abort
let line = getline(a:lnum)
let midx = stridx(line, '--')
while midx != -1
if !s:IsStringOrComment(a:lnum, midx + 1)
return midx
endif
let midx = stridx(line, '--', midx + 2)
endwhile
return -1
endfunction
function s:IsCode(lnum, col) abort
let comment = s:LineCommentStart(a:lnum)
return (comment == -1 || a:col <= comment) && !s:IsStringOrComment(a:lnum, a:col)
endfunction
function s:HasBlockCloser(lnum) abort
let line = getline(a:lnum)
let midx = match(line, '\<\%(end\|until\)\>')
while midx != -1
if s:IsCode(a:lnum, midx + 1)
return 1
endif
let midx = match(line, '\<\%(end\|until\)\>', midx + 1)
endwhile
return 0
endfunction
function s:GetLuauIndentIntern() abort
" find a non-blank line above the current line
let prevlnum = prevnonblank(v:lnum - 1)
" hit the start of the file, use zero indent
if prevlnum == 0
return 0
endif
" add a 'shiftwidth' after lines that start a block
let ind = indent(prevlnum)
let prevline = getline(prevlnum)
let attr = '@\%(\h\w*\|\[[^]]*\]\)\s*'
let stmt = 'if\>\|for\>\|while\>\|repeat\>\|else\>\|elseif\>\|do\>\|then\>'
let class = 'class\>\s\+\h\|declare\s\+class\>\s\+\h'
let func = '\%(\%(public\s\+\)\=function\|local\s\+function\|const\s\+function\|type\s\+function\|return\s\+function\)'
let declare_func = '^\s*\%(' .. attr .. '\)*declare\s\+function\>'
let midx = -1
if prevline =~# '^\s*\%(@\|\%(if\|for\|while\|repeat\|else\|elseif\|do\|then\|class\)\>\|declare\s\+class\>\)'
let midx = match(prevline, '^\s*\%(' .. attr .. '\)*\%(' .. stmt .. '\|' .. class .. '\)')
endif
if midx == -1
if prevline =~# '^\s*\%(' .. attr .. '\)*declare\s\+extern\s\+type\>'
let midx = match(prevline, '\<with\>\s*\%(--.*\)\=$')
endif
if midx == -1
let midx = match(prevline, '\%({\|(\|\[\)\s*\%(--\%([^[].*\)\?\)\?$')
if midx == -1 && stridx(prevline, 'function') != -1 && prevline !~# declare_func
let midx = match(prevline, '\<' .. func .. '\>\s*\%(\k\|[.:]\)\{-}\s*\%(<[^>]*>\s*\)\=(')
endif
endif
endif
if midx == -1 && prevline =~ '^\s*)\s*\%(:.\+\)\=\s*\%(--.*\)\=$'
let save_cursor = getcurpos()
call cursor(prevlnum, match(prevline, ')') + 1)
let [par_lnum, par_col] = searchpairpos('(', '', ')', 'bnW')
call setpos('.', save_cursor)
if par_lnum > 0
let funline = getline(par_lnum)
let funidx = match(funline, '\<' .. func .. '\>')
if funidx != -1 && funidx < par_col && funline !~# declare_func
let midx = match(prevline, ')')
endif
endif
endif
if midx != -1
" add 'shiftwidth' if this is not in a comment or string and the block
" does not close on the same line
if s:IsCode(prevlnum, midx + 1) && !s:HasBlockCloser(prevlnum)
\ && !(prevline =~# '^\s*\%(public\s\+\)\=function\>' && s:InDeclareClass(prevlnum))
let ind = ind + shiftwidth()
endif
endif
" subtract a 'shiftwidth' on end, else, elseif, until, '}', ')' and ']'
let midx = match(getline(v:lnum), '^\s*\%(end\>\|else\>\|elseif\>\|until\>\|}\|)\|\]\)')
if midx != -1
if s:IsCode(v:lnum, midx + 1)
let ind = ind - shiftwidth()
endif
endif
return ind
endfunction
let &cpo = s:cpo_save
unlet s:cpo_save
" vim: nowrap sw=2 sts=2 ts=8 noet:
|