mirror of
https://github.com/neovim/neovim.git
synced 2026-07-23 09:23:09 +00:00
Problem: runtime(luau): runtime support is incomplete.
Solution: Add Luau syntax, indent, filetype plugin and indent tests.
closes: vim/vim#20544
8181c6e313
Co-authored-by: Lopy <70210066+lopi-py@users.noreply.github.com>
154 lines
4.5 KiB
VimL
154 lines
4.5 KiB
VimL
" 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:
|