runtime(luau): runtime support is incomplete
Commit:
https://github.com/vim/vim/commit/8181c6e31387c0467fcd6394d1b7da07f38e737c
Author: Lopy <[email protected]>
Date: Thu Jun 18 19:36:32 2026 +0000
runtime(luau): runtime support is incomplete
Problem: runtime(luau): runtime support is incomplete.
Solution: Add Luau syntax, indent, filetype plugin and indent tests.
closes: #20544
Signed-off-by: Lopy <[email protected]>
Signed-off-by: Christian Brabandt <[email protected]>
diff --git a/.github/MAINTAINERS b/.github/MAINTAINERS
index 6a786bfb1..f0266e772 100644
--- a/.github/MAINTAINERS
+++ b/.github/MAINTAINERS
@@ -255,6 +255,7 @@ runtime/ftplugin/liquid.vim @tpope
runtime/ftplugin/logtalk.dict @pmoura
runtime/ftplugin/logtalk.vim @pmoura
runtime/ftplugin/lua.vim @dkearns
+runtime/ftplugin/luau.vim @lopi-py
runtime/ftplugin/lynx.vim @dkearns
runtime/ftplugin/m17ndb.vim @dseomn
runtime/ftplugin/m3build.vim @dkearns
@@ -420,6 +421,7 @@ runtime/indent/less.vim
@genoma
runtime/indent/liquid.vim @tpope
runtime/indent/logtalk.vim @pmoura
runtime/indent/lua.vim @marcuscf
+runtime/indent/luau.vim @lopi-py
runtime/indent/m17ndb.vim @dseomn
runtime/indent/make.vim @dkearns
runtime/indent/meson.vim @Liambeguin
@@ -609,6 +611,7 @@ runtime/syntax/liquid.vim @tpope
runtime/syntax/log.vim @mao-yining
runtime/syntax/logtalk.vim @pmoura
runtime/syntax/lua.vim @marcuscf
+runtime/syntax/luau.vim @lopi-py
runtime/syntax/lynx.vim @dkearns
runtime/syntax/lyrics.vim @ObserverOfTime
runtime/syntax/m17ndb.vim @dseomn
diff --git a/runtime/doc/filetype.txt b/runtime/doc/filetype.txt
index 61c72fffa..73ce826c1 100644
--- a/runtime/doc/filetype.txt
+++ b/runtime/doc/filetype.txt
@@ -1,4 +1,4 @@
-*filetype.txt* For Vim version 9.2. Last change: 2026 Jun 17
+*filetype.txt* For Vim version 9.2. Last change: 2026 Jun 18
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -890,6 +890,12 @@ For example, to use Lua 5.1, set the variables like this: >
let g:lua_version = 5
let g:lua_subversion = 1
<
+LUAU *ft-luau-plugin* *g:luau_folding*
+
+You can enable folding of Luau block constructs using |fold-expr| by: >
+
+ let g:luau_folding = 1
+<
MAIL *ft-mail-plugin*
Options:
diff --git a/runtime/doc/tags b/runtime/doc/tags
index 40161f75c..1b9575fd9 100644
--- a/runtime/doc/tags
+++ b/runtime/doc/tags
@@ -7634,6 +7634,7 @@ ft-log-syntax syntax.txt /*ft-log-syntax*
ft-lpc-syntax syntax.txt /*ft-lpc-syntax*
ft-lua-plugin filetype.txt /*ft-lua-plugin*
ft-lua-syntax syntax.txt /*ft-lua-syntax*
+ft-luau-plugin filetype.txt /*ft-luau-plugin*
ft-mail-plugin filetype.txt /*ft-mail-plugin*
ft-mail.vim syntax.txt /*ft-mail.vim*
ft-make-syntax syntax.txt /*ft-make-syntax*
@@ -7898,6 +7899,7 @@ g:lf_shell_syntax syntax.txt /*g:lf_shell_syntax*
g:lua_folding filetype.txt /*g:lua_folding*
g:lua_subversion filetype.txt /*g:lua_subversion*
g:lua_version filetype.txt /*g:lua_version*
+g:luau_folding filetype.txt /*g:luau_folding*
g:markdown_fenced_languages syntax.txt /*g:markdown_fenced_languages*
g:markdown_minlines syntax.txt /*g:markdown_minlines*
g:markdown_syntax_conceal syntax.txt /*g:markdown_syntax_conceal*
diff --git a/runtime/ftplugin/luau.vim b/runtime/ftplugin/luau.vim
index 458d0b05a..9b413e677 100644
--- a/runtime/ftplugin/luau.vim
+++ b/runtime/ftplugin/luau.vim
@@ -1,14 +1,193 @@
" Vim filetype plugin file
-" Language: Luau
-" Maintainer: None yet
-" Last Change: 2023 Apr 30
+" Language: Luau
+" Maintainer: Lopy (@lopi-py)
+" Last Change: 2026 Jun 16
if exists("b:did_ftplugin")
finish
endif
+let b:did_ftplugin = 1
-" Luau is a superset of Lua
-runtime! ftplugin/lua.vim
+let s:cpo_save = &cpo
+set cpo&vim
+setlocal comments=:---,:--
+setlocal commentstring=--\ %s
+setlocal formatoptions-=t formatoptions+=croql
-" vim: nowrap sw=2 sts=2 ts=8
+let &l:define =
'\<\%(function\|local\%(\s\+function\)\=\|const\%(\s\+function\)\=\|type\%(\s\+function\)\=\|export\s\+type\%(\s\+function\)\=\|class\|declare\s\+\%(function\|class\|extern\s\+type\)\)\>'
+let &l:include = '\<require\s*('
+setlocal includeexpr=s:LuauInclude(v:fname)
+setlocal suffixesadd=.luau,.lua
+
+let b:undo_ftplugin = "setl cms< com< def< fo< inc< inex< sua<"
+
+let s:attr = '@\%(\h\w*\|\[[^]]*\]\)\s*'
+let s:line_end = '\s*\%(--.*\)\=$'
+let s:end_pat = '^\s*end\>' .. s:line_end
+let s:end_block = '^\s*\%(' .. s:attr .. '\)*if\>.\{-}\<then\>' ..
+ \ '\|^\s*\%(' .. s:attr .. '\)*class\>\s\+\h' ..
+ \ '\|^\s*\%(' .. s:attr .. '\)*declare\s\+class\>\s\+\h' ..
+ \ '\|^\s*\%(' .. s:attr .. '\)*declare\s\+extern\s\+type\>.\{-}\<with\>'
.. s:line_end
+
+if exists("loaded_matchit") && !exists("b:match_words")
+ let b:match_ignorecase = 0
+ let s:match_tail = ':\<return\>\|^\s*\%(else\|elseif\)\>:' .. s:end_pat ..
+ \ ',^\s*repeat\>:\<until\>,' ..
+ \ '\%(--\)\=\[\(=*\)\[:\] \]'
+ let s:match_words = '\<\%(do\|function\)\>\|' .. s:end_block .. s:match_tail
+ let s:match_words_no_function = '\<do\>\|' .. s:end_block .. s:match_tail
+ let b:match_words = "LuauMatchWords()"
+ let b:match_skip = 'LuauMatchSkip()'
+ let b:undo_ftplugin ..= " | unlet! b:match_words b:match_ignorecase
b:match_skip"
+endif
+
+if (has("gui_win32") || has("gui_gtk")) && !exists("b:browsefilter")
+ let b:browsefilter = "Luau Source Files (*.luau) *.luau
"
+ if has("win32")
+ let b:browsefilter ..= "All Files (*.*) *
"
+ else
+ let b:browsefilter ..= "All Files (*) *
"
+ endif
+ let b:undo_ftplugin ..= " | unlet! b:browsefilter"
+endif
+
+if has("folding") && get(g:, "luau_folding", 0)
+ setlocal foldmethod=expr
+ setlocal foldexpr=s:LuauFold()
+ let b:luau_lasttick = -1
+ let b:undo_ftplugin ..= " | setl foldexpr< foldmethod< | unlet!
b:luau_lasttick b:luau_foldlists"
+endif
+
+" the rest of the file needs to be sourced only once per Vim session
+if exists("s:loaded_luau") || &cp
+ let &cpo = s:cpo_save
+ unlet s:cpo_save
+ finish
+endif
+let s:loaded_luau = 1
+
+function s:LuauInclude(fname) abort
+ let fname = a:fname
+ if fname =~# '^@'
+ return fname
+ endif
+ for path in [fname, fname .. ".luau", fname .. ".lua", fname ..
"/init.luau", fname .. "/init.lua"]
+ if filereadable(path)
+ return path
+ endif
+ endfor
+ return fname
+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: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 LuauMatchSkip() abort
+ let lnum = line(".")
+ let col = col(".")
+ let comment = s:LineCommentStart(lnum)
+ return s:IsStringOrComment(lnum, col)
+ \ || (comment != -1 && col > comment)
+ \ || (expand("<cword>") ==# "function" && s:InDeclareClass(lnum))
+endfunction
+
+function LuauMatchWords() abort
+ if exists("s:match_words_no_function")
+ \ && expand("<cword>") ==# "function" && s:InDeclareClass(line("."))
+ return s:match_words_no_function
+ endif
+ return get(s:, "match_words", "")
+endfunction
+
+let s:fold_guard = '^\s*\%(@\|\%(do\|if\|repeat\|for\|while\|public' ..
+ \ '\|function\|return\|local\|const\|type\|export\|class' ..
+ \ '\|declare\|end\|until\)\>\)'
+
+let s:patterns = [
+ \ ['^\s*do\>' .. s:line_end, s:end_pat, 'block'],
+ \ ['^\s*if\>.\{-}\<then\>' .. s:line_end, s:end_pat, 'block'],
+ \ ['^\s*repeat\>' .. s:line_end, '^\s*until\>.*', 'block'],
+ \ ['^\s*for\>.\{-}\<do\>' .. s:line_end, s:end_pat, 'block'],
+ \ ['^\s*while\>.\{-}\<do\>' .. s:line_end, s:end_pat, 'block'],
+ \ ['^\s*\%(' .. s:attr .. '\)*\%(public\s\+\)\=function\>.*', s:end_pat,
'function'],
+ \ ['^\s*return\s\+function\>.*', s:end_pat, 'function'],
+ \ ['^\s*\%(' .. s:attr .. '\)*local\s\+function\>.*', s:end_pat,
'function'],
+ \ ['^\s*\%(' .. s:attr .. '\)*const\s\+function\>.*', s:end_pat,
'function'],
+ \ ['^\s*\%(' .. s:attr .. '\)*\%(export\s\+\)\=type\s\+function\>.*',
s:end_pat, 'function'],
+ \ ['^\s*class\>\s\+\h.*', s:end_pat, 'class'],
+ \ ['^\s*declare\s\+class\>\s\+\h.*', s:end_pat, 'declare_class'],
+ \ ['^\s*declare\s\+extern\s\+type\>.\{-}\<with\>' .. s:line_end,
s:end_pat, 'block'],
+ \ ]
+
+function s:LuauFold() abort
+ if b:luau_lasttick == b:changedtick
+ return b:luau_foldlists[v:lnum - 1]
+ endif
+ let b:luau_lasttick = b:changedtick
+
+ let b:luau_foldlists = []
+ let foldlist = []
+ let buf = getline(1, "$")
+ for line in buf
+ let open = 0
+ let end = 0
+ if line !~# s:fold_guard
+ call add(b:luau_foldlists, "" .. len(foldlist))
+ continue
+ endif
+ for t in s:patterns
+ let tagopen = t[0]
+ let tagend = t[1]
+ if line =~# tagopen
+ if t[2] ==# 'function' && len(foldlist) > 0 && foldlist[-1][2] ==#
'declare_class'
+ continue
+ endif
+ call add(foldlist, t)
+ let open = 1
+ break
+ elseif line =~# tagend
+ if len(foldlist) > 0 && line =~# foldlist[-1][1]
+ call remove(foldlist, -1)
+ let end = 1
+ else
+ let foldlist = []
+ endif
+ break
+ endif
+ endfor
+ let prefix = ""
+ if open == 1 | let prefix = ">" | endif
+ if end == 1 | let prefix = "<" | endif
+ call add(b:luau_foldlists, prefix .. (len(foldlist) + end))
+ endfor
+
+ return b:luau_foldlists[v:lnum - 1]
+endfunction
+
+let &cpo = s:cpo_save
+unlet s:cpo_save
+
+" vim: nowrap sw=2 sts=2 ts=8 noet:
diff --git a/runtime/indent/luau.vim b/runtime/indent/luau.vim
index 69893f739..a7422acf3 100644
--- a/runtime/indent/luau.vim
+++ b/runtime/indent/luau.vim
@@ -1,14 +1,153 @@
-" Vim filetype indent file
-" Language: Luau
-" Maintainer: None yet
-" Last Change: 2023 Apr 30
+" Vim indent file
+" Language: Luau
+" Maintainer: Lopy (@lopi-py)
+" Last Change: 2026 Jun 17
-" Only load this indent file when no other was loaded.
+" only load this indent file when no other was loaded
if exists("b:did_indent")
- finish
+ finish
endif
+let b:did_indent = 1
-" Luau is a superset of Lua
-runtime! indent/lua.vim
+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:
diff --git a/runtime/indent/testdir/luau.in b/runtime/indent/testdir/luau.in
new file mode 100644
index 000000000..0d3a4afaa
--- /dev/null
+++ b/runtime/indent/testdir/luau.in
@@ -0,0 +1,101 @@
+-- vim: set ft=luau sw=2 noet:
+
+-- START_INDENT
+@native
+function compute<T>(values: {T}): number
+local total: number = 0
+for _, value: T in values do
+if value then
+continue
+else
+total += 1
+end
+end
+return total
+end
+
+local function typed(
+name: string,
+count: number
+): boolean
+return count > 0
+end
+
+function singletonReturn(): "end"
+print("string singleton return")
+end
+
+if ready then -- end in a comment
+print("comment closer ignored")
+end
+
+local oneline = function() end
+local afterOneline = oneline
+
+declare function PluginManager(): PluginManager
+local afterDeclareFunction = true
+
+declare function WithArgs(
+arg: string
+): boolean
+local afterDeclareFunctionArgs = true
+
+local text = `function(`
+local afterText = text
+
+-- function(
+local afterLineComment = text
+
+class = makeClass()
+local afterClassIdentifier = class
+
+export type Box<T> = {
+read value: T,
+write name: string,
+callback: (T) -> (),
+}
+
+const function makeBox<T>(value: T): Box<T>
+return {
+value = value,
+name = `box {tostring(value)}`,
+callback = function(item: T)
+print(item)
+end,
+}
+end
+
+declare extern type Vector with
+x: number
+y: number
+z: number
+end
+
+declare class EnumItem extends Enum
+@deprecated
+function IsA(self, enumName: string): boolean
+Name: string
+end
+
+type function Optionalize(t)
+return types.optional(t)
+end
+
+local choice = if 2 == 3 then 4 else 5
+local raw = [=[
+if true then
+]=]
+local afterRaw = choice
+
+--[=[
+function ignored()
+]=]
+local afterComment = raw
+
+class Widget
+public Name: string
+public function Describe(self): string
+return `Widget {self.Name}`
+end
+end
+-- END_INDENT
diff --git a/runtime/indent/testdir/luau.ok b/runtime/indent/testdir/luau.ok
new file mode 100644
index 000000000..d38b79525
--- /dev/null
+++ b/runtime/indent/testdir/luau.ok
@@ -0,0 +1,101 @@
+-- vim: set ft=luau sw=2 noet:
+
+-- START_INDENT
+@native
+function compute<T>(values: {T}): number
+ local total: number = 0
+ for _, value: T in values do
+ if value then
+ continue
+ else
+ total += 1
+ end
+ end
+ return total
+end
+
+local function typed(
+ name: string,
+ count: number
+): boolean
+ return count > 0
+end
+
+function singletonReturn(): "end"
+ print("string singleton return")
+end
+
+if ready then -- end in a comment
+ print("comment closer ignored")
+end
+
+local oneline = function() end
+local afterOneline = oneline
+
+declare function PluginManager(): PluginManager
+local afterDeclareFunction = true
+
+declare function WithArgs(
+ arg: string
+): boolean
+local afterDeclareFunctionArgs = true
+
+local text = `function(`
+local afterText = text
+
+-- function(
+local afterLineComment = text
+
+class = makeClass()
+local afterClassIdentifier = class
+
+export type Box<T> = {
+ read value: T,
+ write name: string,
+ callback: (T) -> (),
+}
+
+const function makeBox<T>(value: T): Box<T>
+ return {
+ value = value,
+ name = `box {tostring(value)}`,
+ callback = function(item: T)
+ print(item)
+ end,
+ }
+end
+
+declare extern type Vector with
+ x: number
+ y: number
+ z: number
+end
+
+declare class EnumItem extends Enum
+ @deprecated
+ function IsA(self, enumName: string): boolean
+ Name: string
+end
+
+type function Optionalize(t)
+ return types.optional(t)
+end
+
+local choice = if 2 == 3 then 4 else 5
+local raw = [=[
+if true then
+]=]
+local afterRaw = choice
+
+--[=[
+function ignored()
+]=]
+local afterComment = raw
+
+class Widget
+ public Name: string
+ public function Describe(self): string
+ return `Widget {self.Name}`
+ end
+end
+-- END_INDENT
diff --git a/runtime/syntax/luau.vim b/runtime/syntax/luau.vim
index 59eccac10..e5b3490ee 100644
--- a/runtime/syntax/luau.vim
+++ b/runtime/syntax/luau.vim
@@ -1,15 +1,193 @@
" Vim syntax file
-" Language: Luau
-" Maintainer: None yet
-" Last Change: 2023 Apr 30
+" Language: Luau
+" Maintainer: Lopy (@lopi-py)
+" Last Change: 2026 Jun 17
+" quit when a syntax file was already loaded
if exists("b:current_syntax")
finish
endif
-" Luau is a superset of lua
-runtime! syntax/lua.vim
+let s:cpo_save = &cpo
+set cpo&vim
+
+syn case match
+syn sync minlines=300
+
+" comments
+syn keyword luauTodo contained TODO FIXME
+syn match luauDirective contained
"--!\%(strict\|nonstrict\|nocheck\|nolint\%(Global\)\=\|native\|optimize\)\>.*"
+
+" strings
+syn match luauSpecial contained
#\[[:digit:]]\{1,3}\|\x[[:xdigit:]]\{2}\|\u{[[:xdigit:]]\+}\|\z\s*\|\
\|\[^xu[:digit:]
]#
+syn region luauString2 matchgroup=luauStringDelimiter start="\[\z(=*\)\["
end="\]\z1\]" contains=@Spell
+syn region luauString matchgroup=luauStringDelimiter start=+'+ end=+'+
skip=+\\\|\'+ contains=luauSpecial,@Spell
+syn region luauString matchgroup=luauStringDelimiter start=+"+ end=+"+
skip=+\\\|\"+ contains=luauSpecial,@Spell
+syn region luauInterpString matchgroup=luauStringDelimiter start=+`+ end=+`+
skip=+\`+ contains=luauSpecial,luauInterp,@Spell
+syn region luauInterp contained transparent matchgroup=luauInterpDelimiter
start=+\\@<!{+ end=+}+ contains=TOP,luauInterpBlock
+syn region luauInterpBlock contained transparent start=+{+ end=+}+
contains=TOP,luauInterpBlock
+
+" numbers
+syn match luauNumber "\<0_*[xX][[:xdigit:]_]*[[:xdigit:]][[:xdigit:]_]*\>"
+syn match luauNumber "\<0_*[bB][01_]*[01][01_]*\>"
+syn match luauNumber
"\<\d[[:digit:]_]*\%(\.[[:digit:]_]*\)\=\%([eE][-+]\=[[:digit:]_]*\d[[:digit:]_]*\)\=\>"
+syn match luauNumber
"\.\d[[:digit:]_]*\%([eE][-+]\=[[:digit:]_]*\d[[:digit:]_]*\)\=\>"
+
+" keywords
+syn keyword luauStatement return local break end
+syn keyword luauStatement do nextgroup=luauStatement skipwhite
+syn keyword luauStatement contained continue
+syn match luauStatement
"^\s*\zscontinue\>\ze\s*\%(;\|end\>\|else\>\|elseif\>\|until\>\|--.*\|$\)"
+syn match luauStatement
";\s*\zscontinue\>\ze\s*\%(;\|end\>\|else\>\|elseif\>\|until\>\|--.*\|$\)"
+syn keyword luauFunction function nextgroup=luauFunctionName,luauGenericParams
skipwhite
+syn match luauStatement
"^\s*\%(@\%(\h\w*\|\[[^]]*\]\)\s*\)*\zsconst\>\ze\s\+\%(function\>\|\h\)"
+syn match luauStatement
"^\s*\%(@\%(\h\w*\|\[[^]]*\]\)\s*\)*\zsdeclare\>\ze\s\+\%(function\>\|class\>\s\+\h\|extern\s\+type\>\|\h\w*\s*:\)"
nextgroup=luauStatement,luauDeclareName,luauFunction skipwhite
+syn match luauStatement contained "\<class\>\ze\s\+\h" nextgroup=luauTypedef
skipwhite
+syn match luauDeclareName contained "\h\w*\ze\s*:" nextgroup=luauTypeColon
skipwhite
+syn match luauStatement "\<export\>\ze\s\+type\>"
+syn match luauStatement contained "\<extern\>\ze\s\+type\>"
+syn match luauStatement "\<extends\>\ze\s\+\h" nextgroup=luauTypeName
skipwhite
+syn match luauStatement "\<with\>\ze\s*\%(--.*\)\=$"
+syn match luauModifier "\<public\>\ze\s\+\%(function\|\h\)"
+syn match luauTypeKeyword "\<type\>\ze\s\+\h"
nextgroup=luauTypeFunction,luauTypedef skipwhite
+syn keyword luauTypeFunction contained function nextgroup=luauFunctionName
skipwhite
+syn match luauFunctionName contained transparent "\h\w*\%([.:]\h\w*\)*"
nextgroup=luauGenericParams skipwhite
+syn keyword luauCond if elseif
+syn keyword luauCond then else nextgroup=luauStatement skipwhite
+syn keyword luauRepeat while for until in
+syn keyword luauRepeat repeat nextgroup=luauStatement skipwhite
+syn keyword luauOperator and or not
+
+" operators and punctuation
+syn match luauSymbolOperator "[#+*/%^=<>~?-]\|\.\{3}\|\.\.=\="
+syn match luauSymbolOperator "->"
nextgroup=luauSymbolOperator,luauConstant,luauTableType,luauTypePack,luauTypeName
skipwhite
+syn match luauSymbolOperator "[|&]"
nextgroup=luauConstant,luauTableType,luauTypePack,luauTypeName skipwhite
+syn match luauSymbolOperator "::"
+
+" tables
+syn region luauTableBlock transparent matchgroup=luauTable start="{" end="}"
contains=TOP,luauStatement
+
+syn match luauComment "--.*$" contains=luauTodo,luauDirective,@Spell
+syn region luauComment matchgroup=luauCommentDelimiter start="--\[\z(=*\)\["
end="\]\z1\]" contains=luauTodo,@Spell
+
+" the first line may start with #!
+syn match luauComment "\%^#!.*"
+
+" attributes
+syn match luauAttribute "@\h\w*"
+syn region luauAttributeBlock matchgroup=luauAttributeDelimiter start="@\["
end="\]"
contains=luauAttributeName,luauAttributeTable,luauString,luauString2,luauInterpString,luauNumber,luauConstant
+syn region luauAttributeTable contained transparent matchgroup=luauTable
start="{" end="}"
contains=luauAttributeTable,luauString,luauString2,luauInterpString,luauNumber,luauConstant,luauSymbolOperator
+syn keyword luauAttributeName contained checked native deprecated
+
+" constants and types
+syn keyword luauConstant nil true false
+syn match luauConstant "\.\.\."
+syn keyword luauSelf self
+syn match luauSelf contained "(\s*\zsself\>\ze\s*:"
+syn cluster luauTypeCommon
contains=luauGenericParams,luauString,luauString2,luauInterpString,luauNumber,luauConstant,luauSymbolOperator
+syn cluster luauTypeExpr
contains=luauFunctionTypeParams,luauTableType,luauTypeParam,luauType,luauTypeKeyword,@luauTypeCommon
+syn region luauGenericParams contained transparent
matchgroup=luauSymbolOperator start="<" end=">" contains=@luauTypeExpr
+syn region luauTypedefGenericParams contained transparent
matchgroup=luauSymbolOperator start="<" end=">" contains=@luauTypeExpr
nextgroup=luauTypeAliasAssign skipwhite
+syn region luauExplicitTypeArgs transparent matchgroup=luauSymbolOperator
start="<<" end=">>" contains=@luauTypeExpr
+syn match luauTypeParam contained "\h\w*\%(\.\.\.\)\="
+syn match luauTypedef "\h\w*" contained
nextgroup=luauTypedefGenericParams,luauTypeAliasAssign skipwhite
+syn match luauTypeAliasAssign contained "="
nextgroup=luauSymbolOperator,luauConstant,luauTableType,luauTypeName skipwhite
+syn region luauTableType contained transparent matchgroup=luauTable start="{"
end="}"
contains=luauFunctionTypeParams,luauTableType,luauSelf,luauTypeIndexer,luauTableElementType,luauTypeColon,luauTypeKeyword,@luauTypeCommon
+syn match luauTypeIndexer "^\s*\[\s*" nextgroup=luauType skipwhite
+syn match luauTypeIndexer contained transparent "\[\s*" nextgroup=luauType
skipwhite
+syn match luauType contained "\h\w*\%(\.\h\w*\)*\ze\s*\]\s*:"
nextgroup=luauGenericParams skipwhite
+syn match luauTableElementType contained
"\h\w*\%(\.\h\w*\)*\ze\s*[<?|&,;})]" nextgroup=luauGenericParams skipwhite
+syn match luauTypeColon transparent ":"
nextgroup=luauSymbolOperator,luauConstant,luauTableType,luauTypeAfterColon
skipwhite
+syn match luauTypeAfterColon contained
"\h\w*\%(\.\h\w*\)*\%(\.\.\.\)\=\ze\s*\%([?=},)\]|&]\|,\|<\|->\|$\)"
nextgroup=luauGenericParams skipwhite
+syn region luauFunctionTypeParams transparent start="(\ze\%([^()]*\))\s*->"
end=")\ze\s*->"
contains=luauFunctionTypeParam,luauTypeColon,luauSelf,@luauTypeCommon
+syn match luauFunctionTypeParam contained
"\h\w*\%(\.\h\w*\)*\%(\.\.\.\)\=\ze\s*?\=\s*[,)|&]" nextgroup=luauGenericParams
skipwhite
+syn match luauFunctionReturnStart transparent ")\s*:\s*"
nextgroup=luauSymbolOperator,luauFunctionTypeParams,luauConstant,luauTableType,luauTypePack,luauTypeName
skipwhite
+syn region luauTypePack contained transparent start="(\%([^()]*)\s*->\)\@!"
end=")"
contains=luauFunctionTypeParams,luauTableType,luauTypeName,@luauTypeCommon
+syn match luauTypeName contained "\h\w*\%(\.\h\w*\)*\%(\.\.\.\)\="
nextgroup=luauGenericParams skipwhite
+syn match luauTypeKeyword "\<\%(read\|write\)\>\ze\s*\%(\[\|\h\+\s*:\)"
nextgroup=luauTypeIndexer skipwhite
+
+" metamethods
+syn keyword luauMetaMethod __index __newindex __mode __namecall __call __iter
__len
+syn keyword luauMetaMethod __eq __add __sub __mul __div __idiv __mod __pow
__unm
+syn keyword luauMetaMethod __lt __le __concat __type __metatable __tostring
+
+" methods
+syn match luauMethodColon transparent
":\ze\s*\h\w*\s*\%(<<.\{-}>>\s*\|<[^>]*>\s*\)\=\%((\|{\|'\|\"\|\[\)"
nextgroup=luauFunc skipwhite
+syn match luauFunc contained
"\h\w*\ze\s*\%(<<.\{-}>>\s*\|<[^>]*>\s*\)\=\%((\|{\|'\|\"\|\[\)"
+
+" global functions and values
+syn keyword luauFunc assert error gcinfo getfenv getmetatable
+syn keyword luauFunc ipairs loadstring newproxy next pairs pcall print
+syn keyword luauFunc rawequal rawget rawlen rawset require select setfenv
+syn keyword luauFunc setmetatable tonumber tostring unpack xpcall
+syn keyword luauGlobal _G
+syn keyword luauBuiltinConstant _VERSION
+syn match luauFunc "\<type\>\ze\s*\%(<<.\{-}>>\s*\)\=("
+syn match luauFunc "\<typeof\>\ze\s*\%(<<.\{-}>>\s*\)\=("
+
+" standard library members
+syn match luauFunc
/\<bit32\.\%(arshift\|band\|bnot\|bor\|btest\|bxor\|byteswap\|countlz\|countrz\|extract\|lrotate\|lshift\|replace\|rrotate\|rshift\)\>/
+syn match luauFunc
/\<buffer\.\%(copy\|create\|fill\|fromstring\|len\|readbits\|readf32\|readf64\|readi16\|readi32\|readi8\|readstring\|readu16\|readu32\|readu8\)\>/
+syn match luauFunc
/\<buffer\.\%(tostring\|writebits\|writef32\|writef64\|writei16\|writei32\|writei8\|writestring\|writeu16\|writeu32\|writeu8\)\>/
+syn match luauFunc
/\<coroutine\.\%(close\|create\|isyieldable\|resume\|running\|status\|wrap\|yield\)\>/
+syn match luauFunc /\<debug\.\%(info\|traceback\)\>/
+syn match luauFunc
/\<math\.\%(abs\|acos\|asin\|atan2\=\|ceil\|clamp\|cosh\=\|deg\|exp\|floor\|fmod\|frexp\)\>/
+syn match luauFunc
/\<math\.\%(isfinite\|isinf\|isnan\|ldexp\|lerp\|log\|log10\|map\|max\|min\|modf\|noise\)\>/
+syn match luauFunc
/\<math\.\%(pow\|rad\|random\%(seed\)\=\|round\|sign\|sinh\=\|sqrt\|tanh\=\)\>/
+syn match luauBuiltinConstant /\<math\.\%(huge\|pi\)\>/
+syn match luauFunc /\<os\.\%(clock\|date\|difftime\|time\)\>/
+syn match luauFunc
/\<string\.\%(byte\|char\|find\|format\|gmatch\|gsub\|len\|lower\|match\|pack\%(size\)\=\|rep\|reverse\|split\|sub\|unpack\|upper\)\>/
+syn match luauFunc
/\<table\.\%(clear\|clone\|concat\|create\|find\|foreachi\=\|freeze\|getn\|insert\|isfrozen\|maxn\|move\|pack\|remove\|sort\|unpack\)\>/
+syn match luauFunc /\<utf8\.\%(char\|codepoint\|codes\|len\|offset\)\>/
+syn match luauBuiltinConstant /\<utf8\.charpattern\>/
+syn match luauFunc
/\<vector\.\%(abs\|angle\|ceil\|clamp\|create\|cross\|dot\|floor\|lerp\|magnitude\|max\|min\|normalize\|sign\)\>/
+syn match luauBuiltinConstant /\<vector\.\%(one\|zero\)\>/
+syn match luauFunc
/\<types\.\%(any\|boolean\|buffer\|copy\|generic\|intersectionof\|never\|negationof\|newfunction\|newtable\|number\|optional\|singleton\|string\|thread\|unionof\|unknown\)\>/
+
+" define the default highlighting
+hi def link luauStatement Statement
+hi def link luauRepeat Repeat
+hi def link luauString String
+hi def link luauString2 String
+hi def link luauInterpString String
+hi def link luauStringDelimiter luauString
+hi def link luauInterpDelimiter Special
+hi def link luauNumber Number
+hi def link luauOperator Operator
+hi def link luauSymbolOperator luauOperator
+hi def link luauConstant Constant
+hi def link luauCond Conditional
+hi def link luauFunction Function
+hi def link luauMetaMethod Function
+hi def link luauTable Structure
+hi def link luauComment Comment
+hi def link luauCommentDelimiter luauComment
+hi def link luauDirective PreProc
+hi def link luauTodo Todo
+hi def link luauSpecial SpecialChar
+hi def link luauFunc Identifier
+hi def link luauGlobal Identifier
+hi def link luauBuiltinConstant Constant
+hi def link luauSelf Identifier
+hi def link luauModifier StorageClass
+hi def link luauType Type
+hi def link luauTypeAfterColon luauType
+hi def link luauTableElementType luauType
+hi def link luauTypeAliasAssign luauSymbolOperator
+hi def link luauFunctionTypeParam luauType
+hi def link luauTypeName luauType
+hi def link luauTypedef Typedef
+hi def link luauTypeParam Type
+hi def link luauTypeKeyword Keyword
+hi def link luauTypeFunction luauFunction
+hi def link luauDeclareName Identifier
+hi def link luauAttribute PreProc
+hi def link luauAttributeName PreProc
+hi def link luauAttributeDelimiter PreProc
let b:current_syntax = "luau"
+let &cpo = s:cpo_save
+unlet s:cpo_save
+
" vim: nowrap sw=2 sts=2 ts=8 noet:
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion visit
https://groups.google.com/d/msgid/vim_dev/E1waIfi-004Rga-I3%40256bit.org.