summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/checkPR.yml16
-rw-r--r--.gitmodules3
-rw-r--r--.luarc.json10
-rw-r--r--.vscode/launch.json8
-rw-r--r--README.md13
-rw-r--r--changelog.md25
-rw-r--r--locale/en-us/script.lua11
-rw-r--r--locale/pt-br/meta.lua429
-rw-r--r--locale/pt-br/script.lua270
-rw-r--r--locale/zh-cn/script.lua5
-rw-r--r--meta/3rd/lovr/config.lua9
-rw-r--r--meta/3rd/lovr/library/callback.lua115
-rw-r--r--meta/3rd/lovr/library/lovr.audio.lua495
-rw-r--r--meta/3rd/lovr/library/lovr.data.lua387
-rw-r--r--meta/3rd/lovr/library/lovr.event.lua387
-rw-r--r--meta/3rd/lovr/library/lovr.filesystem.lua197
-rw-r--r--meta/3rd/lovr/library/lovr.graphics.lua2055
-rw-r--r--meta/3rd/lovr/library/lovr.headset.lua511
-rw-r--r--meta/3rd/lovr/library/lovr.lovr.lua15
-rw-r--r--meta/3rd/lovr/library/lovr.lua28
-rw-r--r--meta/3rd/lovr/library/lovr.math.lua791
-rw-r--r--meta/3rd/lovr/library/lovr.physics.lua1284
-rw-r--r--meta/3rd/lovr/library/lovr.system.lua34
-rw-r--r--meta/3rd/lovr/library/lovr.thread.lua114
-rw-r--r--meta/3rd/lovr/library/lovr.timer.lua43
-rw-r--r--meta/3rd/skynet/library/skynet.lua91
-rw-r--r--meta/template/basic.lua26
-rw-r--r--meta/template/bit.lua30
-rw-r--r--meta/template/bit32.lua12
-rw-r--r--meta/template/coroutine.lua13
-rw-r--r--meta/template/debug.lua30
-rw-r--r--meta/template/ffi.lua10
-rw-r--r--meta/template/io.lua15
-rw-r--r--meta/template/jit.lua1
-rw-r--r--meta/template/math.lua38
-rw-r--r--meta/template/os.lua6
-rw-r--r--meta/template/package.lua1
-rw-r--r--meta/template/string.lua25
-rw-r--r--meta/template/table.lua4
-rw-r--r--meta/template/utf8.lua8
-rw-r--r--script/await.lua9
-rw-r--r--script/client.lua19
-rw-r--r--script/config/config.lua2
-rw-r--r--script/config/loader.lua22
-rw-r--r--script/core/code-action.lua40
-rw-r--r--script/core/command/autoRequire.lua4
-rw-r--r--script/core/command/jsonToLua.lua1
-rw-r--r--script/core/command/removeSpace.lua1
-rw-r--r--script/core/command/solve.lua1
-rw-r--r--script/core/completion.lua212
-rw-r--r--script/core/diagnostics/await-in-sync.lua30
-rw-r--r--script/core/diagnostics/deprecated.lua3
-rw-r--r--script/core/diagnostics/discard-returns.lua29
-rw-r--r--script/core/diagnostics/duplicate-doc-class.lua3
-rw-r--r--script/core/diagnostics/init.lua1
-rw-r--r--script/core/diagnostics/not-yieldable.lua63
-rw-r--r--script/core/diagnostics/redundant-value.lua3
-rw-r--r--script/core/diagnostics/type-check.lua30
-rw-r--r--script/core/diagnostics/undefined-doc-param.lua3
-rw-r--r--script/core/diagnostics/undefined-field.lua2
-rw-r--r--script/core/diagnostics/undefined-global.lua3
-rw-r--r--script/core/diagnostics/unused-function.lua4
-rw-r--r--script/core/document-symbol.lua6
-rw-r--r--script/core/folding.lua3
-rw-r--r--script/core/generic.lua2
-rw-r--r--script/core/hint.lua44
-rw-r--r--script/core/hover/arg.lua22
-rw-r--r--script/core/hover/init.lua8
-rw-r--r--script/core/hover/label.lua14
-rw-r--r--script/core/hover/table.lua1
-rw-r--r--script/core/infer.lua2
-rw-r--r--script/core/noder.lua40
-rw-r--r--script/core/semantic-tokens.lua3
-rw-r--r--script/core/signature.lua5
-rw-r--r--script/core/workspace-symbol.lua1
-rw-r--r--script/files.lua30
-rw-r--r--script/filewatch.lua1
-rw-r--r--script/glob/gitignore.lua3
-rw-r--r--script/global.d.lua7
-rw-r--r--script/library.lua5
-rw-r--r--script/parser/luadoc.lua111
-rw-r--r--script/parser/newparser.lua22
-rw-r--r--script/plugin.lua5
-rw-r--r--script/proto/converter.lua5
-rw-r--r--script/proto/define.lua6
-rw-r--r--script/proto/proto.lua26
-rw-r--r--script/provider/capability.lua1
-rw-r--r--script/provider/diagnostic.lua36
-rw-r--r--script/provider/provider.lua1463
-rw-r--r--script/pub/pub.lua1
-rw-r--r--script/service/telemetry.lua2
-rw-r--r--script/utility.lua1
-rw-r--r--script/vm/eachDef.lua2
-rw-r--r--script/vm/eachRef.lua2
-rw-r--r--script/vm/getDocs.lua136
-rw-r--r--script/vm/getGlobals.lua2
-rw-r--r--script/vm/getLinks.lua2
-rw-r--r--script/vm/vm.lua2
-rw-r--r--script/workspace/require-path.lua8
-rw-r--r--script/workspace/workspace.lua24
-rw-r--r--test/completion/common.lua9
-rw-r--r--test/completion/init.lua1
-rw-r--r--test/crossfile/completion.lua109
-rw-r--r--test/crossfile/definition.lua25
-rw-r--r--test/crossfile/diagnostic.lua1
-rw-r--r--test/crossfile/hover.lua3
-rw-r--r--test/definition/luadoc.lua5
-rw-r--r--test/diagnostics/init.lua179
-rw-r--r--test/document_symbol/init.lua1
-rw-r--r--test/full/example.lua1
-rw-r--r--test/full/projects.lua1
-rw-r--r--test/full/self.lua1
-rw-r--r--test/hover/init.lua79
-rw-r--r--test/signature/init.lua3
-rw-r--r--test/type_inference/init.lua5
-rw-r--r--tools/build-3rd-meta.lua4
-rw-r--r--tools/love-api.lua3
-rw-r--r--tools/lovr-api.lua234
118 files changed, 9707 insertions, 1061 deletions
diff --git a/.github/workflows/checkPR.yml b/.github/workflows/checkPR.yml
new file mode 100644
index 00000000..c83bf3ab
--- /dev/null
+++ b/.github/workflows/checkPR.yml
@@ -0,0 +1,16 @@
+name: checkPR
+on: pull_request
+jobs:
+ compile:
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [windows-latest, ubuntu-18.04, macos-latest]
+ steps:
+ - uses: actions/checkout@v1
+ with:
+ ref: ${{ github.event.pull_request.head.sha }}
+ submodules : recursive
+ - uses: actboy168/setup-luamake@master
+ - run: luamake
diff --git a/.gitmodules b/.gitmodules
index 92e225d5..0a1d17a8 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -13,3 +13,6 @@
[submodule "3rd/love-api"]
path = 3rd/love-api
url = https://github.com/love2d-community/love-api
+[submodule "3rd/lovr-api"]
+ path = 3rd/lovr-api
+ url = https://github.com/bjornbytes/lovr-docs
diff --git a/.luarc.json b/.luarc.json
index 2a2fcd2f..a8f8bbe2 100644
--- a/.luarc.json
+++ b/.luarc.json
@@ -1,6 +1,5 @@
{
"$schema": "https://raw.githubusercontent.com/sumneko/vscode-lua/master/setting/schema.json",
-
"color": {
"mode": "SemanticEnhanced"
},
@@ -9,7 +8,10 @@
"close-non-object"
],
"neededFileStatus": {
- "undefined-field": "Any"
+ "undefined-field": "Any",
+ "await-in-sync": "Any",
+ "not-yieldable": "Any",
+ "discard-returns": "Any"
},
"ignoredFiles": "Opened",
"libraryFiles": "Opened"
@@ -17,10 +19,10 @@
"runtime": {
"version": "Lua 5.4",
"path": [
- "?.lua",
"script/?.lua",
"script/?/init.lua"
- ]
+ ],
+ "pathStrict": true
},
"workspace": {
"maxPreload": 1600,
diff --git a/.vscode/launch.json b/.vscode/launch.json
index bb14e759..671a0662 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -3,7 +3,7 @@
"version": "0.2.0",
"configurations": [
{
- "name": "🍺测试",
+ "name": "🍺test",
"type": "lua",
"request": "launch",
"stopOnEntry": false,
@@ -21,7 +21,7 @@
],
},
{
- "name": "附加",
+ "name": "attach",
"type": "lua",
"request": "attach",
"stopOnEntry": false,
@@ -36,12 +36,12 @@
]
},
{
- "name": "love-api",
+ "name": "build-3rd-meta",
"type": "lua",
"request": "launch",
"stopOnEntry": false,
"luaexe": "${workspaceFolder}/bin/Windows/lua-language-server.exe",
- "program": "${workspaceRoot}/tools/love-api.lua",
+ "program": "${workspaceRoot}/tools/build-3rd-meta.lua",
"cpath": "${workspaceFolder}/bin/Windows/?.dll",
"arg": [
],
diff --git a/README.md b/README.md
index bc30905e..554869bf 100644
--- a/README.md
+++ b/README.md
@@ -87,22 +87,25 @@ If you find any mistakes, please [tell me][issues] or use [Pull Requests][@meta]
## Locale
-- [x] en-US
-- [x] zh-CN
+- [x] en-us
+- [x] zh-cn
+- [x] pt-br (thanks [Jeferson Ferreira](https://github.com/jefersonf))
Please [help me][en-US] improve the quality of `en-US`.
[en-US]: https://github.com/sumneko/lua-language-server/tree/master/locale/en-us
## Build
+The extensions in the VSCode market already come with pre-compiled binary files, usually you don't need to compile them.
-* [Build and Run (In VSCode)](https://github.com/sumneko/lua-language-server/wiki/Build-and-Run-(In-VSCode))
-* [Build and Run (Standalone)](https://github.com/sumneko/lua-language-server/wiki/Build-and-Run-(Standalone))
+Other clients can first try to download and use [pre-compiled binary files](https://github.com/sumneko/lua-language-server/wiki/PreCompiled-Binaries).
+
+If you need to compile by yourself, please refer to [here](https://github.com/sumneko/lua-language-server/wiki/Build-and-Run)
## Setting
* In VSCode: Just use the setting of VSCode.
-* Standalone: See https://github.com/sumneko/lua-language-server/wiki/Setting-without-VSCode
+* Standalone: See https://github.com/sumneko/lua-language-server/wiki/Setting
## Credit
diff --git a/changelog.md b/changelog.md
index a5f4d316..cee2349c 100644
--- a/changelog.md
+++ b/changelog.md
@@ -1,5 +1,30 @@
# changelog
+## 2.5.0
+* `NEW` settings:
+ + `Lua.runtime.pathStrict`: not check subdirectories when using `runtime.path`
+ + `Lua.hint.await`: display `await` when calling a function marked as async
+* `NEW` add supports for `lovr`
+* `NEW` file encoding supports `utf16le` and `utf16be`
+* `NEW` `LuaDoc` annotations:
+ + `---@async`: mark a function as async
+ + `---@nodiscard`: the return value of the marking function cannot be discarded
+* `NEW` diagnostics:
+ + `await-in-sync`: check whether calls async function in sync function. disabled by default.
+ + `not-yieldable`: check whether the function supports async functions as parameters. disabled by default.
+ + `discard-returns`: check whether the return value is discarded.
+* `NEW` locale `pt-br`, thanks [Jeferson Ferreira](https://github.com/jefersonf)
+* `NEW` supports [utf-8-offsets](https://clangd.llvm.org/extensions#utf-8-offsets)
+* `CHG` `LuaDoc`:
+ + `---@class` can be re-declared
+ + supports unicode
+ + supports `---@param ... number`, equivalent to `---@vararg number`
+ + supports `fun(...: string)`
+ + supports `fun(x, y, ...)`, equivalent to `fun(x: any, y: any, ...: any)`
+* `CHG` no longer asks to trust plugin in VSCode, because VSCode already provides the workspace trust feature
+* `CHG` skip huge files (>= 10 MB)
+* `CHG` after using `Lua.runtime.nonstandardSymbol` to treat `//` as a comment, `//` is no longer parsed as an operator
+
## 2.4.10
* `FIX` [#790](https://github.com/sumneko/lua-language-server/issues/790)
* `FIX` [#798](https://github.com/sumneko/lua-language-server/issues/798)
diff --git a/locale/en-us/script.lua b/locale/en-us/script.lua
index c5e683b0..a03aec0a 100644
--- a/locale/en-us/script.lua
+++ b/locale/en-us/script.lua
@@ -43,6 +43,9 @@ DIAG_IMPLICIT_ANY = 'Can not infer type.'
DIAG_DEPRECATED = 'Deprecated.'
DIAG_DIFFERENT_REQUIRES = 'The same file is required with different names.'
DIAG_REDUNDANT_RETURN = 'Redundant return.'
+DIAG_AWAIT_IN_SYNC = 'Async function can only be called in async function.'
+DIAG_NOT_YIELDABLE = 'The {}th parameter of this function was not marked as yieldable, but an async function was passed in. (Use `---@param name async fun()` to mark as yieldable)'
+DIAG_DISCARD_RETURNS = 'The return values of this function cannot be discarded.'
DIAG_CIRCLE_DOC_CLASS = 'Circularly inherited classes.'
DIAG_DOC_FIELD_NO_CLASS = 'The field must be defined after the class.'
@@ -54,7 +57,7 @@ DIAG_UNDEFINED_DOC_NAME = 'Undefined type or alias `{}`.'
DIAG_UNDEFINED_DOC_PARAM = 'Undefined param `{}`.'
DIAG_UNKNOWN_DIAG_CODE = 'Unknown diagnostic code `{}`.'
-MWS_NOT_SUPPORT = '{} dose not support multi workspace for now, I may need to restart to support the new workspace ...'
+MWS_NOT_SUPPORT = '{} does not support multi workspace for now, I may need to restart to support the new workspace ...'
MWS_RESTART = 'Restart'
MWS_NOT_COMPLETE = 'Workspace is not complete yet. You may try again later...'
MWS_COMPLETE = 'Workspace is complete now. You may try again...'
@@ -66,6 +69,7 @@ MWS_WCONFIG_UPDATED = 'Workspace setting updated.'
WORKSPACE_SKIP_LARGE_FILE = 'Too large file: {} skipped. The currently set size limit is: {} KB, and the file size is: {} KB.'
WORKSPACE_LOADING = 'Loading workspace'
WORKSPACE_DIAGNOSTIC = 'Diagnosing workspace'
+WORKSPACE_SKIP_HUGE_FILE = 'For performance reasons, the parsing of this file has been stopped: {}'
PARSER_CRASH = 'Parser crashed! Last words:{}'
PARSER_UNKNOWN = 'Unknown syntax error...'
@@ -74,7 +78,7 @@ PARSER_UNKNOWN_SYMBOL = 'Unexpected symbol `{symbol}`.'
PARSER_MISS_SYMBOL = 'Missed symbol `{symbol}`.'
PARSER_MISS_ESC_X = 'Should be 2 hexadecimal digits.'
PARSER_UTF8_SMALL = 'At least 1 hexadecimal digit.'
-PARSER_UTF8_MAX = 'Should between {min} and {max} .'
+PARSER_UTF8_MAX = 'Should be between {min} and {max} .'
PARSER_ERR_ESC = 'Invalid escape sequence.'
PARSER_MUST_X16 = 'Should be hexadecimal digits.'
PARSER_MISS_EXPONENT = 'Missed digits for the exponent.'
@@ -94,7 +98,7 @@ PARSER_UNSUPPORT_SYMBOL = '{version} does not support this grammar.'
PARSER_UNEXPECT_DOTS = 'Cannot use `...` outside a vararg function.'
PARSER_UNEXPECT_SYMBOL = 'Unexpected symbol `{symbol}` .'
PARSER_UNKNOWN_TAG = 'Unknown attribute.'
-PARSER_MULTI_TAG = 'Dose not support multi attributes.'
+PARSER_MULTI_TAG = 'Does not support multi attributes.'
PARSER_UNEXPECT_LFUNC_NAME = 'Local function can only use identifiers as name.'
PARSER_UNEXPECT_EFUNC_NAME = 'Function as expression cannot be named.'
PARSER_ERR_LCOMMENT_END = 'Multi-line annotations should be closed by `{symbol}` .'
@@ -190,6 +194,7 @@ ACTION_FIX_INSERT_SPACE = 'Insert space.'
ACTION_JSON_TO_LUA = 'Convert JSON to Lua'
ACTION_DISABLE_DIAG_LINE= 'Disable diagnostics on this line ({}).'
ACTION_DISABLE_DIAG_FILE= 'Disable diagnostics in this file ({}).'
+ACTION_MARK_ASYNC = 'Mark current function as async.'
COMMAND_DISABLE_DIAG = 'Disable diagnostics'
COMMAND_MARK_GLOBAL = 'Mark defined global'
diff --git a/locale/pt-br/meta.lua b/locale/pt-br/meta.lua
new file mode 100644
index 00000000..6e23cff8
--- /dev/null
+++ b/locale/pt-br/meta.lua
@@ -0,0 +1,429 @@
+-- basic
+arg = 'Argumentos de inicialização para a versão standalone da linguagem Lua.'
+assert = 'Emite um erro se o valor de seu argumento v for falso (i.e., `nil` ou `false`); caso contrário, devolve todos os seus argumentos. Em caso de erro, `message` é o objeto de erro que, quando ausente, por padrão é `"assertion failed!"`'
+cgopt.collect = 'Realiza um ciclo completo de coleta de lixo (i.e., garbage-collection cycle).'
+cgopt.stop = 'Interrompe a execução automática.'
+cgopt.restart = 'Reinicia a execução automática.'
+cgopt.count = 'Retorna, em Kbytes, a quantidade total de memória utilizada pela linguagem Lua.'
+cgopt.step = 'Executa a coleta de lixo (i.e., garbage-collection) em uma única etapa. A quantidade de execuções por etapa é controlada via `arg`.'
+cgopt.setpause = 'Estabelece pausa. Defina via `arg` o intervalo de pausa do coletor de lixo (i.e., garbage-collection).'
+cgopt.setstepmul = 'Estabelece um multiplicador para etapa de coleta de lixo (i.e., garbage-collection). Defina via `arg` o valor multiplicador.'
+cgopt.incremental = 'Altera o modo do coletor para incremental.'
+cgopt.generational = 'Altera o modo do coletor para geracional.'
+cgopt.isrunning = 'Retorna um valor booleano indicando se o coletor de lixo (i.e., garbage-collection) está em execução.'
+collectgarbage = 'Esta função é uma interface genérica para o coletor de lixo (i.e., garbage-collection). Ela executa diferentes funções de acordo com seu primeiro argumento, `opt`.'
+dofile = 'Abre o arquivo fornecido por argumento e executa seu conteúdo como código Lua. Quando chamado sem argumentos, `dofile` executa o conteúdo da entrada padrão (`stdin`). Retorna todos os valores retornados pelo trecho de código contido no arquivo. Em caso de erros, o `dofile` propaga o erro para seu chamador. Ou seja, o `dofile` não funciona em modo protegido.'
+error = [[
+Termina a última chamada de função protegida e retorna `message` como objeto de `erro`.
+
+Normalmente, o 'erro' adiciona algumas informações sobre a localização do erro no início da mensagem, quando a mensagem for uma string.
+]]
+_G = 'Uma variável global (não uma função) que detém o ambiente global (ver §2.2). Lua em si não usa esta variável; mudar seu valor não afeta nenhum ambiente e vice-versa.'
+getfenv = 'Retorna o ambiente atual em uso pela função. O `f` pode ser uma função Lua ou um número que especifica a função naquele nível de pilha.'
+getmetatable = 'Se o objeto não tiver uma metatable, o retorno é `nil`. Mas caso a metatable do objeto tenha um campo `__metatable`, é retornado o valor associado. Caso contrário, retorna a metatable do objeto dado.'
+ipairs = [[
+Retorna três valores (uma função iteradora, a tabela `t`, e `0`) para que a seguinte construção
+```lua
+ for i,v in ipairs(t) do body end
+```
+possa iterar sobre os pares de valor-chave `(1,t[1]), (2,t[2]), ...`, até o primeiro índice ausente.
+]]
+loadmode.b = 'Somente blocos binários.'
+loadmode.t = 'Somente blocos de texto.'
+loadmode.bt = 'Tanto binário quanto texto.'
+load['<5.1'] = 'Carrega um bloco utilizando a função `func` para obter suas partes. Cada chamada para o `func` deve retornar uma string que é concatenada com os resultados anteriores.'
+load['>5.2'] = [[
+Carrega um bloco.
+
+Se o bloco (i.e., `chunk`) é uma string, o bloco é essa string. Se o bloco é uma função, a função "load" é chamada repetidamente para obter suas partes. Cada chamada para o bloco deve retornar uma string que é concatenada com os resultados anteriores. O fim do bloco é sinalizado com o retorno de uma string vazia ou `nil`.
+]]
+loadfile = 'Carrega um bloco de arquivo `filename` ou da entrada padrão, se nenhum nome de arquivo for dado.'
+loadstring = 'Carrega um bloco a partir de uma string dada.'
+module = 'Cria um módulo.'
+next = [[
+Permite que um programa percorra todos os campos de uma tabela. Seu primeiro argumento é uma tabela e seu segundo argumento é um índice nesta tabela. Uma chamada `next` retorna o próximo índice da tabela e seu valor associado. Quando chamado usando `nil` como segundo argumento, `next` retorna um índice inicial e seu valor associado. Quando chamado com o último índice, ou com `nil` em uma tabela vazia, o `next` retorna o `nil`. Se o segundo argumento estiver ausente, então é interpretado como `nil`. Portanto, pode-se utilizar o `next(t)` para verificar se uma tabela está vazia.
+
+A ordem na qual os índices são enumerados não é especificada, *mesmo para índices numéricos*. (Para percorrer uma tabela em ordem numérica, utilize um `for`).
+
+O comportamento do `next` é indefinido se, durante a iteração/travessia, você atribuir qualquer valor a um campo inexistente na tabela. Você pode, entretanto, modificar os campos existentes e pode, inclusive, os definir como nulos.
+]]
+pairs = [[
+Se `t` tem um "meta" método (i.e., metamethod) `__pairs`, a chamada é feita usando t como argumento e retorna os três primeiros resultados.
+
+Caso contrário, retorna três valores: a função $next, a tabela `t` e `nil`, para que a seguinte construção
+```lua
+ for k,v in pairs(t) do body end
+```
+possa iterar sobre todos os pares de valor-chave da tabela 't'.
+
+Veja a função $next para saber as ressalvas em modificar uma tabela durante sua iteração.
+]]
+pcall = [[
+Chama a função `f` com os argumentos dados em modo *protegido*. Isto significa que qualquer erro dentro de `f` não é propagado; em vez disso, o `pcall` captura o erro e retorna um código de status. Seu primeiro resultado é o código de status (booleano), que é verdadeiro se a chamada for bem sucedida sem erros. Neste caso, `pcall' também retorna todos os resultados da chamada, após este primeiro resultado. Em caso de qualquer erro, `pcall` retorna `false` mais o objeto de erro.
+]]
+print = [[
+Recebe qualquer número de argumentos e imprime seus valores na saída padrão `stdout`, convertendo cada argumento em uma string seguindo as mesmas regras do $tostring.
+A função `print` não é destinada à saída formatada, mas apenas como uma forma rápida de mostrar um valor, por exemplo, para debugging. Para controle completo sobre a saída, use $string.format e $io.write.
+]]
+rawequal = 'Verifica se v1 é igual a v2, sem invocar a metatable `__eq`.'
+rawget = 'Obtém o valor real de `table[index]`, sem invocar a metatable `__index`.'
+rawlen = 'Retorna o comprimento do objeto `v`, sem invocar a metatable `__len`.'
+rawset = [[
+Define o valor real de `table[index]` para `value`, sem utilizar o metavalue `__newindex`. `table` deve ser uma tabela, `index` qualquer valor diferente de `nil` e `NaN`, e `value` qualquer valor de tipos do Lua.
+Esta função retorna uma `table`.
+]]
+select = 'Se `index` é um número, retorna todos os argumentos após o número do argumento `index`; um número negativo de índices do final (`-1` é o último argumento). Caso contrário, `index` deve ser a string `"#"`, e `select` retorna o número total de argumentos extras dados.'
+setfenv = 'Define o ambiente a ser utilizado pela função em questão.'
+setmetatable = [[
+Define a metatable para a tabela dada. Se `metatabela` for `nil`, remove a metatable da tabela em questão. Se a metatable original tiver um campo `__metatable', um erro é lançado.
+
+Esta função retorna uma `table`.
+
+Para alterar a metatable de outros tipos do código Lua, você deve utilizar a biblioteca de debugging (§6.10).
+]]
+tonumber = [[
+Quando chamado sem a base, `tonumber` tenta converter seu argumento para um número. Se o argumento já for um número ou uma string numérica, então `tonumber` retorna este número; caso contrário, retorna `fail`.
+
+A conversão de strings pode resultar em números inteiros ou de ponto flutuante, de acordo com as convenções lexicais de Lua (ver §3.1). A string pode ter espaços antes e depois e um sinal.
+]]
+tostring = [[
+Recebe um valor de qualquer tipo e o converte em uma string em formato legível por humanos.
+
+Se a metatable de `v` tem um campo `__tostring', então `tostring' chama o valor correspondente usando `v` como argumento, e utiliza o resultado da chamada como seu resultado. Caso contrário, se a metatable de `v` tiver um campo `__name` com um valor do tipo string, `tostring` pode utilizar essa string em seu resultado final.
+
+Para controle completo de como os números são convertidos, utilize $string.format.
+]]
+type = [[
+Retorna o tipo de seu único argumento, codificado como uma string. Os resultados possíveis desta função são `"nil"` (uma string, não o valor `nil`), `"number"`, `"string"`, `"boolean"`, `"table"`, `"function"`, `"thread"`, e `"userdata"`.
+]]
+_VERSION = 'Uma variável global (não uma função) que contém uma string contendo a versão Lua em execução.'
+warn = 'Emite um aviso com uma mensagem composta pela concatenação de todos os seus argumentos (que devem ser strings).'
+xpcall['=5.1'] = 'Faz chamada a função `f` com os argumentos dados e em modo protegido, usando um manipulador de mensagens dado.'
+xpcall['>5.2'] = 'Faz chamada a função `f` com os argumentos dados e em modo protegido, usando um manipulador de mensagens dado.'
+unpack = [[
+Retorna os elementos da lista dada. Esta função é equivalente a
+```lua
+ return list[i], list[i+1], ···, list[j]
+```
+]]
+
+bit32 = ''
+bit32.arshift = [[
+Retorna o número `x` deslocado `disp` bits para a direita. Deslocamentos negativos movem os bits para a esquerda.
+
+Esta operação de deslocamento é chamada de deslocamento aritmético. Os bits vagos à esquerda são preenchidos com cópias do bit mais significativo de `x`; os bits vagos à direita são preenchidos com zeros.
+]]
+bit32.band = 'Retorna a operação bitwise *and* de seus operandos.'
+bit32.bnot = [[
+Retorna a negação da operação bitwise de `x`.
+
+```lua
+assert(bit32.bnot(x) == (-1 - x) % 2^32)
+```
+]]
+bit32.bor = 'Retorna a operação bitwise *or* de seus operandos.'
+bit32.btest = 'Retorna um valor booleano verdadeiro se a operação bitwise *and* de seus operandos for diferente de zero. Falso, caso contrário.'
+bit32.bxor = 'Retorna a operação bitwise *exclusive or* de seus operandos.'
+bit32.extract = 'Retorna o número formado pelos bits de `field` a `field + width - 1` de `n`, sem sinal.'
+bit32.replace = 'Retorna uma cópia de `n` com os bits de `field` a `field + width - 1` substituídos pelo valor `v` .'
+bit32.lrotate = 'Retorna o número `x` rotacionado `disp` bits para a esquerda. Rotações negativos movem os bits para a direita. '
+bit32.lshift = [[
+Retorna o número `x` deslocado `disp` bits para a esquerda. Deslocamentos negativos movem os bits para a direita. Em ambas as direções, os bits vazios/vagos são preenchidos com zeros.
+
+```lua
+assert(bit32.lshift(b, disp) == (b * 2^disp) % 2^32)
+```
+]]
+bit32.rrotate = 'Retorna o número `x` rotacionado `disp` bits para a direita. Deslocamentos negativos movem os bits para a esquerda.'
+bit32.rshift = [[
+Retorna o número `x` deslocado `disp` bits para a direita. Deslocamentos negativos movem os bits para a esquerda. Em ambas as direções, os bits vazios são preenchidos com zeros.
+
+```lua
+assert(bit32.rshift(b, disp) == math.floor(b % 2^32 / 2^disp))
+```
+]]
+
+coroutine = ''
+coroutine.create = 'Cria uma nova `coroutine`, a partir de uma função `f` e retorna esta coroutine como objeto do tipo `"thread"`.'
+coroutine.isyieldable = 'Retorna verdadeiro quando a `coroutine` em execução for finalizada.'
+coroutine.isyieldable['>5.4']= 'Retorna verdadeiro quando a `coroutine` `co` for finalizada. Por padrão `co` é uma coroutine em execução.'
+coroutine.close = 'Finaliza a coroutine `co` , encerrando todas as variáveis pendentes e colocando a coroutine em um estado morto.'
+coroutine.resume = 'Inicia ou continua a execução da coroutine `co`.'
+coroutine.running = 'Retorna a `coroutine` corrente e um booleana verdadeiro quando a coroutine corrente é a principal.'
+coroutine.status = 'Retorna o status da `coroutine `co`.'
+coroutine.wrap = 'Cria uma nova `coroutine`, a partir de uma função `f` e retorna uma função que retorna a coroutine cada vez que ele é chamado.'
+coroutine.yield = 'Suspende a execução da coroutine chamada.'
+costatus.running = 'Está em execução.'
+costatus.suspended = 'Está suspenso ou não foi iniciado.'
+costatus.normal = 'Está ativo, mas não está em execução.'
+costatus.dead = 'Terminou ou parou devido a erro'
+
+debug = ''
+debug.debug = 'Entra em modo interativo com o usuário, executando os comandos de entrada.'
+debug.getfenv = 'Retorna o ambiente do objeto `o` .'
+debug.gethook = 'Retorna as configurações do `hook` atual da `thread`.'
+debug.getinfo = 'Retorna uma tabela com informações sobre uma função.'
+debug.getlocal['<5.1'] = 'Retorna o nome e o valor da variável local com índice `local` da função de nível `level` da pilha.'
+debug.getlocal['>5.2'] = 'Retorna o nome e o valor da variável local com índice `local` da função de nível `f` da pilha.'
+debug.getmetatable = 'Retorna a `metatable` do valor dado.'
+debug.getregistry = 'Retorna a tabela de registro.'
+debug.getupvalue = 'Retorna o nome e o valor da variável antecedente com índice `up` da função.'
+debug.getuservalue['<5.3'] = 'Retorna o valor de Lua associado a `u` (i.e., user).'
+debug.getuservalue['>5.4'] = [[
+Retorna o `n`-ésimo valor de usuário associado
+aos dados do usuário `u` e um booleano,
+`false`, se nos dados do usuário não existir esse valor.
+]]
+debug.setcstacklimit = [[
+### **Deprecated in `Lua 5.4.2`**
+
+Estabelece um novo limite para a pilha C. Este limite controla quão profundamente as chamadas aninhadas podem ir em Lua, com a intenção de evitar um transbordamento da pilha.
+
+Em caso de sucesso, esta função retorna o antigo limite. Em caso de erro, ela retorna `false`.
+]]
+debug.setfenv = 'Define o ambiente do `object` dado para a `table` dada .'
+debug.sethook = 'Define a função dada como um `hook`.'
+debug.setlocal = 'Atribui o valor `value` à variável local com índice `local` da função de nível `level` da pilha.'
+debug.setmetatable = 'Define a `metatable` com o valor dado para tabela dada (que pode ser `nil`).'
+debug.setupvalue = 'Atribui `value` a variável antecedente com índice `up` da função.'
+debug.setuservalue['<5.3'] = 'Define o valor dado como o valor Lua associado ao `udata` (i.e., user data).'
+debug.setuservalue['>5.4'] = [[
+Define o valor dado como
+o `n`-ésimo valor de usuário associado ao `udata` (i.e., user data).
+O `udata` deve ser um dado de usuário completo.
+]]
+debug.traceback = 'Retorna uma string com um `traceback` de chamadas. A string de mensagen (opcional) é anexada no início do traceback.'
+debug.upvalueid = 'Retorna um identificador único (como um dado de usuário leve) para o valor antecedente de numero `n` da função dada.'
+debug.upvaluejoin = 'Faz o `n1`-ésimo valor da função `f1` (i.e., closure Lua) referir-se ao `n2`-ésimo valor da função `f2`.'
+infowhat.n = '`name` e `namewhat`'
+infowhat.S = '`source`, `short_src`, `linedefined`, `lastlinedefined` e `what`'
+infowhat.l = '`currentline`'
+infowhat.t = '`istailcall`'
+infowhat.u['<5.1'] = '`nups`'
+infowhat.u['>5.2'] = '`nups`, `nparams` e `isvararg`'
+infowhat.f = '`func`'
+infowhat.r = '`ftransfer` e `ntransfer`'
+infowhat.L = '`activelines`'
+hookmask.c = 'Faz chamada a um `hook` quando o Lua chama uma função.'
+hookmask.r = 'Faz chamada a um `hook` quando o retorno de uma função é executado.'
+hookmask.l = 'Faz chamada a um `hook` quando encontra nova linha de código.'
+
+file = ''
+file[':close'] = 'Fecha o arquivo `file`.'
+file[':flush'] = 'Salva qualquer dado de entrada no arquivo `file`.'
+file[':lines'] = [[
+------
+```lua
+for c in file:lines(...) do
+ body
+end
+```
+]]
+file[':read'] = 'Lê o arquivo de acordo com o formato fornecido e que especifica o que deve ser lido.'
+file[':seek'] = 'Define e obtém a posição do arquivo, medida a partir do início do arquivo.'
+file[':setvbuf'] = 'Define o modo de `buffer` para um arquivo de saída.'
+file[':write'] = 'Escreve o valor de cada um de seus argumentos no arquivo.'
+readmode.n = 'Lê um numeral e o devolve como número.'
+readmode.a = 'Lê o arquivo completo.'
+readmode.l = 'Lê a próxima linha pulando o final da linha.'
+readmode.L = 'Lê a próxima linha mantendo o final da linha.'
+seekwhence.set = 'O cursor base é o início do arquivo.'
+seekwhence.cur = 'O cursor base é a posição atual.'
+seekwhence['.end'] = 'O cursor base é o final do arquivo.'
+vbuf.no = 'A saída da operação aparece imediatamente.'
+vbuf.full = 'Realizado apenas quando o `buffer` está cheio.'
+vbuf.line = '`Buffered` até que uma nova linha seja encontrada.'
+
+io = ''
+io.stdin = 'Entrada padrão.'
+io.stdout = 'Saída padrão.'
+io.stderr = 'Erro padrão.'
+io.close = 'Fecha o arquivo dado ou o arquivo de saída padrão.'
+io.flush = 'Salva todos os dados gravados no arquivo de saída padrão.'
+io.input = 'Define o arquivo de entrada padrão.'
+io.lines = [[
+------
+```lua
+for c in io.lines(filename, ...) do
+ body
+end
+```
+]]
+io.open = 'Abre um arquivo no modo especificado pela *string* `mode`.'
+io.output = 'Define o arquivo de saída padrão.'
+io.popen = 'Inicia o programa dado em um processo separado.'
+io.read = 'Lê o arquivo de acordo com o formato fornecido e que especifica o que deve ser lido.'
+io.tmpfile = 'Em caso de sucesso, retorna um `handler` para um arquivo temporário.'
+io.type = 'Verifica se `obj` é um identificador de arquivo válido.'
+io.write = 'Escreve o valor de cada um dos seus argumentos para o arquivo de saída padrão.'
+openmode.r = 'Modo de leitura.'
+openmode.w = 'Modo de escrita.'
+openmode.a = 'Modo de anexação.'
+openmode['.r+'] = 'Modo de atualização, todos os dados anteriores são preservados.'
+openmode['.w+'] = 'Modo de atualização, todos os dados anteriores são apagados.'
+openmode['.a+'] = 'Modo de anexação e atualização, os dados anteriores são preservados, a escrita só é permitida no final do arquivo.'
+openmode.rb = 'Modo de leitura. (em modo binário)'
+openmode.wb = 'Modo de escrita. (em modo binário)'
+openmode.ab = 'Modo de anexação. (em modo binário)'
+openmode['.r+b'] = 'Modo de atualização, todos os dados anteriores são preservados. (em modo binário)'
+openmode['.w+b'] = 'Modo de atualização, todos os dados anteriores são apagados. (em modo binário)'
+openmode['.a+b'] = 'Modo de anexação e atualização, todos os dados anteriores são preservados, a escrita só é permitida no final do arquivo. (em modo binário)'
+popenmode.r = 'Leia dados deste programa pelo arquivo.'
+popenmode.w = 'Escreva dados neste programa pelo arquivo.'
+filetype.file = '`handler` para arquivo aberto.'
+filetype['.closed file'] = '`handler` para arquivo fechado.'
+filetype['.nil'] = 'Não é um `handler` de arquivo'
+
+math = ''
+math.abs = 'Retorna o valor absoluto de `x`.'
+math.acos = 'Retorna o arco cosseno de `x` (em radianos).'
+math.asin = 'Retorna o arco seno de `x` (em radianos).'
+math.atan['<5.2'] = 'Retorna o arco tangente de `x` (em radianos).'
+math.atan['>5.3'] = 'Retorna o arco tangente de `y/x` (em radianos).'
+math.atan2 = 'Retorna o arco tangente de `y/x` (em radianos).'
+math.ceil = 'Retorna o menor valor inteiro maior ou igual a `x`.'
+math.cos = 'Retorna o cosseno de `x` (requer valor em radianos).'
+math.cosh = 'Retorna o cosseno hiperbólico de `x` (requer valor em radianos).'
+math.deg = 'Converte o ângulo `x` de radianos para graus.'
+math.exp = 'Retorna o valor `e^x` (onde `e` é a base do logaritmo natural).'
+math.floor = 'Retorna o maior valor inteiro menor ou igual a `x`.'
+math.fmod = 'Retorna o resto da divisão de `x` por `y` que arredonda o quociente para zero.'
+math.frexp = 'Decompõe `x` em fatores e expoentes. Retorna `m` e `e` tal que `x = m * (2 ^ e)` é um inteiro e o valor absoluto de `m` está no intervalo [0,5, 1) (ou zero quando `x` é zero).'
+math.huge = 'Um valor maior que qualquer outro valor numérico.'
+math.ldexp = 'Retorna `m * (2 ^ e)`.'
+math.log['<5.1'] = 'Retorna o logaritmo natural de `x`.'
+math.log['>5.2'] = 'Retorna o logaritmo de `x` na base dada.'
+math.log10 = 'Retorna o logaritmo `x` na base 10.'
+math.max = 'Retorna o argumento com o valor máximo de acordo com o operador `<`.'
+math.maxinteger = 'Retorna o valor máximo para um inteiro.'
+math.min = 'Retorna o argumento com o valor mínimo de acordo com o operador `<`.'
+math.mininteger = 'Retorna o valor mínimo para um inteiro.'
+math.modf = 'Retorna a parte inteira e a parte fracionária de `x`.'
+math.pi = 'O valor de *π*.'
+math.pow = 'Retorna `x ^ y`.'
+math.rad = 'Converte o ângulo `x` de graus para radianos.'
+math.random = [[
+* `math.random()`: Retorna um valor real (i.e., ponto flutuante) no intervalo [0,1).
+* `math.random(n)`: Retorna um inteiro no intervalo [1, n].
+* `math.random(m, n)`: Retorna um inteiro no intervalo [m, n].
+]]
+math.randomseed['<5.3'] = 'Define `x` como valor semente (i.e., `seed`) para a função geradora de números pseudo-aleatória.'
+math.randomseed['>5.4'] = [[
+* `math.randomseed(x, y)`: Concatena `x` e `y` em um espaço de 128-bits que é usado como valor semente (`seed`) para reinicializar o gerador de números pseudo-aleatório.
+* `math.randomseed(x)`: Equivale a `math.randomseed(x, 0)` .
+* `math.randomseed()`: Gera um valor semente (i.e., `seed`) com fraca probabilidade de aleatoriedade.
+]]
+math.sin = 'Retorna o seno de `x` (requer valor em radianos).'
+math.sinh = 'Retorna o seno hiperbólico de `x` (requer valor em radianos).'
+math.sqrt = 'Retorna a raiz quadrada de `x`.'
+math.tan = 'Retorna a tangente de `x` (requer valor em radianos).'
+math.tanh = 'Retorna a tangente hiperbólica de `x` (requer valor em radianos).'
+math.tointeger = 'Se o valor `x` pode ser convertido para um inteiro, retorna esse inteiro.'
+math.type = 'Retorna `"integer"` se `x` é um inteiro, `"float"` se for um valor real (i.e., ponto flutuante), ou `nil` se `x` não é um número.'
+math.ult = 'Retorna `true` se e somente se `m` é menor `n` quando eles são comparados como inteiros sem sinal.'
+
+os = ''
+os.clock = 'Retorna uma aproximação do valor, em segundos, do tempo de CPU usado pelo programa.'
+os.date = 'Retorna uma string ou uma tabela contendo data e hora, formatada de acordo com a string `format` fornecida.'
+os.difftime = 'Retorna a diferença, em segundos, do tempo `t1` para o tempo` t2`.'
+os.execute = 'Passa `command` para ser executado por um `shell` do sistema operacional.'
+os.exit['<5.1'] = 'Chama a função `exit` do C para encerrar o programa.'
+os.exit['>5.2'] = 'Chama a função `exit` do ISO C para encerrar o programa.'
+os.getenv = 'Retorna o valor da variável de ambiente de processo `varname`.'
+os.remove = 'Remove o arquivo com o nome dado.'
+os.rename = 'Renomeia o arquivo ou diretório chamado `oldname` para `newname`.'
+os.setlocale = 'Define a localidade atual do programa.'
+os.time = 'Retorna a hora atual quando chamada sem argumentos, ou um valor representando a data e a hora local especificados pela tabela fornecida.'
+os.tmpname = 'Retorna uma string com um nome de arquivo que pode ser usado como arquivo temporário.'
+osdate.year = 'Quatro dígitos.'
+osdate.month = '1-12'
+osdate.day = '1-31'
+osdate.hour = '0-23'
+osdate.min = '0-59'
+osdate.sec = '0-61'
+osdate.wday = 'Dia da semana, 1–7, Domingo é 1'
+osdate.yday = 'Dia do ano, 1–366'
+osdate.isdst = 'Bandeira para indicar horário de verão (i.e., `Daylight Saving Time`), um valor booleano.'
+
+package = ''
+require['<5.3'] = 'Carrega o módulo fornecido e retorna qualquer valor retornado pelo módulo (`true` quando `nil`).'
+require['>5.4'] = 'Carrega o módulo fornecido e retorna qualquer valor retornado pelo pesquisador (`true` quando `nil`). Além desse valor, também retorna como segundo resultado um carregador de dados retornados pelo pesquisador, o que indica como `require` encontrou o módulo. (Por exemplo, se o módulo vier de um arquivo, este carregador de dados é o caminho do arquivo.)'
+package.config = 'string descrevendo configurações a serem utilizadas durante a compilação de pacotes.'
+package.cpath = 'O caminho usado pelo `require` para procurar pelo carregador C.'
+package.loaded = 'Uma tabela usada pelo `require` para controlar quais módulos já estão carregados.'
+package.loaders = 'Uma tabela usada pelo `require` para controlar como carregar módulos.'
+package.loadlib = 'Dinamicamente vincula o programa no `host` com a biblioteca C `libname`.'
+package.path = 'O caminho usado pelo `require` para procurar por um carregador Lua.'
+package.preload = 'Uma tabela para armazenar carregadores de módulos específicos.'
+package.searchers = 'Uma tabela usada pelo `require` para controlar como buscar módulos.'
+package.searchpath = 'Procura por `name` em `path`.'
+package.seeall = 'Define uma `metatable` `module` com o campo `__index` referenciando o ambiente global, para que este módulo herde valores do ambiente global. Para ser usado como uma opção a função `module`.'
+
+string = ''
+string.byte = 'Retorna os códigos numéricos internos dos caracteres `s[i], s[i+1], ..., s[j]`.'
+string.char = 'Retorna uma string com comprimento igual ao número de argumentos, no qual cada caractere possui o código numérico interno igual ao seu argumento correspondente.'
+string.dump = 'Retorna uma string contendo uma representação binária (i.e., *binary chunk*) da função dada.'
+string.find = 'Procura a primeira correspondencia de `pattern` (veja §6.4.1) na string.'
+string.format = 'Retorna uma versão formatada de seu número variável de argumentos após a descrição dada em seu primeiro argumento.'
+string.gmatch = [[
+Retorna um iterator que, a cada vez que é chamado, retorna as próximas capturas de `pattern` (veja §6.4.1) sobre a string *s*.
+
+Por exemplo, o loop a seguir irá iterar em todas as palavras da string *s*, imprimindo cada palavra por linha:
+```lua
+ s = "hello world from Lua"
+ for w in string.gmatch(s, "%a+") do
+ print(w)
+ end
+```
+]]
+string.gsub = 'Retorna uma cópia da *s* em que todas ou, caso fornecido, as primeiras `n` ocorrências de `pattern` (veja §6.4.1) que tiverem sido substituídas por uma string de substituição especificada por `repl`.'
+string.len = 'Retorna o comprimento da string.'
+string.lower = 'Retorna uma cópia desta string com todas as letras maiúsculas alteradas para minúsculas.'
+string.match = 'Procura a primeira ocorrência do `pattern` (veja §6.4.1) na string.'
+string.pack = 'Retorna uma string binária contendo os valores `V1`, `v2`, etc. empacotados (isto é, serializado de forma binário) de acordo com o formato da string `fmt` fornecida (veja §6.4.2).'
+string.packsize = 'Retorna o tamanho de uma string resultante de `string.pack` com o formato da string `fmt` fornecida (veja §6.4.2).'
+string.rep['>5.2'] = 'Retorna uma string que é a concatenação de `n` cópias da string `s` separadas pela string `sep`.'
+string.rep['<5.1'] = 'Retorna uma string que é a concatenação de `n` cópias da string `s`.'
+string.reverse = 'Retorna uma string que representa a string `s` invertida.'
+string.sub = 'Retorna a substring da string `s` que começa no índice `i` e continua até o índice `j`.'
+string.unpack = 'Retorna os valores empacotados na string de acordo com o formato da string `fmt` fornecida (veja §6.4.2).'
+string.upper = 'Retorna uma cópia desta string com todas as letras minúsculas alteradas para maiúsculas.'
+
+table = ''
+table.concat = 'Dada uma lista onde todos os elementos são strings ou números, retorna a string `list[i]..sep..list[i+1] ··· sep..list[j]`.'
+table.insert = 'Insere o elemento `value` na posição `pos` de `list`.'
+table.maxn = 'Retorna o maior índice numérico positivo da tabela fornecida ou zero se a tabela não tiver índices numéricos positivos.'
+table.move = [[
+Move os elementos da tabela `a1` para tabela `a2`.
+```lua
+a2[t],··· = a1[f],···,a1[e]
+return a2
+```
+]]
+table.pack = 'Retorna uma nova tabela com todos os argumentos armazenados em chaves `1`, `2`, etc. e com um campo `"n"` com o número total de argumentos.'
+table.remove = 'Remove de `list` o elemento na posição `pos`, retornando o valor do elemento removido.'
+table.sort = 'Ordena os elementos de `list` em uma determinada ordem, *in-place*, de `list[1]` para `list[#list]`.'
+table.unpack = [[
+Retorna os elementos da lista fornecida. Esta função é equivalente a
+```lua
+ return list[i], list[i+1], ···, list[j]
+```
+Por padrão, `i` é `1` e `j` é `#list`.
+]]
+
+utf8 = ''
+utf8.char = 'Recebe zero ou mais inteiros, converte cada um à sua sequência de byte UTF-8 correspondente e retorna uma string com a concatenação de todas essas sequências.'
+utf8.charpattern = 'O padrão que corresponde exatamente uma sequência de byte UTF-8, supondo que seja uma sequência válida UTF-8.'
+utf8.codes = [[
+Retorna valores tal que a seguinte construção
+```lua
+for p, c in utf8.codes(s) do
+ body
+end
+```
+itere em todos os caracteres UTF-8 na string s, com p sendo a posição (em bytes) e c o *codepoint* de cada caractere. Ele gera um erro se encontrado qualquer sequência de byte inválida.
+]]
+utf8.codepoint = 'Retorna os *codepoints* (em inteiros) de todos os caracteres em `s` que iniciam entre as posições do byte `i` e `j` (ambos inclusos).'
+utf8.len = 'Retorna o número de caracteres UTF-8 na string `s` que começa entre as posições `i` e `j` (ambos inclusos).'
+utf8.offset = 'Returns the position (in bytes) where the encoding of the `n`-th character of `s` (counting from position `i`) starts.'
+utf8.offset = 'Retorna a posição (em bytes) onde a codificação do `n`-ésimo caractere de `s` inícia (contando a partir da posição `i`).'
diff --git a/locale/pt-br/script.lua b/locale/pt-br/script.lua
new file mode 100644
index 00000000..9bd7ca8a
--- /dev/null
+++ b/locale/pt-br/script.lua
@@ -0,0 +1,270 @@
+DIAG_LINE_ONLY_SPACE = 'Linha com espaços apenas.'
+DIAG_LINE_POST_SPACE = 'Linha com espaço extra ao final.'
+DIAG_UNUSED_LOCAL = 'Escopo não utilizado `{}`.'
+DIAG_UNDEF_GLOBAL = 'Escopo global indefinido `{}`.'
+DIAG_UNDEF_FIELD = 'Campo indefinido `{}`.'
+DIAG_UNDEF_ENV_CHILD = 'Variável indefinida `{}` (overloaded `_ENV` ).'
+DIAG_UNDEF_FENV_CHILD = 'Variável indefinida `{}` (módulo interno).'
+DIAG_GLOBAL_IN_NIL_ENV = 'Valor global inválido (`_ENV` é `nil`).'
+DIAG_GLOBAL_IN_NIL_FENV = 'Valor global inválido (Ambiente do módulo é `nil`).'
+DIAG_UNUSED_LABEL = 'Identificador não utilizado `{}`.'
+DIAG_UNUSED_FUNCTION = 'Funções não utilizadas.'
+DIAG_UNUSED_VARARG = 'vararg não utilizado.'
+DIAG_REDEFINED_LOCAL = 'Valor local redefinido `{}`.'
+DIAG_DUPLICATE_INDEX = 'Índice duplicado `{}`.'
+DIAG_DUPLICATE_METHOD = 'Método duplicado `{}`.'
+DIAG_PREVIOUS_CALL = 'Será interpretado como `{}{}`. Pode ser necessário adicionar uma `,`.'
+DIAG_PREFIELD_CALL = 'Será interpretado como `{}{}`. Pode ser necessário adicionar uma `,` ou `;`.'
+DIAG_OVER_MAX_ARGS = 'A função aceita apenas os parâmetros {:d}, mas você passou {:d}.'
+DIAG_OVER_MAX_ARGS = 'Recebe apenas {} variáveis, mas você definiu {}.'
+DIAG_AMBIGUITY_1 = 'Calcule primeiro `{}`. Você pode precisar adicionar colchetes.'
+DIAG_LOWERCASE_GLOBAL = 'Variável global com inicial minúscula, você esqueceu o `local` ou digitou errado?'
+DIAG_EMPTY_BLOCK = 'Bloco vazio.'
+DIAG_DIAGNOSTICS = 'Diagnósticos Lua.'
+DIAG_SYNTAX_CHECK = 'Verificação de sintaxe Lua.'
+DIAG_NEED_VERSION = 'Suportado em {}, atual é {}.'
+DIAG_DEFINED_VERSION = 'Definido em {}, a corrente é {}.'
+DIAG_DEFINED_CUSTOM = 'Definido em {}.'
+DIAG_DUPLICATE_CLASS = 'Classe duplicada `{}`.'
+DIAG_UNDEFINED_CLASS = 'Classe indefinida `{}`.'
+DIAG_CYCLIC_EXTENDS = 'Herança cíclica.'
+DIAG_INEXISTENT_PARAM = 'Parâmetro inexistente.'
+DIAG_DUPLICATE_PARAM = 'Parâmetro duplicado.'
+DIAG_NEED_CLASS = 'Classe precisa ser definida primeiro.'
+DIAG_DUPLICATE_SET_FIELD= 'Campo duplicado `{}`.'
+DIAG_SET_CONST = 'Atribuição à variável constante.'
+DIAG_SET_FOR_STATE = 'Atribuição à variável to tipo for-state.'
+DIAG_CODE_AFTER_BREAK = 'Não é possível executar o código depois `break`.'
+DIAG_UNBALANCED_ASSIGNMENTS = 'O valor é atribuído como `nil` porque o número de valores não é suficiente. Em Lua, `x, y = 1` é equivalente a `x, y = 1, nil` .'
+DIAG_REQUIRE_LIKE = 'Você pode tratar `{}` como `require` por configuração.'
+DIAG_COSE_NON_OBJECT = 'Não é possível fechar um valor desse tipo. (A menos que se defina o meta método `__close`)'
+DIAG_COUNT_DOWN_LOOP = 'Você quer dizer `{}` ?'
+DIAG_IMPLICIT_ANY = 'Não pode inferir tipo.'
+DIAG_DEPRECATED = 'Descontinuada.'
+DIAG_DIFFERENT_REQUIRES = 'O mesmo arquivo é necessário com nomes diferentes.'
+DIAG_REDUNDANT_RETURN = 'Retorno redundante.'
+
+DIAG_CIRCLE_DOC_CLASS = 'Classes com herança cíclica.'
+DIAG_DOC_FIELD_NO_CLASS = 'O campo deve ser definido após a classe.'
+DIAG_DUPLICATE_DOC_CLASS = 'Classe definida duplicada `{}`.'
+DIAG_DUPLICATE_DOC_FIELD = 'Campos definidos duplicados `{}`.'
+DIAG_DUPLICATE_DOC_PARAM = 'Parâmetros duplicados `{}`.'
+DIAG_UNDEFINED_DOC_CLASS = 'Classe indefinida `{}`.'
+DIAG_UNDEFINED_DOC_NAME = 'Tipo ou alias indefinido `{}`.'
+DIAG_UNDEFINED_DOC_PARAM = 'Parâmetro indefinido `{}`.'
+DIAG_UNKNOWN_DIAG_CODE = 'Código de diagnóstico desconhecido `{}`.'
+
+MWS_NOT_SUPPORT = '{} não é suportado múltiplos espaços de trabalho por enquanto, posso precisar reiniciar para estabelecer um novo espaço de trabalho ...'
+MWS_RESTART = 'Reiniciar'
+MWS_NOT_COMPLETE = 'O espaço de trabalho ainda não está completo. Você pode tentar novamente mais tarde ...'
+MWS_COMPLETE = 'O espaço de trabalho está completo agora. Você pode tentar novamente ...'
+MWS_MAX_PRELOAD = 'Arquivos pré-carregados atingiram o limite máximo ({}), você precisa abrir manualmente os arquivos que precisam ser carregados.'
+MWS_UCONFIG_FAILED = 'Armazenamento da configuração do usuário falhou.'
+MWS_UCONFIG_UPDATED = 'Configuração do usuário atualizada.'
+MWS_WCONFIG_UPDATED = 'Configuração do espaço de trabalho atualizado.'
+
+WORKSPACE_SKIP_LARGE_FILE = 'Arquivo muito grande: {} ignorada. O limite de tamanho atualmente definido é: {} KB, e o tamanho do arquivo é: {} KB.'
+WORKSPACE_LOADING = 'Carregando espaço de trabalho.'
+WORKSPACE_DIAGNOSTIC = 'Diagnóstico de espaço de trabalho.'
+WORKSPACE_SKIP_HUGE_FILE = 'Por motivos de desempenho, a análise deste arquivo foi interrompida: {}'
+
+PARSER_CRASH = 'Parser quebrou! Últimas palavras: {}'
+PARSER_UNKNOWN = 'Erro de sintaxe desconhecido ...'
+PARSER_MISS_NAME = '<name> esperado.'
+PARSER_UNKNOWN_SYMBOL = 'Símbolo inesperado `{symbol}`.'
+PARSER_MISS_SYMBOL = 'Símbolo não encontrado `{symbol}`.'
+PARSER_MISS_ESC_X = 'Deve ser 2 dígitos hexadecimais.'
+PARSER_UTF8_SMALL = 'Pelo menos 1 dígito hexadecimal.'
+PARSER_UTF8_MAX = 'Deve estar entre {min} e {max}.'
+PARSER_ERR_ESC = 'Sequência de saída inválida.'
+PARSER_MUST_X16 = 'Deve ser dígitos hexadecimais.'
+PARSER_MISS_EXPONENT = 'Dígitos perdidos para o expoente.'
+PARSER_MISS_EXP = '<exp> esperada.'
+PARSER_MISS_FIELD = '<field> esperado.'
+PARSER_MISS_METHOD = '<method> esperado.'
+PARSER_ARGS_AFTER_DOTS = '`...` deve ser o último argumento.'
+PARSER_KEYWORD = '<keyword> não pode ser usado como nome.'
+PARSER_EXP_IN_ACTION = 'Inesperada <exp>.'
+PARSER_BREAK_OUTSIDE = '<break> não está dentro de um loop.'
+PARSER_MALFORMED_NUMBER = 'Número malformado.'
+PARSER_ACTION_AFTER_RETURN = '<eof> esperado após `return`.'
+PARSER_ACTION_AFTER_BREAK = '<eof> esperado após `break`.'
+PARSER_NO_VISIBLE_LABEL = 'Nenhum identificador visível `{label}` .'
+PARSER_REDEFINE_LABEL = 'Identificador `{label}` já foi definido.'
+PARSER_UNSUPPORT_SYMBOL = '{version} não suporta esta gramática.'
+PARSER_UNEXPECT_DOTS = 'Não pode usar `...` fora de uma função vararg.'
+PARSER_UNEXPECT_SYMBOL = 'Símbolo inesperado `{symbol}` .'
+PARSER_UNKNOWN_TAG = 'Atributo desconhecido.'
+PARSER_MULTI_TAG = 'Não suporta múltiplos atributos.'
+PARSER_UNEXPECT_LFUNC_NAME = 'A função local só pode usar identificadores como nome.'
+PARSER_UNEXPECT_EFUNC_NAME = 'Função como expressão não pode ser nomeada.'
+PARSER_ERR_LCOMMENT_END = 'Anotações em múltiplas linhas devem ser fechadas por `{symbol}` .'
+PARSER_ERR_C_LONG_COMMENT = 'Lua deve usar `--[[ ]]` para anotações em múltiplas linhas.'
+PARSER_ERR_LSTRING_END = 'String longa deve ser fechada por `{symbol}` .'
+PARSER_ERR_ASSIGN_AS_EQ = 'Deveria usar `=` para atribuição.'
+PARSER_ERR_EQ_AS_ASSIGN = 'Deveria usar `==` para comparação de igualdade.'
+PARSER_ERR_UEQ = 'Deveria usar `~=` para comparação de desigualdade.'
+PARSER_ERR_THEN_AS_DO = 'Deveria usar `then` .'
+PARSER_ERR_DO_AS_THEN = 'Deveria usar `do` .'
+PARSER_MISS_END = 'Falta o `end` correspondente.'
+PARSER_ERR_COMMENT_PREFIX = 'Lua usa `--` para anotações/comentários.'
+PARSER_MISS_SEP_IN_TABLE = 'Falta o símbolo `,` ou `;` .'
+PARSER_SET_CONST = 'Atribuição à variável constante.'
+PARSER_UNICODE_NAME = 'Contém caracteres Unicode.'
+PARSER_ERR_NONSTANDARD_SYMBOL = 'Deveria usar `{symbol}`.'
+PARSER_MISS_SPACE_BETWEEN = 'Devem ser deixados espaços entre símbolos.'
+PARSER_INDEX_IN_FUNC_NAME = 'A forma `[name]` não pode ser usada em nome de uma função nomeada.'
+PARSER_UNKNOWN_ATTRIBUTE = 'Atributo local deve ser `const` ou `close`'
+
+PARSER_LUADOC_MISS_CLASS_NAME = 'Esperado <class name>.'
+PARSER_LUADOC_MISS_EXTENDS_SYMBOL = 'Esperado `:`.'
+PARSER_LUADOC_MISS_CLASS_EXTENDS_NAME = 'Esperado <class extends name>.'
+PARSER_LUADOC_MISS_SYMBOL = 'Esperado `{symbol}`.'
+PARSER_LUADOC_MISS_ARG_NAME = 'Esperado <arg name>.'
+PARSER_LUADOC_MISS_TYPE_NAME = 'Esperado <type name>.'
+PARSER_LUADOC_MISS_ALIAS_NAME = 'Esperado <alias name>.'
+PARSER_LUADOC_MISS_ALIAS_EXTENDS = 'Esperado <alias extends>.'
+PARSER_LUADOC_MISS_PARAM_NAME = 'Esperado <param name>.'
+PARSER_LUADOC_MISS_PARAM_EXTENDS = 'Esperado <param extends>.'
+PARSER_LUADOC_MISS_FIELD_NAME = 'Esperado <field name>.'
+PARSER_LUADOC_MISS_FIELD_EXTENDS = 'Esperado <field extends>.'
+PARSER_LUADOC_MISS_GENERIC_NAME = 'Esperado <generic name>.'
+PARSER_LUADOC_MISS_GENERIC_EXTENDS_NAME = 'Esperado <generic extends name>.'
+PARSER_LUADOC_MISS_VARARG_TYPE = 'Esperado <vararg type>.'
+PARSER_LUADOC_MISS_FUN_AFTER_OVERLOAD = 'Esperado `fun`.'
+PARSER_LUADOC_MISS_CATE_NAME = 'Esperado <doc name>.'
+PARSER_LUADOC_MISS_DIAG_MODE = 'Esperado <diagnostic mode>.'
+PARSER_LUADOC_ERROR_DIAG_MODE = '<diagnostic mode> incorreto.'
+
+SYMBOL_ANONYMOUS = '<Anonymous>'
+
+HOVER_VIEW_DOCUMENTS = 'Visualizar documentos'
+
+HOVER_DOCUMENT_LUA51 = 'http://www.lua.org/manual/5.1/manual.html#{}'
+HOVER_DOCUMENT_LUA52 = 'http://www.lua.org/manual/5.2/manual.html#{}'
+HOVER_DOCUMENT_LUA53 = 'http://www.lua.org/manual/5.3/manual.html#{}'
+HOVER_DOCUMENT_LUA54 = 'http://www.lua.org/manual/5.4/manual.html#{}'
+HOVER_DOCUMENT_LUAJIT = 'http://www.lua.org/manual/5.1/manual.html#{}'
+
+
+HOVER_NATIVE_DOCUMENT_LUA51 = 'command:extension.lua.doc?["en-us/51/manual.html/{}"]'
+HOVER_NATIVE_DOCUMENT_LUA52 = 'command:extension.lua.doc?["en-us/52/manual.html/{}"]'
+HOVER_NATIVE_DOCUMENT_LUA53 = 'command:extension.lua.doc?["en-us/53/manual.html/{}"]'
+HOVER_NATIVE_DOCUMENT_LUA54 = 'command:extension.lua.doc?["en-us/54/manual.html/{}"]'
+HOVER_NATIVE_DOCUMENT_LUAJIT = 'command:extension.lua.doc?["en-us/51/manual.html/{}"]'
+
+HOVER_MULTI_PROTOTYPE = '({} protótipos)'
+HOVER_STRING_BYTES = '{} bytes'
+HOVER_STRING_CHARACTERS = '{} bytes, {} caracteres'
+HOVER_MULTI_DEF_PROTO = '({} definições., {} protótipos)'
+HOVER_MULTI_PROTO_NOT_FUNC = '({} definição não funcional)'
+
+HOVER_USE_LUA_PATH = '(Caminho de busca: `{}`)'
+HOVER_EXTENDS = 'Expande para {}'
+HOVER_TABLE_TIME_UP = 'Inferência de tipo parcial foi desativada por motivos de desempenho.'
+HOVER_WS_LOADING = 'Carregando espaço de trabalho: {} / {}'
+
+ACTION_DISABLE_DIAG = 'Desativar diagnósticos no espaço de trabalho ({}).'
+ACTION_MARK_GLOBAL = 'Marque `{}` como definição global.'
+ACTION_REMOVE_SPACE = 'Limpe todos os espaços desnecessários.'
+ACTION_ADD_SEMICOLON = 'Adicione `;` .'
+ACTION_ADD_BRACKETS = 'Adicione colchetes.'
+ACTION_RUNTIME_VERSION = 'Altere a versão de tempo de execução para {}.'
+ACTION_OPEN_LIBRARY = 'Carregue variáveis globais de {}.'
+ACTION_ADD_DO_END = 'Adicione `do ... end`.'
+ACTION_FIX_LCOMMENT_END = 'Modifique para o símbolo de fechamento de anotação/comentário de múltiplas linhas correto.'
+ACTION_ADD_LCOMMENT_END = 'Feche as anotações/comentário de múltiplas linhas.'
+ACTION_FIX_C_LONG_COMMENT = 'Modifique para o formato de anotações/comentários em múltiplas linhas.'
+ACTION_FIX_LSTRING_END = 'Modifique para o símbolo de fechamento de string correta.'
+ACTION_ADD_LSTRING_END = 'Feche a string longa.'
+ACTION_FIX_ASSIGN_AS_EQ = 'Modifique para `=` .'
+ACTION_FIX_EQ_AS_ASSIGN = 'Modifique para `==` .'
+ACTION_FIX_UEQ = 'Modifique para `~=` .'
+ACTION_FIX_THEN_AS_DO = 'Modifique para `then` .'
+ACTION_FIX_DO_AS_THEN = 'Modifique para `do` .'
+ACTION_ADD_END = 'Adicione `end` (Adiciona marcação de fim com base na identação).'
+ACTION_FIX_COMMENT_PREFIX = 'Modifique para `--` .'
+ACTION_FIX_NONSTANDARD_SYMBOL = 'Modifique para `{symbol}` .'
+ACTION_RUNTIME_UNICODE_NAME = 'Permite caracteres Unicode.'
+ACTION_SWAP_PARAMS = 'Mude para o parâmetro {index} de `{node}`.'
+ACTION_FIX_INSERT_SPACE = 'Insira espaço.'
+ACTION_JSON_TO_LUA = 'Converte de JSON para Lua.'
+ACTION_DISABLE_DIAG_LINE= 'Desativa diagnósticos nesta linha ({}).'
+ACTION_DISABLE_DIAG_FILE= 'Desativa diagnósticos nesta linha ({}).'
+
+COMMAND_DISABLE_DIAG = 'Desativar diagnósticos.'
+COMMAND_MARK_GLOBAL = 'Marca como variável global.'
+COMMAND_REMOVE_SPACE = 'Limpa todos os espaços desnecessários.'
+COMMAND_ADD_BRACKETS = 'Adiciona colchetes.'
+COMMAND_RUNTIME_VERSION = 'Altera a versão de tempo de execução.'
+COMMAND_OPEN_LIBRARY = 'Carrega variáveis globais de bibliotecas de terceiros.'
+COMMAND_UNICODE_NAME = 'Permite caracteres Unicode.'
+COMMAND_JSON_TO_LUA = 'Converte de JSON para Lua.'
+COMMAND_JSON_TO_LUA_FAILED = 'Converção de JSON para Lua falhou: {}.'
+
+COMPLETION_IMPORT_FROM = 'Importa de {}.'
+COMPLETION_DISABLE_AUTO_REQUIRE = 'Desativa auto require.'
+COMPLETION_ASK_AUTO_REQUIRE = 'Adicione o código na parte superior do arquivo como auto require?'
+
+DEBUG_MEMORY_LEAK = "{} Sinto muito pelo sério vazamento de memória. O serviço de idioma será reiniciado em breve."
+DEBUG_RESTART_NOW = 'Reinicie agora'
+
+WINDOW_COMPILING = 'Compilando'
+WINDOW_DIAGNOSING = 'Realizando diagnóstico'
+WINDOW_INITIALIZING = 'Inicializando...'
+WINDOW_PROCESSING_HOVER = 'Processando hover...'
+WINDOW_PROCESSING_DEFINITION = 'Processando definições...'
+WINDOW_PROCESSING_REFERENCE = 'Processando referências...'
+WINDOW_PROCESSING_RENAME = 'Processando renomeações...'
+WINDOW_PROCESSING_COMPLETION = 'Processando finalizações...'
+WINDOW_PROCESSING_SIGNATURE = 'Processando ajuda de assinatura...'
+WINDOW_PROCESSING_SYMBOL = 'Processando símbolos do arquivo...'
+WINDOW_PROCESSING_WS_SYMBOL = 'Processando símbolos do espaço de trabalho...'
+WINDOW_PROCESSING_SEMANTIC_FULL = 'Processando tokens semânticas completos...'
+WINDOW_PROCESSING_SEMANTIC_RANGE = 'Processando tokens semânticas incrementais...'
+WINDOW_PROCESSING_TYPE_HINT = 'Processando dicas de lina...'
+WINDOW_INCREASE_UPPER_LIMIT = 'Aumente o limite superior'
+WINDOW_CLOSE = 'Fechar'
+WINDOW_SETTING_WS_DIAGNOSTIC = 'Você pode atrasar ou desativar os diagnósticos do espaço de trabalho nas configurações'
+WINDOW_DONT_SHOW_AGAIN = 'Não mostre novamente'
+WINDOW_DELAY_WS_DIAGNOSTIC = 'Diagnóstico de tempo ocioso (atraso de {} segundos)'
+WINDOW_DISABLE_DIAGNOSTIC = 'Desativa diagnósticos do espaço de trabalho'
+WINDOW_LUA_STATUS = [[
+Área de trabalho : {ws}
+Arquivos em cache: {ast}/{max}
+Uso de memória: {mem:.f}M
+]]
+WINDOW_APPLY_SETTING = 'Aplicar configuração'
+WINDOW_CHECK_SEMANTIC = 'Se você estiver usando o tema de cores do market, talvez seja necessário modificar `editor.semanticHighlighting.enabled` para `true` para fazer com tokens semânticas sejam habilitados.'
+WINDOW_TELEMETRY_HINT = 'Por favor, permita o envio de dados de uso e relatórios de erro anônimos para nos ajudar a melhorar ainda mais essa extensão. Leia nossa política de privacidade [aqui](https://github.com/sumneko/lua-language-server/wiki/Privacy-Policy) .'
+WINDOW_TELEMETRY_ENABLE = 'Permitir'
+WINDOW_TELEMETRY_DISABLE = 'Desabilitar'
+WINDOW_CLIENT_NOT_SUPPORT_CONFIG = 'Seu cliente não suporta configurações de modificação do lado do servidor, modifique manualmente as seguintes configurações:'
+WINDOW_LCONFIG_NOT_SUPPORT_CONFIG= 'A modificação automática de configurações locais não é suportada atualmente, modifique manualmente as seguintes configurações:'
+WINDOW_MANUAL_CONFIG_ADD = '`{key}`: adiciona o elemento `{value:q}` ;'
+WINDOW_MANUAL_CONFIG_SET = '`{key}`: defini como `{value:q}` ;'
+WINDOW_MANUAL_CONFIG_PROP = '`{key}`: define a propriedade `{prop}` para `{value:q}`;'
+WINDOW_APPLY_WHIT_SETTING = 'Aplicar e modificar configurações'
+WINDOW_APPLY_WHITOUT_SETTING = 'Aplicar mas não modificar configurações'
+WINDOW_ASK_APPLY_LIBRARY = 'Você precisa configurar seu ambiente de trabalho como `{}`?'
+
+CONFIG_LOAD_FAILED = 'Não é possível ler o arquivo de configurações: {}'
+CONFIG_LOAD_ERROR = 'Configurando o erro de carregamento do arquivo: {}'
+CONFIG_TYPE_ERROR = 'O arquivo de configuração deve estar no formato LUA ou JSON: {}'
+
+PLUGIN_RUNTIME_ERROR = [[
+Ocorreu um erro no plugin, envie o erro ao autor do plugin.
+Por favor, verifique os detalhes na saída ou log.
+Caminho do plugin: {}
+]]
+PLUGIN_TRUST_LOAD = [[
+As configurações atuais tentam carregar o plugin neste local: {}
+
+Note que plugins mal-intencionados podem prejudicar seu computador
+]]
+PLUGIN_TRUST_YES = [[
+Confie e carregue este plugin
+]]
+PLUGIN_TRUST_NO = [[
+Não carregue este plugin
+]]
diff --git a/locale/zh-cn/script.lua b/locale/zh-cn/script.lua
index de204e63..89ade0e8 100644
--- a/locale/zh-cn/script.lua
+++ b/locale/zh-cn/script.lua
@@ -43,6 +43,9 @@ DIAG_IMPLICIT_ANY = '无法推测出类型。'
DIAG_DEPRECATED = '已废弃。'
DIAG_DIFFERENT_REQUIRES = '使用了不同的名字 require 了同一个文件。'
DIAG_REDUNDANT_RETURN = '冗余返回。'
+DIAG_AWAIT_IN_SYNC = '只能在标记为异步的函数中调用异步函数。'
+DIAG_NOT_YIELDABLE = '此函数的第 {} 个参数没有被标记为可让出,但是传入了异步函数。(使用 `---@param name async fun()` 来标记为可让出)'
+DIAG_DISCARD_RETURNS = '不能丢弃此函数的返回值。'
DIAG_CIRCLE_DOC_CLASS = '循环继承的类。'
DIAG_DOC_FIELD_NO_CLASS = '字段必须定义在类之后。'
@@ -66,6 +69,7 @@ MWS_WCONFIG_UPDATED = '工作区配置已更新。'
WORKSPACE_SKIP_LARGE_FILE = '已跳过过大的文件:{}。当前设置的大小限制为:{} KB,该文件大小为:{} KB'
WORKSPACE_LOADING = '正在加载工作目录'
WORKSPACE_DIAGNOSTIC = '正在对工作目录进行诊断'
+WORKSPACE_SKIP_HUGE_FILE = '出于性能考虑,已停止对此文件解析:{}'
PARSER_CRASH = '语法解析崩溃了!遗言:{}'
PARSER_UNKNOWN = '未知语法错误...'
@@ -189,6 +193,7 @@ ACTION_FIX_INSERT_SPACE = '插入空格'
ACTION_JSON_TO_LUA = '把 JSON 转成 Lua'
ACTION_DISABLE_DIAG_LINE= '在此行禁用诊断 ({})。'
ACTION_DISABLE_DIAG_FILE= '在此文件禁用诊断 ({})。'
+ACTION_MARK_ASYNC = '将当前函数标记为异步。'
COMMAND_DISABLE_DIAG = '禁用诊断'
COMMAND_MARK_GLOBAL = '标记全局变量'
diff --git a/meta/3rd/lovr/config.lua b/meta/3rd/lovr/config.lua
new file mode 100644
index 00000000..c0bf32e6
--- /dev/null
+++ b/meta/3rd/lovr/config.lua
@@ -0,0 +1,9 @@
+name = 'LÖVR'
+words = {'lovr%.%w+'}
+configs = {
+ {
+ key = 'Lua.runtime.version',
+ action = 'set',
+ value = 'LuaJIT',
+ },
+}
diff --git a/meta/3rd/lovr/library/callback.lua b/meta/3rd/lovr/library/callback.lua
new file mode 100644
index 00000000..3fb0a960
--- /dev/null
+++ b/meta/3rd/lovr/library/callback.lua
@@ -0,0 +1,115 @@
+---@meta
+
+---
+---The `lovr.conf` callback lets you configure default settings for LÖVR. It is called once right before the game starts. Make sure you put `lovr.conf` in a file called `conf.lua`, a special file that's loaded before the rest of the framework initializes.
+---
+---@type fun(t: table)
+lovr.conf = nil
+
+---
+---This callback is called every frame. Use it to render the scene. If a VR headset is connected, anything rendered by this function will appear in the headset display. The display is cleared to the background color before this function is called.
+---
+---@type fun()
+lovr.draw = nil
+
+---
+---The "lovr.errhand" callback is run whenever an error occurs. It receives two parameters. The first is a string containing the error message. The second is either nil, or a string containing a traceback (as returned by "debug.traceback()"); if nil, this means "lovr.errhand" is being called in the stack where the error occurred, and it can call "debug.traceback()" itself.
+---
+---"lovr.errhand" should return a handler function to run in a loop to show the error screen. This handler function is of the same type as the one returned by "lovr.run" and has the same requirements (such as pumping events). If an error occurs while this handler is running, the program will terminate immediately-- "lovr.errhand" will not be given a second chance. Errors which occur inside "lovr.errhand" or in the handler it returns may not be cleanly reported, so be careful.
+---
+---A default error handler is supplied that renders the error message as text to the headset and to the window.
+---
+---@type fun(message: string, traceback: string):function
+lovr.errhand = nil
+
+---
+---The `lovr.focus` callback is called whenever the application acquires or loses focus (for example, when opening or closing the Steam dashboard). The callback receives a single argument, focused, which is a boolean indicating whether or not the application is now focused. It may make sense to pause the game or reduce visual fidelity when the application loses focus.
+---
+---@type fun(focused: boolean)
+lovr.focus = nil
+
+---
+---This callback is called when a key is pressed.
+---
+---@type fun(key: lovr.KeyCode, scancode: number, repeating: boolean)
+lovr.keypressed = nil
+
+---
+---This callback is called when a key is released.
+---
+---@type fun(key: lovr.KeyCode, scancode: number)
+lovr.keyreleased = nil
+
+---
+---This callback is called once when the app starts. It should be used to perform initial setup work, like loading resources and initializing classes and variables.
+---
+---@type fun(args: table)
+lovr.load = nil
+
+---
+---This callback is called when a message is logged. The default implementation of this callback prints the message to the console using `print`, but it's possible to override this callback to render messages in VR, write them to a file, filter messages, and more.
+---
+---The message can have a "tag" that is a short string representing the sender, and a "level" indicating how severe the message is.
+---
+---The `t.graphics.debug` flag in `lovr.conf` can be used to get log messages from the GPU driver (tagged as `GL`). It is also possible to emit your own log messages using `lovr.event.push`.
+---
+---@type fun(message: string, level: string, tag: string)
+lovr.log = nil
+
+---
+---This callback is called every frame after rendering to the headset and is usually used to render a mirror of the headset display onto the desktop window. It can be overridden for custom mirroring behavior. For example, you could render a single eye instead of a stereo view, apply postprocessing effects, add 2D UI, or render the scene from an entirely different viewpoint for a third person camera.
+---
+---@type fun()
+lovr.mirror = nil
+
+---
+---This callback contains a permission response previously requested with `lovr.system.requestPermission`. The callback contains information on whether permission was granted or denied.
+---
+---@type fun(permission: lovr.Permission, granted: boolean)
+lovr.permission = nil
+
+---
+---This callback is called right before the application is about to quit. Use it to perform any necessary cleanup work. A truthy value can be returned from this callback to abort quitting.
+---
+---@type fun():boolean
+lovr.quit = nil
+
+---
+---This callback is called when the desktop window is resized.
+---
+---@type fun(width: number, height: number)
+lovr.resize = nil
+
+---
+---This callback is called when a restart from `lovr.event.restart` is happening. A value can be returned to send it to the next LÖVR instance, available as the `restart` key in the argument table passed to `lovr.load`. Object instances can not be used as the restart value, since they are destroyed as part of the cleanup process.
+---
+---@type fun():any
+lovr.restart = nil
+
+---
+---This callback is the main entry point for a LÖVR program. It is responsible for calling `lovr.load` and returning the main loop function.
+---
+---@type fun():function
+lovr.run = nil
+
+---
+---This callback is called when text has been entered.
+---
+---For example, when `shift + 1` is pressed on an American keyboard, `lovr.textinput` will be called with `!`.
+---
+---@type fun(text: string, code: number)
+lovr.textinput = nil
+
+---
+---The `lovr.threaderror` callback is called whenever an error occurs in a Thread. It receives the Thread object where the error occurred and an error message.
+---
+---The default implementation of this callback will call `lovr.errhand` with the error.
+---
+---@type fun(thread: lovr.Thread, message: string)
+lovr.threaderror = nil
+
+---
+---The `lovr.update` callback should be used to update your game's logic. It receives a single parameter, `dt`, which represents the amount of elapsed time between frames. You can use this value to scale timers, physics, and animations in your game so they play at a smooth, consistent speed.
+---
+---@type fun(dt: number)
+lovr.update = nil
diff --git a/meta/3rd/lovr/library/lovr.audio.lua b/meta/3rd/lovr/library/lovr.audio.lua
new file mode 100644
index 00000000..d8b1bd9d
--- /dev/null
+++ b/meta/3rd/lovr/library/lovr.audio.lua
@@ -0,0 +1,495 @@
+---@meta
+
+---
+---The `lovr.audio` module is responsible for playing sound effects and music. To play a sound, create a `Source` object and call `Source:play` on it. Currently ogg, wav, and mp3 audio formats are supported.
+---
+---@class lovr.audio
+lovr.audio = {}
+
+---
+---Returns the global air absorption coefficients for the medium. This affects Sources that have the `absorption` effect enabled, causing audio volume to drop off with distance as it is absorbed by the medium it's traveling through (air, water, etc.). The difference between absorption and falloff is that absorption is more subtle and is frequency-dependent, so higher-frequency bands can get absorbed more quickly than lower ones. This can be used to apply "underwater" effects and stuff.
+---
+---@return number low # The absorption coefficient for the low frequency band.
+---@return number mid # The absorption coefficient for the mid frequency band.
+---@return number high # The absorption coefficient for the high frequency band.
+function lovr.audio.getAbsorption() end
+
+---
+---Returns a list of playback or capture devices. Each device has an `id`, `name`, and a `default` flag indicating whether it's the default device.
+---
+---To use a specific device id for playback or capture, pass it to `lovr.audio.setDevice`.
+---
+---@param type? lovr.AudioType # The type of devices to query (playback or capture).
+---@return {["[].id"]: userdata, ["[].name"]: string, ["[].default"]: boolean} devices # The list of devices.
+function lovr.audio.getDevices(type) end
+
+---
+---Returns the orientation of the virtual audio listener in angle/axis representation.
+---
+---@return number angle # The number of radians the listener is rotated around its axis of rotation.
+---@return number ax # The x component of the axis of rotation.
+---@return number ay # The y component of the axis of rotation.
+---@return number az # The z component of the axis of rotation.
+function lovr.audio.getOrientation() end
+
+---
+---Returns the position and orientation of the virtual audio listener.
+---
+---@return number x # The x position of the listener, in meters.
+---@return number y # The y position of the listener, in meters.
+---@return number z # The z position of the listener, in meters.
+---@return number angle # The number of radians the listener is rotated around its axis of rotation.
+---@return number ax # The x component of the axis of rotation.
+---@return number ay # The y component of the axis of rotation.
+---@return number az # The z component of the axis of rotation.
+function lovr.audio.getPose() end
+
+---
+---Returns the position of the virtual audio listener, in meters.
+---
+---@return number x # The x position of the listener.
+---@return number y # The y position of the listener.
+---@return number z # The z position of the listener.
+function lovr.audio.getPosition() end
+
+---
+---Returns the name of the active spatializer (`simple`, `oculus`, or `phonon`).
+---
+---The `t.audio.spatializer` setting in `lovr.conf` can be used to express a preference for a particular spatializer. If it's `nil`, all spatializers will be tried in the following order: `phonon`, `oculus`, `simple`.
+---
+---@return string spatializer # The name of the active spatializer.
+function lovr.audio.getSpatializer() end
+
+---
+---Returns the master volume. All audio sent to the playback device has its volume multiplied by this factor.
+---
+---@param units? lovr.VolumeUnit # The units to return (linear or db).
+---@return number volume # The master volume.
+function lovr.audio.getVolume(units) end
+
+---
+---Returns whether an audio device is started.
+---
+---@param type? lovr.AudioType # The type of device to check.
+---@return boolean started # Whether the device is active.
+function lovr.audio.isStarted(type) end
+
+---
+---Creates a new Source from an ogg, wav, or mp3 file.
+---
+---@overload fun(blob: lovr.Blob, options: table):lovr.Source
+---@overload fun(sound: lovr.Sound, options: table):lovr.Source
+---@param filename string # The filename of the sound to load.
+---@param options {decode: boolean, effects: table} # Optional options.
+---@return lovr.Source source # The new Source.
+function lovr.audio.newSource(filename, options) end
+
+---
+---Sets the global air absorption coefficients for the medium. This affects Sources that have the `absorption` effect enabled, causing audio volume to drop off with distance as it is absorbed by the medium it's traveling through (air, water, etc.). The difference between absorption and falloff is that absorption is more subtle and is frequency-dependent, so higher-frequency bands can get absorbed more quickly than lower ones. This can be used to apply "underwater" effects and stuff.
+---
+---@param low number # The absorption coefficient for the low frequency band.
+---@param mid number # The absorption coefficient for the mid frequency band.
+---@param high number # The absorption coefficient for the high frequency band.
+function lovr.audio.setAbsorption(low, mid, high) end
+
+---
+---Switches either the playback or capture device to a new one.
+---
+---If a device for the given type is already active, it will be stopped and destroyed. The new device will not be started automatically, use `lovr.audio.start` to start it.
+---
+---A device id (previously retrieved using `lovr.audio.getDevices`) can be given to use a specific audio device, or `nil` can be used for the id to use the default audio device.
+---
+---A sink can be also be provided when changing the device. A sink is an audio stream (`Sound` object with a `stream` type) that will receive all audio samples played (for playback) or all audio samples captured (for capture). When an audio device with a sink is started, be sure to periodically call `Sound:read` on the sink to read audio samples from it, otherwise it will overflow and discard old data. The sink can have any format, data will be converted as needed. Using a sink for the playback device will reduce performance, but this isn't the case for capture devices.
+---
+---Audio devices can be started in `shared` or `exclusive` mode. Exclusive devices may have lower latency than shared devices, but there's a higher chance that requesting exclusive access to an audio device will fail (either because it isn't supported or allowed). One strategy is to first try the device in exclusive mode, switching to shared if it doesn't work.
+---
+---@param type? lovr.AudioType # The device to switch.
+---@param id? userdata # The id of the device to use, or `nil` to use the default device.
+---@param sink? lovr.Sound # An optional audio stream to use as a sink for the device.
+---@param mode? lovr.AudioShareMode # The sharing mode for the device.
+---@return boolean success # Whether creating the audio device succeeded.
+function lovr.audio.setDevice(type, id, sink, mode) end
+
+---
+---Sets a mesh of triangles to use for modeling audio effects, using a table of vertices or a Model. When the appropriate effects are enabled, audio from `Source` objects will correctly be occluded by walls and bounce around to create realistic reverb.
+---
+---An optional `AudioMaterial` may be provided to specify the acoustic properties of the geometry.
+---
+---@overload fun(model: lovr.Model, material: lovr.AudioMaterial):boolean
+---@param vertices table # A flat table of vertices. Each vertex is 3 numbers representing its x, y, and z position. The units used for audio coordinates are up to you, but meters are recommended.
+---@param indices table # A list of indices, indicating how the vertices are connected into triangles. Indices are 1-indexed and are 32 bits (they can be bigger than 65535).
+---@param material? lovr.AudioMaterial # The acoustic material to use.
+---@return boolean success # Whether audio geometry is supported by the current spatializer and the geometry was loaded successfully.
+function lovr.audio.setGeometry(vertices, indices, material) end
+
+---
+---Sets the orientation of the virtual audio listener in angle/axis representation.
+---
+---@param angle number # The number of radians the listener should be rotated around its rotation axis.
+---@param ax number # The x component of the axis of rotation.
+---@param ay number # The y component of the axis of rotation.
+---@param az number # The z component of the axis of rotation.
+function lovr.audio.setOrientation(angle, ax, ay, az) end
+
+---
+---Sets the position and orientation of the virtual audio listener.
+---
+---@param x number # The x position of the listener, in meters.
+---@param y number # The y position of the listener, in meters.
+---@param z number # The z position of the listener, in meters.
+---@param angle number # The number of radians the listener is rotated around its axis of rotation.
+---@param ax number # The x component of the axis of rotation.
+---@param ay number # The y component of the axis of rotation.
+---@param az number # The z component of the axis of rotation.
+function lovr.audio.setPose(x, y, z, angle, ax, ay, az) end
+
+---
+---Sets the position of the virtual audio listener, in meters.
+---
+---@param x number # The x position of the listener.
+---@param y number # The y position of the listener.
+---@param z number # The z position of the listener.
+function lovr.audio.setPosition(x, y, z) end
+
+---
+---Sets the master volume. All audio sent to the playback device has its volume multiplied by this factor.
+---
+---@param volume number # The master volume.
+---@param units? lovr.VolumeUnit # The units of the value.
+function lovr.audio.setVolume(volume, units) end
+
+---
+---Starts the active playback or capture device. By default the playback device is initialized and started, but this can be controlled using the `t.audio.start` flag in `lovr.conf`.
+---
+---@param type? lovr.AudioType # The type of device to start.
+---@return boolean started # Whether the device was successfully started.
+function lovr.audio.start(type) end
+
+---
+---Stops the active playback or capture device. This may fail if:
+---
+---- The device is not started
+---- No device was initialized with `lovr.audio.setDevice`
+---
+---@param type? lovr.AudioType # The type of device to stop.
+---@return boolean stopped # Whether the device was successfully stopped.
+function lovr.audio.stop(type) end
+
+---
+---A Source is an object representing a single sound. Currently ogg, wav, and mp3 formats are supported.
+---
+---When a Source is playing, it will send audio to the speakers. Sources do not play automatically when they are created. Instead, the `play`, `pause`, and `stop` functions can be used to control when they should play.
+---
+---`Source:seek` and `Source:tell` can be used to control the playback position of the Source. A Source can be set to loop when it reaches the end using `Source:setLooping`.
+---
+---@class lovr.Source
+local Source = {}
+
+---
+---Creates a copy of the Source, referencing the same `Sound` object and inheriting all of the settings of this Source. However, it will be created in the stopped state and will be rewound to the beginning.
+---
+---@return lovr.Source source # A genetically identical copy of the Source.
+function Source:clone() end
+
+---
+---Returns the directivity settings for the Source.
+---
+---The directivity is controlled by two parameters: the weight and the power.
+---
+---The weight is a number between 0 and 1 controlling the general "shape" of the sound emitted. 0.0 results in a completely omnidirectional sound that can be heard from all directions. 1.0 results in a full dipole shape that can be heard only from the front and back. 0.5 results in a cardioid shape that can only be heard from one direction. Numbers in between will smoothly transition between these.
+---
+---The power is a number that controls how "focused" or sharp the shape is. Lower power values can be heard from a wider set of angles. It is an exponent, so it can get arbitrarily large. Note that a power of zero will still result in an omnidirectional source, regardless of the weight.
+---
+---@return number weight # The dipole weight. 0.0 is omnidirectional, 1.0 is a dipole, 0.5 is cardioid.
+---@return number power # The dipole power, controlling how focused the directivity shape is.
+function Source:getDirectivity() end
+
+---
+---Returns the duration of the Source.
+---
+---@param unit? lovr.TimeUnit # The unit to return.
+---@return number duration # The duration of the Source.
+function Source:getDuration(unit) end
+
+---
+---Returns the orientation of the Source, in angle/axis representation.
+---
+---@return number angle # The number of radians the Source is rotated around its axis of rotation.
+---@return number ax # The x component of the axis of rotation.
+---@return number ay # The y component of the axis of rotation.
+---@return number az # The z component of the axis of rotation.
+function Source:getOrientation() end
+
+---
+---Returns the position and orientation of the Source.
+---
+---@return number x # The x position of the Source, in meters.
+---@return number y # The y position of the Source, in meters.
+---@return number z # The z position of the Source, in meters.
+---@return number angle # The number of radians the Source is rotated around its axis of rotation.
+---@return number ax # The x component of the axis of rotation.
+---@return number ay # The y component of the axis of rotation.
+---@return number az # The z component of the axis of rotation.
+function Source:getPose() end
+
+---
+---Returns the position of the Source, in meters. Setting the position will cause the Source to be distorted and attenuated based on its position relative to the listener.
+---
+---@return number x # The x coordinate.
+---@return number y # The y coordinate.
+---@return number z # The z coordinate.
+function Source:getPosition() end
+
+---
+---Returns the radius of the Source, in meters.
+---
+---This does not control falloff or attenuation. It is only used for smoothing out occlusion. If a Source doesn't have a radius, then when it becomes occluded by a wall its volume will instantly drop. Giving the Source a radius that approximates its emitter's size will result in a smooth transition between audible and occluded, improving realism.
+---
+---@return number radius # The radius of the Source, in meters.
+function Source:getRadius() end
+
+---
+---Returns the `Sound` object backing the Source. Multiple Sources can share one Sound, allowing its data to only be loaded once. An easy way to do this sharing is by using `Source:clone`.
+---
+---@return lovr.Sound sound # The Sound object.
+function Source:getSound() end
+
+---
+---Returns the current volume factor for the Source.
+---
+---@param units? lovr.VolumeUnit # The units to return (linear or db).
+---@return number volume # The volume of the Source.
+function Source:getVolume(units) end
+
+---
+---Returns whether a given `Effect` is enabled for the Source.
+---
+---@param effect lovr.Effect # The effect.
+---@return boolean enabled # Whether the effect is enabled.
+function Source:isEffectEnabled(effect) end
+
+---
+---Returns whether or not the Source will loop when it finishes.
+---
+---@return boolean looping # Whether or not the Source is looping.
+function Source:isLooping() end
+
+---
+---Returns whether or not the Source is playing.
+---
+---@return boolean playing # Whether the Source is playing.
+function Source:isPlaying() end
+
+---
+---Pauses the source. It can be resumed with `Source:resume` or `Source:play`. If a paused source is rewound, it will remain paused.
+---
+function Source:pause() end
+
+---
+---Plays the Source. This doesn't do anything if the Source is already playing.
+---
+---@return boolean success # Whether the Source successfully started playing.
+function Source:play() end
+
+---
+---Seeks the Source to the specified position.
+---
+---@param position number # The position to seek to.
+---@param unit? lovr.TimeUnit # The units for the seek position.
+function Source:seek(position, unit) end
+
+---
+---Sets the directivity settings for the Source.
+---
+---The directivity is controlled by two parameters: the weight and the power.
+---
+---The weight is a number between 0 and 1 controlling the general "shape" of the sound emitted. 0.0 results in a completely omnidirectional sound that can be heard from all directions. 1.0 results in a full dipole shape that can be heard only from the front and back. 0.5 results in a cardioid shape that can only be heard from one direction. Numbers in between will smoothly transition between these.
+---
+---The power is a number that controls how "focused" or sharp the shape is. Lower power values can be heard from a wider set of angles. It is an exponent, so it can get arbitrarily large. Note that a power of zero will still result in an omnidirectional source, regardless of the weight.
+---
+---@param weight number # The dipole weight. 0.0 is omnidirectional, 1.0 is a dipole, 0.5 is cardioid.
+---@param power number # The dipole power, controlling how focused the directivity shape is.
+function Source:setDirectivity(weight, power) end
+
+---
+---Enables or disables an effect on the Source.
+---
+---@param effect lovr.Effect # The effect.
+---@param enable boolean # Whether the effect should be enabled.
+function Source:setEffectEnabled(effect, enable) end
+
+---
+---Sets whether or not the Source loops.
+---
+---@param loop boolean # Whether or not the Source will loop.
+function Source:setLooping(loop) end
+
+---
+---Sets the orientation of the Source in angle/axis representation.
+---
+---@param angle number # The number of radians the Source should be rotated around its rotation axis.
+---@param ax number # The x component of the axis of rotation.
+---@param ay number # The y component of the axis of rotation.
+---@param az number # The z component of the axis of rotation.
+function Source:setOrientation(angle, ax, ay, az) end
+
+---
+---Sets the position and orientation of the Source.
+---
+---@param x number # The x position of the Source, in meters.
+---@param y number # The y position of the Source, in meters.
+---@param z number # The z position of the Source, in meters.
+---@param angle number # The number of radians the Source is rotated around its axis of rotation.
+---@param ax number # The x component of the axis of rotation.
+---@param ay number # The y component of the axis of rotation.
+---@param az number # The z component of the axis of rotation.
+function Source:setPose(x, y, z, angle, ax, ay, az) end
+
+---
+---Sets the position of the Source, in meters. Setting the position will cause the Source to be distorted and attenuated based on its position relative to the listener.
+---
+---Only mono sources can be positioned. Setting the position of a stereo Source will cause an error.
+---
+---@param x number # The x coordinate.
+---@param y number # The y coordinate.
+---@param z number # The z coordinate.
+function Source:setPosition(x, y, z) end
+
+---
+---Sets the radius of the Source, in meters.
+---
+---This does not control falloff or attenuation. It is only used for smoothing out occlusion. If a Source doesn't have a radius, then when it becomes occluded by a wall its volume will instantly drop. Giving the Source a radius that approximates its emitter's size will result in a smooth transition between audible and occluded, improving realism.
+---
+---@param radius number # The new radius of the Source, in meters.
+function Source:setRadius(radius) end
+
+---
+---Sets the current volume factor for the Source.
+---
+---@param volume number # The new volume.
+---@param units? lovr.VolumeUnit # The units of the value.
+function Source:setVolume(volume, units) end
+
+---
+---Stops the source, also rewinding it to the beginning.
+---
+function Source:stop() end
+
+---
+---Returns the current playback position of the Source.
+---
+---@param unit? lovr.TimeUnit # The unit to return.
+---@return number position # The current playback position.
+function Source:tell(unit) end
+
+---
+---Different types of audio material presets, for use with `lovr.audio.setGeometry`.
+---
+---@class lovr.AudioMaterial
+---
+---Generic default audio material.
+---
+---@field generic integer
+---
+---Brick.
+---
+---@field brick integer
+---
+---Carpet.
+---
+---@field carpet integer
+---
+---Ceramic.
+---
+---@field ceramic integer
+---
+---Concrete.
+---
+---@field concrete integer
+---@field glass integer
+---@field gravel integer
+---@field metal integer
+---@field plaster integer
+---@field rock integer
+---@field wood integer
+
+---
+---Audio devices can be created in shared mode or exclusive mode. In exclusive mode, the audio device is the only one active on the system, which gives better performance and lower latency. However, exclusive devices aren't always supported and might not be allowed, so there is a higher chance that creating one will fail.
+---
+---@class lovr.AudioShareMode
+---
+---Shared mode.
+---
+---@field shared integer
+---
+---Exclusive mode.
+---
+---@field exclusive integer
+
+---
+---When referencing audio devices, this indicates whether it's the playback or capture device.
+---
+---@class lovr.AudioType
+---
+---The playback device (speakers, headphones).
+---
+---@field playback integer
+---
+---The capture device (microphone).
+---
+---@field capture integer
+
+---
+---Different types of effects that can be applied with `Source:setEffectEnabled`.
+---
+---@class lovr.Effect
+---
+---Models absorption as sound travels through the air, water, etc.
+---
+---@field absorption integer
+---
+---Decreases audio volume with distance (1 / max(distance, 1)).
+---
+---@field falloff integer
+---
+---Causes audio to drop off when the Source is occluded by geometry.
+---
+---@field occlusion integer
+---
+---Models reverb caused by audio bouncing off of geometry.
+---
+---@field reverb integer
+---
+---Spatializes the Source using either simple panning or an HRTF.
+---
+---@field spatialization integer
+---
+---Causes audio to be heard through walls when occluded, based on audio materials.
+---
+---@field transmission integer
+
+---
+---When figuring out how long a Source is or seeking to a specific position in the sound file, units can be expressed in terms of seconds or in terms of frames. A frame is one set of samples for each channel (one sample for mono, two samples for stereo).
+---
+---@class lovr.TimeUnit
+---
+---Seconds.
+---
+---@field seconds integer
+---
+---Frames.
+---
+---@field frames integer
+
+---
+---When accessing the volume of Sources or the audio listener, this can be done in linear units with a 0 to 1 range, or in decibels with a range of -∞ to 0.
+---
+---@class lovr.VolumeUnit
+---
+---Linear volume range.
+---
+---@field linear integer
+---
+---Decibels.
+---
+---@field db integer
diff --git a/meta/3rd/lovr/library/lovr.data.lua b/meta/3rd/lovr/library/lovr.data.lua
new file mode 100644
index 00000000..f43cbf94
--- /dev/null
+++ b/meta/3rd/lovr/library/lovr.data.lua
@@ -0,0 +1,387 @@
+---@meta
+
+---
+---The `lovr.data` module provides functions for accessing underlying data representations for several LÖVR objects.
+---
+---@class lovr.data
+lovr.data = {}
+
+---
+---Creates a new Blob.
+---
+---@overload fun(contents: string, name: string):lovr.Blob
+---@overload fun(source: lovr.Blob, name: string):lovr.Blob
+---@param size number # The amount of data to allocate for the Blob, in bytes. All of the bytes will be filled with zeroes.
+---@param name? string # A name for the Blob (used in error messages)
+---@return lovr.Blob blob # The new Blob.
+function lovr.data.newBlob(size, name) end
+
+---
+---Creates a new Image. Image data can be loaded and decoded from an image file, or a raw block of pixels with a specified width, height, and format can be created.
+---
+---@overload fun(width: number, height: number, format: lovr.TextureFormat, data: lovr.Blob):lovr.Image
+---@overload fun(source: lovr.Image):lovr.Image
+---@overload fun(blob: lovr.Blob, flip: boolean):lovr.Image
+---@param filename string # The filename of the image to load.
+---@param flip? boolean # Whether to vertically flip the image on load. This should be true for normal textures, and false for textures that are going to be used in a cubemap.
+---@return lovr.Image image # The new Image.
+function lovr.data.newImage(filename, flip) end
+
+---
+---Loads a 3D model from a file. The supported 3D file formats are OBJ and glTF.
+---
+---@overload fun(blob: lovr.Blob):lovr.ModelData
+---@param filename string # The filename of the model to load.
+---@return lovr.ModelData modelData # The new ModelData.
+function lovr.data.newModelData(filename) end
+
+---
+---Creates a new Rasterizer from a TTF file.
+---
+---@overload fun(filename: string, size: number):lovr.Rasterizer
+---@overload fun(blob: lovr.Blob, size: number):lovr.Rasterizer
+---@param size? number # The resolution to render the fonts at, in pixels. Higher resolutions use more memory and processing power but may provide better quality results for some fonts/situations.
+---@return lovr.Rasterizer rasterizer # The new Rasterizer.
+function lovr.data.newRasterizer(size) end
+
+---
+---Creates a new Sound. A sound can be loaded from an audio file, or it can be created empty with capacity for a certain number of audio frames.
+---
+---When loading audio from a file, use the `decode` option to control whether compressed audio should remain compressed or immediately get decoded to raw samples.
+---
+---When creating an empty sound, the `contents` parameter can be set to `'stream'` to create an audio stream. On streams, `Sound:setFrames` will always write to the end of the stream, and `Sound:getFrames` will always read the oldest samples from the beginning. The number of frames in the sound is the total capacity of the stream's buffer.
+---
+---@overload fun(filename: string, decode: boolean):lovr.Sound
+---@overload fun(blob: lovr.Blob, decode: boolean):lovr.Sound
+---@param frames number # The number of frames the Sound can hold.
+---@param format? lovr.SampleFormat # The sample data type.
+---@param channels? lovr.ChannelLayout # The channel layout.
+---@param sampleRate? number # The sample rate, in Hz.
+---@param contents? any # A Blob containing raw audio samples to use as the initial contents, 'stream' to create an audio stream, or `nil` to leave the data initialized to zero.
+---@return lovr.Sound sound # Sounds good.
+function lovr.data.newSound(frames, format, channels, sampleRate, contents) end
+
+---
+---A Blob is an object that holds binary data. It can be passed to most functions that take filename arguments, like `lovr.graphics.newModel` or `lovr.audio.newSource`. Blobs aren't usually necessary for simple projects, but they can be really helpful if:
+---
+---- You need to work with low level binary data, potentially using the LuaJIT FFI for increased
+--- performance.
+---- You are working with data that isn't stored as a file, such as programmatically generated data
+--- or a string from a network request.
+---- You want to load data from a file once and then use it to create many different objects.
+---
+---A Blob's size cannot be changed once it is created.
+---
+---@class lovr.Blob
+local Blob = {}
+
+---
+---Returns the filename the Blob was loaded from, or the custom name given to it when it was created. This label is also used in error messages.
+---
+---@return string name # The name of the Blob.
+function Blob:getName() end
+
+---
+---Returns a raw pointer to the Blob's data. This can be used to interface with other C libraries using the LuaJIT FFI. Use this only if you know what you're doing!
+---
+---@return userdata pointer # A pointer to the data.
+function Blob:getPointer() end
+
+---
+---Returns the size of the Blob's contents, in bytes.
+---
+---@return number bytes # The size of the Blob, in bytes.
+function Blob:getSize() end
+
+---
+---Returns a binary string containing the Blob's data.
+---
+---@return string data # The Blob's data.
+function Blob:getString() end
+
+---
+---An Image stores raw 2D pixel info for `Texture`s. It has a width, height, and format. The Image can be initialized with the contents of an image file or it can be created with uninitialized contents. The supported image formats are `png`, `jpg`, `hdr`, `dds`, `ktx`, and `astc`.
+---
+---Usually you can just use Textures, but Image can be useful if you want to manipulate individual pixels, load Textures in a background thread, or use the FFI to efficiently access the raw image data.
+---
+---@class lovr.Image
+local Image = {}
+
+---
+---Encodes the Image to an uncompressed png. This intended mainly for debugging.
+---
+---@return lovr.Blob blob # A new Blob containing the PNG image data.
+function Image:encode() end
+
+---
+---Returns a Blob containing the raw bytes of the Image.
+---
+---@return lovr.Blob blob # The Blob instance containing the bytes for the `Image`.
+function Image:getBlob() end
+
+---
+---Returns the dimensions of the Image, in pixels.
+---
+---@return number width # The width of the Image, in pixels.
+---@return number height # The height of the Image, in pixels.
+function Image:getDimensions() end
+
+---
+---Returns the format of the Image.
+---
+---@return lovr.TextureFormat format # The format of the pixels in the Image.
+function Image:getFormat() end
+
+---
+---Returns the height of the Image, in pixels.
+---
+---@return number height # The height of the Image, in pixels.
+function Image:getHeight() end
+
+---
+---Returns the value of a pixel of the Image.
+---
+---@param x number # The x coordinate of the pixel to get (0-indexed).
+---@param y number # The y coordinate of the pixel to get (0-indexed).
+---@return number r # The red component of the pixel, from 0.0 to 1.0.
+---@return number g # The green component of the pixel, from 0.0 to 1.0.
+---@return number b # The blue component of the pixel, from 0.0 to 1.0.
+---@return number a # The alpha component of the pixel, from 0.0 to 1.0.
+function Image:getPixel(x, y) end
+
+---
+---Returns the width of the Image, in pixels.
+---
+---@return number width # The width of the Image, in pixels.
+function Image:getWidth() end
+
+---
+---Copies a rectangle of pixels from one Image to this one.
+---
+---@param source lovr.Image # The Image to copy pixels from.
+---@param x? number # The x coordinate to paste to (0-indexed).
+---@param y? number # The y coordinate to paste to (0-indexed).
+---@param fromX? number # The x coordinate in the source to paste from (0-indexed).
+---@param fromY? number # The y coordinate in the source to paste from (0-indexed).
+---@param width? number # The width of the region to copy.
+---@param height? number # The height of the region to copy.
+function Image:paste(source, x, y, fromX, fromY, width, height) end
+
+---
+---Sets the value of a pixel of the Image.
+---
+---@param x number # The x coordinate of the pixel to set (0-indexed).
+---@param y number # The y coordinate of the pixel to set (0-indexed).
+---@param r number # The red component of the pixel, from 0.0 to 1.0.
+---@param g number # The green component of the pixel, from 0.0 to 1.0.
+---@param b number # The blue component of the pixel, from 0.0 to 1.0.
+---@param a? number # The alpha component of the pixel, from 0.0 to 1.0.
+function Image:setPixel(x, y, r, g, b, a) end
+
+---
+---A ModelData is a container object that loads and holds data contained in 3D model files. This can include a variety of things like the node structure of the asset, the vertex data it contains, contains, the `Image` and `Material` properties, and any included animations.
+---
+---The current supported formats are OBJ, glTF, and STL.
+---
+---Usually you can just load a `Model` directly, but using a `ModelData` can be helpful if you want to load models in a thread or access more low-level information about the Model.
+---
+---@class lovr.ModelData
+local ModelData = {}
+
+---
+---A Rasterizer is an object that parses a TTF file, decoding and rendering glyphs from it.
+---
+---Usually you can just use `Font` objects.
+---
+---@class lovr.Rasterizer
+local Rasterizer = {}
+
+---
+---Returns the advance metric of the font, in pixels. The advance is how many pixels the font advances horizontally after each glyph is rendered. This does not include kerning.
+---
+---@return number advance # The advance of the font, in pixels.
+function Rasterizer:getAdvance() end
+
+---
+---Returns the ascent metric of the font, in pixels. The ascent represents how far any glyph of the font ascends above the baseline.
+---
+---@return number ascent # The ascent of the font, in pixels.
+function Rasterizer:getAscent() end
+
+---
+---Returns the descent metric of the font, in pixels. The descent represents how far any glyph of the font descends below the baseline.
+---
+---@return number descent # The descent of the font, in pixels.
+function Rasterizer:getDescent() end
+
+---
+---Returns the number of glyphs stored in the font file.
+---
+---@return number count # The number of glyphs stored in the font file.
+function Rasterizer:getGlyphCount() end
+
+---
+---Returns the height metric of the font, in pixels.
+---
+---@return number height # The height of the font, in pixels.
+function Rasterizer:getHeight() end
+
+---
+---Returns the line height metric of the font, in pixels. This is how far apart lines are.
+---
+---@return number height # The line height of the font, in pixels.
+function Rasterizer:getLineHeight() end
+
+---
+---Check if the Rasterizer can rasterize a set of glyphs.
+---
+---@return boolean hasGlyphs # true if the Rasterizer can rasterize all of the supplied characters, false otherwise.
+function Rasterizer:hasGlyphs() end
+
+---
+---A Sound stores the data for a sound. The supported sound formats are OGG, WAV, and MP3. Sounds cannot be played directly. Instead, there are `Source` objects in `lovr.audio` that are used for audio playback. All Source objects are backed by one of these Sounds, and multiple Sources can share a single Sound to reduce memory usage.
+---
+---Metadata
+------
+---
+---Sounds hold a fixed number of frames. Each frame contains one audio sample for each channel. The `SampleFormat` of the Sound is the data type used for each sample (floating point, integer, etc.). The Sound has a `ChannelLayout`, representing the number of audio channels and how they map to speakers (mono, stereo, etc.). The sample rate of the Sound indicates how many frames should be played per second. The duration of the sound (in seconds) is the number of frames divided by the sample rate.
+---
+---Compression
+------
+---
+---Sounds can be compressed. Compressed sounds are stored compressed in memory and are decoded as they are played. This uses a lot less memory but increases CPU usage during playback. OGG and MP3 are compressed audio formats. When creating a sound from a compressed format, there is an option to immediately decode it, storing it uncompressed in memory. It can be a good idea to decode short sound effects, since they won't use very much memory even when uncompressed and it will improve CPU usage. Compressed sounds can not be written to using `Sound:setFrames`.
+---
+---Streams
+------
+---
+---Sounds can be created as a stream by passing `'stream'` as their contents when creating them. Audio frames can be written to the end of the stream, and read from the beginning. This works well for situations where data is being generated in real time or streamed in from some other data source.
+---
+---Sources can be backed by a stream and they'll just play whatever audio is pushed to the stream. The audio module also lets you use a stream as a "sink" for an audio device. For playback devices, this works like loopback, so the mixed audio from all playing Sources will get written to the stream. For capture devices, all the microphone input will get written to the stream. Conversion between sample formats, channel layouts, and sample rates will happen automatically.
+---
+---Keep in mind that streams can still only hold a fixed number of frames. If too much data is written before it is read, older frames will start to get overwritten. Similary, it's possible to read too much data without writing fast enough.
+---
+---Ambisonics
+------
+---
+---Ambisonic sounds can be imported from WAVs, but can not yet be played. Sounds with a `ChannelLayout` of `ambisonic` are stored as first-order full-sphere ambisonics using the AmbiX format (ACN channel ordering and SN3D channel normalization). The AMB format is supported for import and will automatically get converted to AmbiX. See `lovr.data.newSound` for more info.
+---
+---@class lovr.Sound
+local Sound = {}
+
+---
+---Returns a Blob containing the raw bytes of the Sound.
+---
+---@return lovr.Blob blob # The Blob instance containing the bytes for the `Sound`.
+function Sound:getBlob() end
+
+---
+---Returns the number of channels in the Sound. Mono sounds have 1 channel, stereo sounds have 2 channels, and ambisonic sounds have 4 channels.
+---
+---@return number channels # The number of channels in the sound.
+function Sound:getChannelCount() end
+
+---
+---Returns the channel layout of the Sound.
+---
+---@return lovr.ChannelLayout channels # The channel layout.
+function Sound:getChannelLayout() end
+
+---
+---Returns the duration of the Sound, in seconds.
+---
+---@return number duration # The duration of the Sound, in seconds.
+function Sound:getDuration() end
+
+---
+---Returns the sample format of the Sound.
+---
+---@return lovr.SampleFormat format # The data type of each sample.
+function Sound:getFormat() end
+
+---
+---Returns the number of frames in the Sound. A frame stores one sample for each channel.
+---
+---@return number frames # The number of frames in the Sound.
+function Sound:getFrameCount() end
+
+---
+---Reads frames from the Sound into a table, Blob, or another Sound.
+---
+---@overload fun(t: table, count: number, srcOffset: number, dstOffset: number):table, number
+---@overload fun(blob: lovr.Blob, count: number, srcOffset: number, dstOffset: number):number
+---@overload fun(sound: lovr.Sound, count: number, srcOffset: number, dstOffset: number):number
+---@param count? number # The number of frames to read. If nil, reads as many frames as possible.
+
+Compressed sounds will automatically be decoded.
+
+Reading from a stream will ignore the source offset and read the oldest frames.
+---@param srcOffset? number # A frame offset to apply to the sound when reading frames.
+---@return table t # A table containing audio frames.
+---@return number count # The number of frames read.
+function Sound:getFrames(count, srcOffset) end
+
+---
+---Returns the total number of samples in the Sound.
+---
+---@return number samples # The total number of samples in the Sound.
+function Sound:getSampleCount() end
+
+---
+---Returns the sample rate of the Sound, in Hz. This is the number of frames that are played every second. It's usually a high number like 48000.
+---
+---@return number frequency # The number of frames per second in the Sound.
+function Sound:getSampleRate() end
+
+---
+---Returns whether the Sound is compressed. Compressed sounds are loaded from compressed audio formats like MP3 and OGG. They use a lot less memory but require some extra CPU work during playback. Compressed sounds can not be modified using `Sound:setFrames`.
+---
+---@return boolean compressed # Whether the Sound is compressed.
+function Sound:isCompressed() end
+
+---
+---Returns whether the Sound is a stream.
+---
+---@return boolean stream # Whether the Sound is a stream.
+function Sound:isStream() end
+
+---
+---Writes frames to the Sound.
+---
+---@overload fun(blob: lovr.Blob, count: number, dstOffset: number, srcOffset: number):number
+---@overload fun(sound: lovr.Sound, count: number, dstOffset: number, srcOffset: number):number
+---@param t table # A table containing frames to write.
+---@param count? number # How many frames to write. If nil, writes as many as possible.
+---@param dstOffset? number # A frame offset to apply when writing the frames.
+---@param srcOffset? number # A frame, byte, or index offset to apply when reading frames from the source.
+---@return number count # The number of frames written.
+function Sound:setFrames(t, count, dstOffset, srcOffset) end
+
+---
+---Sounds can have different numbers of channels, and those channels can map to various speaker layouts.
+---
+---@class lovr.ChannelLayout
+---
+---1 channel.
+---
+---@field mono integer
+---
+---2 channels. The first channel is for the left speaker and the second is for the right.
+---
+---@field stereo integer
+---
+---4 channels. Ambisonic channels don't map directly to speakers but instead represent directions in 3D space, sort of like the images of a skybox. Currently, ambisonic sounds can only be loaded, not played.
+---
+---@field ambisonic integer
+
+---
+---Sounds can store audio samples as 16 bit integers or 32 bit floats.
+---
+---@class lovr.SampleFormat
+---
+---32 bit floating point samples (between -1.0 and 1.0).
+---
+---@field f32 integer
+---
+---16 bit integer samples (between -32768 and 32767).
+---
+---@field i16 integer
diff --git a/meta/3rd/lovr/library/lovr.event.lua b/meta/3rd/lovr/library/lovr.event.lua
new file mode 100644
index 00000000..416d955f
--- /dev/null
+++ b/meta/3rd/lovr/library/lovr.event.lua
@@ -0,0 +1,387 @@
+---@meta
+
+---
+---The `lovr.event` module handles events from the operating system.
+---
+---Due to its low-level nature, it's rare to use `lovr.event` in simple projects.
+---
+---@class lovr.event
+lovr.event = {}
+
+---
+---Clears the event queue, removing any unprocessed events.
+---
+function lovr.event.clear() end
+
+---
+---This function returns a Lua iterator for all of the unprocessed items in the event queue. Each event consists of a name as a string, followed by event-specific arguments. This function is called in the default implementation of `lovr.run`, so it is normally not necessary to poll for events yourself.
+---
+---@return function iterator # The iterator function, usable in a for loop.
+function lovr.event.poll() end
+
+---
+---Fills the event queue with unprocessed events from the operating system. This function should be called often, otherwise the operating system will consider the application unresponsive. This function is called in the default implementation of `lovr.run`.
+---
+function lovr.event.pump() end
+
+---
+---Pushes an event onto the event queue. It will be processed the next time `lovr.event.poll` is called. For an event to be processed properly, there needs to be a function in the `lovr.handlers` table with a key that's the same as the event name.
+---
+---@param name string # The name of the event.
+function lovr.event.push(name) end
+
+---
+---Pushes an event to quit. An optional number can be passed to set the exit code for the application. An exit code of zero indicates normal termination, whereas a nonzero exit code indicates that an error occurred.
+---
+---@param code? number # The exit code of the program.
+function lovr.event.quit(code) end
+
+---
+---Pushes an event to restart the framework.
+---
+function lovr.event.restart() end
+
+---
+---Keys that can be pressed on a keyboard. Notably, numpad keys are missing right now.
+---
+---@class lovr.KeyCode
+---
+---The A key.
+---
+---@field a integer
+---
+---The B key.
+---
+---@field b integer
+---
+---The C key.
+---
+---@field c integer
+---
+---The D key.
+---
+---@field d integer
+---
+---The E key.
+---
+---@field e integer
+---
+---The F key.
+---
+---@field f integer
+---
+---The G key.
+---
+---@field g integer
+---
+---The H key.
+---
+---@field h integer
+---
+---The I key.
+---
+---@field i integer
+---
+---The J key.
+---
+---@field j integer
+---
+---The K key.
+---
+---@field k integer
+---
+---The L key.
+---
+---@field l integer
+---
+---The M key.
+---
+---@field m integer
+---
+---The N key.
+---
+---@field n integer
+---
+---The O key.
+---
+---@field o integer
+---
+---The P key.
+---
+---@field p integer
+---
+---The Q key.
+---
+---@field q integer
+---
+---The R key.
+---
+---@field r integer
+---
+---The S key.
+---
+---@field s integer
+---
+---The T key.
+---
+---@field t integer
+---
+---The U key.
+---
+---@field u integer
+---
+---The V key.
+---
+---@field v integer
+---
+---The W key.
+---
+---@field w integer
+---
+---The X key.
+---
+---@field x integer
+---
+---The Y key.
+---
+---@field y integer
+---
+---The Z key.
+---
+---@field z integer
+---
+---The 0 key.
+---
+---@field ["0"] integer
+---
+---The 1 key.
+---
+---@field ["1"] integer
+---
+---The 2 key.
+---
+---@field ["2"] integer
+---
+---The 3 key.
+---
+---@field ["3"] integer
+---
+---The 4 key.
+---
+---@field ["4"] integer
+---
+---The 5 key.
+---
+---@field ["5"] integer
+---
+---The 6 key.
+---
+---@field ["6"] integer
+---
+---The 7 key.
+---
+---@field ["7"] integer
+---
+---The 8 key.
+---
+---@field ["8"] integer
+---
+---The 9 key.
+---
+---@field ["9"] integer
+---
+---The space bar.
+---
+---@field space integer
+---
+---The enter key.
+---
+---@field return integer
+---
+---The tab key.
+---
+---@field tab integer
+---
+---The escape key.
+---
+---@field escape integer
+---
+---The backspace key.
+---
+---@field backspace integer
+---
+---The up arrow key.
+---
+---@field up integer
+---
+---The down arrow key.
+---
+---@field down integer
+---
+---The left arrow key.
+---
+---@field left integer
+---
+---The right arrow key.
+---
+---@field right integer
+---
+---The home key.
+---
+---@field home integer
+---
+---The end key.
+---
+---@field end integer
+---
+---The page up key.
+---
+---@field pageup integer
+---
+---The page down key.
+---
+---@field pagedown integer
+---
+---The insert key.
+---
+---@field insert integer
+---
+---The delete key.
+---
+---@field delete integer
+---
+---The F1 key.
+---
+---@field f1 integer
+---
+---The F2 key.
+---
+---@field f2 integer
+---
+---The F3 key.
+---
+---@field f3 integer
+---
+---The F4 key.
+---
+---@field f4 integer
+---
+---The F5 key.
+---
+---@field f5 integer
+---
+---The F6 key.
+---
+---@field f6 integer
+---
+---The F7 key.
+---
+---@field f7 integer
+---
+---The F8 key.
+---
+---@field f8 integer
+---
+---The F9 key.
+---
+---@field f9 integer
+---
+---The F10 key.
+---
+---@field f10 integer
+---
+---The F11 key.
+---
+---@field f11 integer
+---
+---The F12 key.
+---
+---@field f12 integer
+---
+---The backtick/backquote/grave accent key.
+---
+---@field ["`"] integer
+---
+---The dash/hyphen/minus key.
+---
+---@field ["-"] integer
+---
+---The equal sign key.
+---
+---@field ["="] integer
+---
+---The left bracket key.
+---
+---@field ["["] integer
+---
+---The right bracket key.
+---
+---@field ["]"] integer
+---
+---The backslash key.
+---
+---@field ["\\"] integer
+---
+---The semicolon key.
+---
+---@field [";"] integer
+---
+---The single quote key.
+---
+---@field ["'"] integer
+---
+---The comma key.
+---
+---@field [","] integer
+---
+---The period key.
+---
+---@field ["."] integer
+---
+---The slash key.
+---
+---@field ["/"] integer
+---
+---The left control key.
+---
+---@field lctrl integer
+---
+---The left shift key.
+---
+---@field lshift integer
+---
+---The left alt key.
+---
+---@field lalt integer
+---
+---The left OS key (windows, command, super).
+---
+---@field lgui integer
+---
+---The right control key.
+---
+---@field rctrl integer
+---
+---The right shift key.
+---
+---@field rshift integer
+---
+---The right alt key.
+---
+---@field ralt integer
+---
+---The right OS key (windows, command, super).
+---
+---@field rgui integer
+---
+---The caps lock key.
+---
+---@field capslock integer
+---
+---The scroll lock key.
+---
+---@field scrolllock integer
+---
+---The numlock key.
+---
+---@field numlock integer
diff --git a/meta/3rd/lovr/library/lovr.filesystem.lua b/meta/3rd/lovr/library/lovr.filesystem.lua
new file mode 100644
index 00000000..37fe8e0e
--- /dev/null
+++ b/meta/3rd/lovr/library/lovr.filesystem.lua
@@ -0,0 +1,197 @@
+---@meta
+
+---
+---The `lovr.filesystem` module provides access to the filesystem.
+---
+---@class lovr.filesystem
+lovr.filesystem = {}
+
+---
+---Appends content to the end of a file.
+---
+---@overload fun(filename: string, blob: lovr.Blob):number
+---@param filename string # The file to append to.
+---@param content string # A string to write to the end of the file.
+---@return number bytes # The number of bytes actually appended to the file.
+function lovr.filesystem.append(filename, content) end
+
+---
+---Creates a directory in the save directory. Any parent directories that don't exist will also be created.
+---
+---@param path string # The directory to create, recursively.
+---@return boolean success # Whether the directory was created.
+function lovr.filesystem.createDirectory(path) end
+
+---
+---Returns the application data directory. This will be something like:
+---
+---- `C:\Users\user\AppData\Roaming` on Windows.
+---- `/home/user/.config` on Linux.
+---- `/Users/user/Library/Application Support` on macOS.
+---
+---@return string path # The absolute path to the appdata directory.
+function lovr.filesystem.getAppdataDirectory() end
+
+---
+---Returns a sorted table containing all files and folders in a single directory.
+---
+---@param path string # The directory.
+---@return lovr.items table # A table with a string for each file and subfolder in the directory.
+function lovr.filesystem.getDirectoryItems(path) end
+
+---
+---Returns the absolute path of the LÖVR executable.
+---
+---@return string path # The absolute path of the LÖVR executable, or `nil` if it is unknown.
+function lovr.filesystem.getExecutablePath() end
+
+---
+---Returns the identity of the game, which is used as the name of the save directory. The default is `default`. It can be changed using `t.identity` in `lovr.conf`.
+---
+---@return string identity # The name of the save directory, or `nil` if it isn't set.
+function lovr.filesystem.getIdentity() end
+
+---
+---Returns when a file was last modified, since some arbitrary time in the past.
+---
+---@param path string # The file to check.
+---@return number time # The modification time of the file, in seconds, or `nil` if it's unknown.
+function lovr.filesystem.getLastModified(path) end
+
+---
+---Get the absolute path of the mounted archive containing a path in the virtual filesystem. This can be used to determine if a file is in the game's source directory or the save directory.
+---
+---@param path string # The path to check.
+---@return string realpath # The absolute path of the mounted archive containing `path`.
+function lovr.filesystem.getRealDirectory(path) end
+
+---
+---Returns the require path. The require path is a semicolon-separated list of patterns that LÖVR will use to search for files when they are `require`d. Any question marks in the pattern will be replaced with the module that is being required. It is similar to Lua\'s `package.path` variable, but the main difference is that the patterns are relative to the virtual filesystem.
+---
+---@return string path # The semicolon separated list of search patterns.
+function lovr.filesystem.getRequirePath() end
+
+---
+---Returns the absolute path to the save directory.
+---
+---@return string path # The absolute path to the save directory.
+function lovr.filesystem.getSaveDirectory() end
+
+---
+---Returns the size of a file, in bytes.
+---
+---@param file string # The file.
+---@return number size # The size of the file, in bytes.
+function lovr.filesystem.getSize(file) end
+
+---
+---Get the absolute path of the project's source directory or archive.
+---
+---@return string path # The absolute path of the project's source, or `nil` if it's unknown.
+function lovr.filesystem.getSource() end
+
+---
+---Returns the absolute path of the user's home directory.
+---
+---@return string path # The absolute path of the user's home directory.
+function lovr.filesystem.getUserDirectory() end
+
+---
+---Returns the absolute path of the working directory. Usually this is where the executable was started from.
+---
+---@return string path # The current working directory, or `nil` if it's unknown.
+function lovr.filesystem.getWorkingDirectory() end
+
+---
+---Check if a path exists and is a directory.
+---
+---@param path string # The path to check.
+---@return boolean isDirectory # Whether or not the path is a directory.
+function lovr.filesystem.isDirectory(path) end
+
+---
+---Check if a path exists and is a file.
+---
+---@param path string # The path to check.
+---@return boolean isFile # Whether or not the path is a file.
+function lovr.filesystem.isFile(path) end
+
+---
+---Returns whether the current project source is fused to the executable.
+---
+---@return boolean fused # Whether or not the project is fused.
+function lovr.filesystem.isFused() end
+
+---
+---Load a file containing Lua code, returning a Lua chunk that can be run.
+---
+---@param filename string # The file to load.
+---@return function chunk # The runnable chunk.
+function lovr.filesystem.load(filename) end
+
+---
+---Mounts a directory or `.zip` archive, adding it to the virtual filesystem. This allows you to read files from it.
+---
+---@param path string # The path to mount.
+---@param mountpoint? string # The path in the virtual filesystem to mount to.
+---@param append? boolean # Whether the archive will be added to the end or the beginning of the search path.
+---@param root? string # A subdirectory inside the archive to use as the root. If `nil`, the actual root of the archive is used.
+---@return boolean success # Whether the archive was successfully mounted.
+function lovr.filesystem.mount(path, mountpoint, append, root) end
+
+---
+---Creates a new Blob that contains the contents of a file.
+---
+---@param filename string # The file to load.
+---@return lovr.Blob blob # The new Blob.
+function lovr.filesystem.newBlob(filename) end
+
+---
+---Read the contents of a file.
+---
+---@param filename string # The name of the file to read.
+---@param bytes? number # The number of bytes to read (if -1, all bytes will be read).
+---@return string contents # The contents of the file.
+---@return number bytes # The number of bytes read from the file.
+function lovr.filesystem.read(filename, bytes) end
+
+---
+---Remove a file or directory in the save directory.
+---
+---@param path string # The file or directory to remove.
+---@return boolean success # Whether the path was removed.
+function lovr.filesystem.remove(path) end
+
+---
+---Set the name of the save directory.
+---
+---@param identity string # The new name of the save directory.
+function lovr.filesystem.setIdentity(identity) end
+
+---
+---Sets the require path. The require path is a semicolon-separated list of patterns that LÖVR will use to search for files when they are `require`d. Any question marks in the pattern will be replaced with the module that is being required. It is similar to Lua\'s `package.path` variable, but the main difference is that the patterns are relative to the save directory and the project directory.
+---
+---@param path? string # An optional semicolon separated list of search patterns.
+function lovr.filesystem.setRequirePath(path) end
+
+---
+---Sets the location of the project's source. This can only be done once, and is usually done internally.
+---
+---@param identity string # The path containing the project's source.
+function lovr.filesystem.setSource(identity) end
+
+---
+---Unmounts a directory or archive previously mounted with `lovr.filesystem.mount`.
+---
+---@param path string # The path to unmount.
+---@return boolean success # Whether the archive was unmounted.
+function lovr.filesystem.unmount(path) end
+
+---
+---Write to a file.
+---
+---@overload fun(filename: string, blob: lovr.Blob):number
+---@param filename string # The file to write to.
+---@param content string # A string to write to the file.
+---@return number bytes # The number of bytes written.
+function lovr.filesystem.write(filename, content) end
diff --git a/meta/3rd/lovr/library/lovr.graphics.lua b/meta/3rd/lovr/library/lovr.graphics.lua
new file mode 100644
index 00000000..63b3596a
--- /dev/null
+++ b/meta/3rd/lovr/library/lovr.graphics.lua
@@ -0,0 +1,2055 @@
+---@meta
+
+---
+---The `lovr.graphics` module renders graphics to displays. Anything rendered using this module will automatically show up in the VR headset if one is connected, otherwise it will just show up in a window on the desktop.
+---
+---@class lovr.graphics
+lovr.graphics = {}
+
+---
+---Draws an arc.
+---
+---@overload fun(material: lovr.Material, x: number, y: number, z: number, radius: number, angle: number, ax: number, ay: number, az: number, start: number, end: number, segments: number)
+---@overload fun(mode: lovr.DrawStyle, transform: lovr.mat4, start: number, end: number, segments: number)
+---@overload fun(material: lovr.Material, transform: lovr.mat4, start: number, end: number, segments: number)
+---@overload fun(mode: lovr.DrawStyle, arcmode: lovr.ArcMode, x: number, y: number, z: number, radius: number, angle: number, ax: number, ay: number, az: number, start: number, end: number, segments: number)
+---@overload fun(material: lovr.Material, arcmode: lovr.ArcMode, x: number, y: number, z: number, radius: number, angle: number, ax: number, ay: number, az: number, start: number, end: number, segments: number)
+---@overload fun(mode: lovr.DrawStyle, arcmode: lovr.ArcMode, transform: lovr.mat4, start: number, end: number, segments: number)
+---@overload fun(material: lovr.Material, arcmode: lovr.ArcMode, transform: lovr.mat4, start: number, end: number, segments: number)
+---@param mode lovr.DrawStyle # Whether the arc is filled or outlined.
+---@param x? number # The x coordinate of the center of the arc.
+---@param y? number # The y coordinate of the center of the arc.
+---@param z? number # The z coordinate of the center of the arc.
+---@param radius? number # The radius of the arc, in meters.
+---@param angle? number # The rotation of the arc around its rotation axis, in radians.
+---@param ax? number # The x coordinate of the arc's axis of rotation.
+---@param ay? number # The y coordinate of the arc's axis of rotation.
+---@param az? number # The z coordinate of the arc's axis of rotation.
+---@param start? number # The starting angle of the arc, in radians.
+---@param end? number # The ending angle of the arc, in radians.
+---@param segments? number # The number of segments to use for the full circle. A smaller number of segments will be used, depending on how long the arc is.
+function lovr.graphics.arc(mode, x, y, z, radius, angle, ax, ay, az, start, end, segments) end
+
+---
+---Draws a box. This is similar to `lovr.graphics.cube` except you can have different values for the width, height, and depth of the box.
+---
+---@overload fun(material: lovr.Material, x: number, y: number, z: number, width: number, height: number, depth: number, angle: number, ax: number, ay: number, az: number)
+---@overload fun(mode: lovr.DrawStyle, transform: lovr.mat4)
+---@overload fun(material: lovr.Material, transform: lovr.mat4)
+---@param mode lovr.DrawStyle # How to draw the box.
+---@param x? number # The x coordinate of the center of the box.
+---@param y? number # The y coordinate of the center of the box.
+---@param z? number # The z coordinate of the center of the box.
+---@param width? number # The width of the box, in meters.
+---@param height? number # The height of the box, in meters.
+---@param depth? number # The depth of the box, in meters.
+---@param angle? number # The rotation of the box around its rotation axis, in radians.
+---@param ax? number # The x coordinate of the axis of rotation.
+---@param ay? number # The y coordinate of the axis of rotation.
+---@param az? number # The z coordinate of the axis of rotation.
+function lovr.graphics.box(mode, x, y, z, width, height, depth, angle, ax, ay, az) end
+
+---
+---Draws a 2D circle.
+---
+---@overload fun(material: lovr.Material, x: number, y: number, z: number, radius: number, angle: number, ax: number, ay: number, az: number, segments: number)
+---@overload fun(mode: lovr.DrawStyle, transform: lovr.mat4, segments: number)
+---@overload fun(material: lovr.Material, transform: lovr.mat4, segments: number)
+---@param mode lovr.DrawStyle # Whether the circle is filled or outlined.
+---@param x? number # The x coordinate of the center of the circle.
+---@param y? number # The y coordinate of the center of the circle.
+---@param z? number # The z coordinate of the center of the circle.
+---@param radius? number # The radius of the circle, in meters.
+---@param angle? number # The rotation of the circle around its rotation axis, in radians.
+---@param ax? number # The x coordinate of the circle's axis of rotation.
+---@param ay? number # The y coordinate of the circle's axis of rotation.
+---@param az? number # The z coordinate of the circle's axis of rotation.
+---@param segments? number # The number of segments to use for the circle geometry. Higher numbers increase smoothness but increase rendering cost slightly.
+function lovr.graphics.circle(mode, x, y, z, radius, angle, ax, ay, az, segments) end
+
+---
+---Clears the screen, resetting the color, depth, and stencil information to default values. This function is called automatically by `lovr.run` at the beginning of each frame to clear out the data from the previous frame.
+---
+---@overload fun(r: number, g: number, b: number, a: number, z: number, s: number)
+---@overload fun(hex: number)
+---@param color? boolean # Whether or not to clear color information on the screen.
+---@param depth? boolean # Whether or not to clear the depth information on the screen.
+---@param stencil? boolean # Whether or not to clear the stencil information on the screen.
+function lovr.graphics.clear(color, depth, stencil) end
+
+---
+---This function runs a compute shader on the GPU. Compute shaders must be created with `lovr.graphics.newComputeShader` and they should implement the `void compute();` GLSL function. Running a compute shader doesn't actually do anything, but the Shader can modify data stored in `Texture`s or `ShaderBlock`s to get interesting things to happen.
+---
+---When running the compute shader, you can specify the number of times to run it in 3 dimensions, which is useful to iterate over large numbers of elements like pixels or array elements.
+---
+---@param shader lovr.Shader # The compute shader to run.
+---@param x? number # The amount of times to run in the x direction.
+---@param y? number # The amount of times to run in the y direction.
+---@param z? number # The amount of times to run in the z direction.
+function lovr.graphics.compute(shader, x, y, z) end
+
+---
+---Create the desktop window, usually used to mirror the headset display.
+---
+---@param flags {width: number, height: number, fullscreen: boolean, resizable: boolean, msaa: number, title: string, icon: string, vsync: number} # Flags to customize the window's appearance and behavior.
+function lovr.graphics.createWindow(flags) end
+
+---
+---Draws a cube.
+---
+---@overload fun(material: lovr.Material, x: number, y: number, z: number, size: number, angle: number, ax: number, ay: number, az: number)
+---@overload fun(mode: lovr.DrawStyle, transform: lovr.mat4)
+---@overload fun(material: lovr.Material, transform: lovr.mat4)
+---@param mode lovr.DrawStyle # How to draw the cube.
+---@param x? number # The x coordinate of the center of the cube.
+---@param y? number # The y coordinate of the center of the cube.
+---@param z? number # The z coordinate of the center of the cube.
+---@param size? number # The size of the cube, in meters.
+---@param angle? number # The rotation of the cube around its rotation axis, in radians.
+---@param ax? number # The x coordinate of the cube's axis of rotation.
+---@param ay? number # The y coordinate of the cube's axis of rotation.
+---@param az? number # The z coordinate of the cube's axis of rotation.
+function lovr.graphics.cube(mode, x, y, z, size, angle, ax, ay, az) end
+
+---
+---Draws a cylinder.
+---
+---@overload fun(material: lovr.Material, x: number, y: number, z: number, length: number, angle: number, ax: number, ay: number, az: number, r1: number, r2: number, capped: boolean, segments: number)
+---@param x? number # The x coordinate of the center of the cylinder.
+---@param y? number # The y coordinate of the center of the cylinder.
+---@param z? number # The z coordinate of the center of the cylinder.
+---@param length? number # The length of the cylinder, in meters.
+---@param angle? number # The rotation of the cylinder around its rotation axis, in radians.
+---@param ax? number # The x coordinate of the cylinder's axis of rotation.
+---@param ay? number # The y coordinate of the cylinder's axis of rotation.
+---@param az? number # The z coordinate of the cylinder's axis of rotation.
+---@param r1? number # The radius of one end of the cylinder.
+---@param r2? number # The radius of the other end of the cylinder.
+---@param capped? boolean # Whether the top and bottom should be rendered.
+---@param segments? number # The number of radial segments to use for the cylinder. If nil, the segment count is automatically determined from the radii.
+function lovr.graphics.cylinder(x, y, z, length, angle, ax, ay, az, r1, r2, capped, segments) end
+
+---
+---Discards pixel information in the active Canvas or display. This is mostly used as an optimization hint for the GPU, and is usually most helpful on mobile devices.
+---
+---@param color? boolean # Whether or not to discard color information.
+---@param depth? boolean # Whether or not to discard depth information.
+---@param stencil? boolean # Whether or not to discard stencil information.
+function lovr.graphics.discard(color, depth, stencil) end
+
+---
+---Draws a fullscreen textured quad.
+---
+---@overload fun()
+---@param texture lovr.Texture # The texture to use.
+---@param u? number # The x component of the uv offset.
+---@param v? number # The y component of the uv offset.
+---@param w? number # The width of the Texture to render, in uv coordinates.
+---@param h? number # The height of the Texture to render, in uv coordinates.
+function lovr.graphics.fill(texture, u, v, w, h) end
+
+---
+---Flushes the internal queue of draw batches. Under normal circumstances this is done automatically when needed, but the ability to flush manually may be helpful if you're integrating a LÖVR project with some external rendering code.
+---
+function lovr.graphics.flush() end
+
+---
+---Returns whether or not alpha sampling is enabled. Alpha sampling is also known as alpha-to-coverage. When it is enabled, the alpha channel of a pixel is factored into how antialiasing is computed, so the edges of a transparent texture will be correctly antialiased.
+---
+---@return boolean enabled # Whether or not alpha sampling is enabled.
+function lovr.graphics.getAlphaSampling() end
+
+---
+---Returns the current background color. Color components are from 0.0 to 1.0.
+---
+---@return number r # The red component of the background color.
+---@return number g # The green component of the background color.
+---@return number b # The blue component of the background color.
+---@return number a # The alpha component of the background color.
+function lovr.graphics.getBackgroundColor() end
+
+---
+---Returns the current blend mode. The blend mode controls how each pixel's color is blended with the previous pixel's color when drawn.
+---
+---If blending is disabled, `nil` will be returned.
+---
+---@return lovr.BlendMode blend # The current blend mode.
+---@return lovr.BlendAlphaMode alphaBlend # The current alpha blend mode.
+function lovr.graphics.getBlendMode() end
+
+---
+---Returns the active Canvas. Usually when you render something it will render directly to the headset. If a Canvas object is active, things will be rendered to the textures attached to the Canvas instead.
+---
+---@return lovr.Canvas canvas # The active Canvas, or `nil` if no canvas is set.
+function lovr.graphics.getCanvas() end
+
+---
+---Returns the current global color factor. Color components are from 0.0 to 1.0. Every pixel drawn will be multiplied (i.e. tinted) by this color.
+---
+---@return number r # The red component of the color.
+---@return number g # The green component of the color.
+---@return number b # The blue component of the color.
+---@return number a # The alpha component of the color.
+function lovr.graphics.getColor() end
+
+---
+---Returns a boolean for each color channel (red, green, blue, alpha) indicating whether it is enabled. When a color channel is enabled, it will be affected by drawing commands and clear commands.
+---
+function lovr.graphics.getColorMask() end
+
+---
+---Returns the default filter mode for new Textures. This controls how textures are sampled when they are minified, magnified, or stretched.
+---
+---@return lovr.FilterMode mode # The filter mode.
+---@return number anisotropy # The level of anisotropy.
+function lovr.graphics.getDefaultFilter() end
+
+---
+---Returns the current depth test settings.
+---
+---@return lovr.CompareMode compareMode # The current comparison method for depth testing.
+---@return boolean write # Whether pixels will have their z value updated when rendered to.
+function lovr.graphics.getDepthTest() end
+
+---
+---Returns the dimensions of the desktop window.
+---
+---@return number width # The width of the window, in pixels.
+---@return number height # The height of the window, in pixels.
+function lovr.graphics.getDimensions() end
+
+---
+---Returns whether certain features are supported by the system\'s graphics card.
+---
+---@return {astc: boolean, compute: boolean, dxt: boolean, instancedstereo: boolean, multiview: boolean, timers: boolean} features # A table of features and whether or not they are supported.
+function lovr.graphics.getFeatures() end
+
+---
+---Returns the active font.
+---
+---@return lovr.Font font # The active font object.
+function lovr.graphics.getFont() end
+
+---
+---Returns the height of the desktop window.
+---
+---@return number height # The height of the window, in pixels.
+function lovr.graphics.getHeight() end
+
+---
+---Returns information about the maximum limits of the graphics card, such as the maximum texture size or the amount of supported antialiasing.
+---
+---@return {anisotropy: number, blocksize: number, pointsize: number, texturemsaa: number, texturesize: number, compute: table} limits # The table of limits.
+function lovr.graphics.getLimits() end
+
+---
+---Returns the current line width.
+---
+---@return number width # The current line width, in pixels.
+function lovr.graphics.getLineWidth() end
+
+---
+---Returns the pixel density of the window. On "high-dpi" displays, this will be `2.0`, indicating that there are 2 pixels for every window coordinate. On a normal display it will be `1.0`, meaning that the pixel to window-coordinate ratio is 1:1.
+---
+---@return number density # The pixel density of the window.
+function lovr.graphics.getPixelDensity() end
+
+---
+---Returns the current point size.
+---
+---@return number size # The current point size, in pixels.
+function lovr.graphics.getPointSize() end
+
+---
+---Returns the projection for a single view.
+---
+---@overload fun(view: number, matrix: lovr.Mat4):lovr.Mat4
+---@param view number # The view index.
+---@return number left # The left field of view angle, in radians.
+---@return number right # The right field of view angle, in radians.
+---@return number up # The top field of view angle, in radians.
+---@return number down # The bottom field of view angle, in radians.
+function lovr.graphics.getProjection(view) end
+
+---
+---Returns the active shader.
+---
+---@return lovr.Shader shader # The active shader object, or `nil` if none is active.
+function lovr.graphics.getShader() end
+
+---
+---Returns graphics-related performance statistics for the current frame.
+---
+---@return {drawcalls: number, renderpasses: number, shaderswitches: number, buffers: number, textures: number, buffermemory: number, texturememory: number} stats # The table of stats.
+function lovr.graphics.getStats() end
+
+---
+---Returns the current stencil test. The stencil test lets you mask out pixels that meet certain criteria, based on the contents of the stencil buffer. The stencil buffer can be modified using `lovr.graphics.stencil`. After rendering to the stencil buffer, the stencil test can be set to control how subsequent drawing functions are masked by the stencil buffer.
+---
+---@return lovr.CompareMode compareMode # The comparison method used to decide if a pixel should be visible, or nil if the stencil test is disabled.
+---@return number compareValue # The value stencil values are compared against, or nil if the stencil test is disabled.
+function lovr.graphics.getStencilTest() end
+
+---
+---Get the pose of a single view.
+---
+---@overload fun(view: number, matrix: lovr.Mat4, invert: boolean):lovr.Mat4
+---@param view number # The view index.
+---@return number x # The x position of the viewer, in meters.
+---@return number y # The y position of the viewer, in meters.
+---@return number z # The z position of the viewer, in meters.
+---@return number angle # The number of radians the viewer is rotated around its axis of rotation.
+---@return number ax # The x component of the axis of rotation.
+---@return number ay # The y component of the axis of rotation.
+---@return number az # The z component of the axis of rotation.
+function lovr.graphics.getViewPose(view) end
+
+---
+---Returns the width of the desktop window.
+---
+---@return number width # The width of the window, in pixels.
+function lovr.graphics.getWidth() end
+
+---
+---Returns the current polygon winding. The winding direction determines which face of a triangle is the front face and which is the back face. This lets the graphics engine cull the back faces of polygons, improving performance.
+---
+---@return lovr.Winding winding # The current winding direction.
+function lovr.graphics.getWinding() end
+
+---
+---Returns whether the desktop window is currently created.
+---
+---@return boolean present # Whether a window is created.
+function lovr.graphics.hasWindow() end
+
+---
+---Returns whether or not culling is active. Culling is an optimization that avoids rendering the back face of polygons. This improves performance by reducing the number of polygons drawn, but requires that the vertices in triangles are specified in a consistent clockwise or counter clockwise order.
+---
+---@return boolean isEnabled # Whether or not culling is enabled.
+function lovr.graphics.isCullingEnabled() end
+
+---
+---Returns a boolean indicating whether or not wireframe rendering is enabled.
+---
+---@return boolean isWireframe # Whether or not wireframe rendering is enabled.
+function lovr.graphics.isWireframe() end
+
+---
+---Draws lines between points. Each point will be connected to the previous point in the list.
+---
+---@overload fun(points: table)
+---@param x1 number # The x coordinate of the first point.
+---@param y1 number # The y coordinate of the first point.
+---@param z1 number # The z coordinate of the first point.
+---@param x2 number # The x coordinate of the second point.
+---@param y2 number # The y coordinate of the second point.
+---@param z2 number # The z coordinate of the second point.
+function lovr.graphics.line(x1, y1, z1, x2, y2, z2) end
+
+---
+---Creates a new Canvas. You can specify Textures to attach to it, or just specify a width and height and attach textures later using `Canvas:setTexture`.
+---
+---Once created, you can render to the Canvas using `Canvas:renderTo`, or `lovr.graphics.setCanvas`.
+---
+---@overload fun(..., flags: table):lovr.Canvas
+---@overload fun(attachments: table, flags: table):lovr.Canvas
+---@param width number # The width of the canvas, in pixels.
+---@param height number # The height of the canvas, in pixels.
+---@param flags? {format: lovr.TextureFormat, depth: lovr.TextureFormat, stereo: boolean, msaa: number, mipmaps: boolean} # Optional settings for the Canvas.
+---@return lovr.Canvas canvas # The new Canvas.
+function lovr.graphics.newCanvas(width, height, flags) end
+
+---
+---Creates a new compute Shader, used for running generic compute operations on the GPU.
+---
+---@param source string # The code or filename of the compute shader.
+---@param options? {flags: table} # Optional settings for the Shader.
+---@return lovr.Shader shader # The new compute Shader.
+function lovr.graphics.newComputeShader(source, options) end
+
+---
+---Creates a new Font. It can be used to render text with `lovr.graphics.print`.
+---
+---Currently, the only supported font format is TTF.
+---
+---@overload fun(size: number, padding: number, spread: number):lovr.Font
+---@overload fun(rasterizer: lovr.Rasterizer, padding: number, spread: number):lovr.Font
+---@param filename string # The filename of the font file.
+---@param size? number # The size of the font, in pixels.
+---@param padding? number # The number of pixels of padding around each glyph.
+---@param spread? number # The range of the distance field, in pixels.
+---@return lovr.Font font # The new Font.
+function lovr.graphics.newFont(filename, size, padding, spread) end
+
+---
+---Creates a new Material. Materials are sets of colors, textures, and other parameters that affect the appearance of objects. They can be applied to `Model`s, `Mesh`es, and most graphics primitives accept a Material as an optional first argument.
+---
+---@overload fun(texture: lovr.Texture, r: number, g: number, b: number, a: number):lovr.Material
+---@overload fun(canvas: lovr.Canvas, r: number, g: number, b: number, a: number):lovr.Material
+---@overload fun(r: number, g: number, b: number, a: number):lovr.Material
+---@overload fun(hex: number, a: number):lovr.Material
+---@return lovr.Material material # The new Material.
+function lovr.graphics.newMaterial() end
+
+---
+---Creates a new Mesh. Meshes contain the data for an arbitrary set of vertices, and can be drawn. You must specify either the capacity for the Mesh or an initial set of vertex data. Optionally, a custom format table can be used to specify the set of vertex attributes the mesh will provide to the active shader. The draw mode and usage hint can also optionally be specified.
+---
+---The default data type for an attribute is `float`, and the default component count is 1.
+---
+---@overload fun(vertices: table, mode: lovr.DrawMode, usage: lovr.MeshUsage, readable: boolean):lovr.Mesh
+---@overload fun(blob: lovr.Blob, mode: lovr.DrawMode, usage: lovr.MeshUsage, readable: boolean):lovr.Mesh
+---@overload fun(format: table, size: number, mode: lovr.DrawMode, usage: lovr.MeshUsage, readable: boolean):lovr.Mesh
+---@overload fun(format: table, vertices: table, mode: lovr.DrawMode, usage: lovr.MeshUsage, readable: boolean):lovr.Mesh
+---@overload fun(format: table, blob: lovr.Blob, mode: lovr.DrawMode, usage: lovr.MeshUsage, readable: boolean):lovr.Mesh
+---@param size number # The maximum number of vertices the Mesh can store.
+---@param mode? lovr.DrawMode # How the Mesh will connect its vertices into triangles.
+---@param usage? lovr.MeshUsage # An optimization hint indicating how often the data in the Mesh will be updated.
+---@param readable? boolean # Whether vertices from the Mesh can be read.
+---@return lovr.Mesh mesh # The new Mesh.
+function lovr.graphics.newMesh(size, mode, usage, readable) end
+
+---
+---Creates a new Model from a file. The supported 3D file formats are OBJ, glTF, and STL.
+---
+---@overload fun(modelData: lovr.ModelData):lovr.Model
+---@param filename string # The filename of the model to load.
+---@return lovr.Model model # The new Model.
+function lovr.graphics.newModel(filename) end
+
+---
+---Creates a new Shader.
+---
+---@overload fun(default: lovr.DefaultShader, options: table):lovr.Shader
+---@param vertex string # The code or filename of the vertex shader. If nil, the default vertex shader is used.
+---@param fragment string # The code or filename of the fragment shader. If nil, the default fragment shader is used.
+---@param options? {flags: table, stereo: boolean} # Optional settings for the Shader.
+---@return lovr.Shader shader # The new Shader.
+function lovr.graphics.newShader(vertex, fragment, options) end
+
+---
+---Creates a new ShaderBlock from a table of variable definitions with their names and types.
+---
+---@param type lovr.BlockType # Whether the block will be used for read-only uniform data or compute shaders.
+---@param uniforms table # A table where the keys are uniform names and the values are uniform types. Uniform arrays can be specified by supplying a table as the uniform's value containing the type and the array size.
+---@param flags? {usage: lovr.BufferUsage, readable: boolean} # Optional settings.
+---@return lovr.ShaderBlock shaderBlock # The new ShaderBlock.
+function lovr.graphics.newShaderBlock(type, uniforms, flags) end
+
+---
+---Creates a new Texture from an image file.
+---
+---@overload fun(images: table, flags: table):lovr.Texture
+---@overload fun(width: number, height: number, depth: number, flags: table):lovr.Texture
+---@overload fun(blob: lovr.Blob, flags: table):lovr.Texture
+---@overload fun(image: lovr.Image, flags: table):lovr.Texture
+---@param filename string # The filename of the image to load.
+---@param flags? {linear: boolean, mipmaps: boolean, type: lovr.TextureType, format: lovr.TextureFormat, msaa: number} # Optional settings for the texture.
+---@return lovr.Texture texture # The new Texture.
+function lovr.graphics.newTexture(filename, flags) end
+
+---
+---Resets the transformation to the origin.
+---
+function lovr.graphics.origin() end
+
+---
+---Draws a plane with a given position, size, and orientation.
+---
+---@overload fun(material: lovr.Material, x: number, y: number, z: number, width: number, height: number, angle: number, ax: number, ay: number, az: number, u: number, v: number, w: number, h: number)
+---@param mode lovr.DrawStyle # How to draw the plane.
+---@param x? number # The x coordinate of the center of the plane.
+---@param y? number # The y coordinate of the center of the plane.
+---@param z? number # The z coordinate of the center of the plane.
+---@param width? number # The width of the plane, in meters.
+---@param height? number # The height of the plane, in meters.
+---@param angle? number # The number of radians to rotate around the rotation axis.
+---@param ax? number # The x component of the rotation axis.
+---@param ay? number # The y component of the rotation axis.
+---@param az? number # The z component of the rotation axis.
+---@param u? number # The u coordinate of the texture.
+---@param v? number # The v coordinate of the texture.
+---@param w? number # The width of the texture UVs to render.
+---@param h? number # The height of the texture UVs to render.
+function lovr.graphics.plane(mode, x, y, z, width, height, angle, ax, ay, az, u, v, w, h) end
+
+---
+---Draws one or more points.
+---
+---@overload fun(points: table)
+---@param x number # The x coordinate of the point.
+---@param y number # The y coordinate of the point.
+---@param z number # The z coordinate of the point.
+function lovr.graphics.points(x, y, z) end
+
+---
+---Pops the current transform from the stack, returning to the transformation that was applied before `lovr.graphics.push` was called.
+---
+function lovr.graphics.pop() end
+
+---
+---Presents the results of pending drawing operations to the window. This is automatically called after `lovr.draw` by the default `lovr.run` function.
+---
+function lovr.graphics.present() end
+
+---
+---Draws text in 3D space using the active font.
+---
+---@param str string # The text to render.
+---@param x? number # The x coordinate of the center of the text.
+---@param y? number # The y coordinate of the center of the text.
+---@param z? number # The z coordinate of the center of the text.
+---@param scale? number # The scale of the text.
+---@param angle? number # The number of radians to rotate the text around its rotation axis.
+---@param ax? number # The x component of the axis of rotation.
+---@param ay? number # The y component of the axis of rotation.
+---@param az? number # The z component of the axis of rotation.
+---@param wrap? number # The maximum width of each line, in meters (before scale is applied). Set to 0 or nil for no wrapping.
+---@param halign? lovr.HorizontalAlign # The horizontal alignment.
+---@param valign? lovr.VerticalAlign # The vertical alignment.
+function lovr.graphics.print(str, x, y, z, scale, angle, ax, ay, az, wrap, halign, valign) end
+
+---
+---Pushes a copy of the current transform onto the transformation stack. After changing the transform using `lovr.graphics.translate`, `lovr.graphics.rotate`, and `lovr.graphics.scale`, the original state can be restored using `lovr.graphics.pop`.
+---
+function lovr.graphics.push() end
+
+---
+---Resets all graphics state to the initial values.
+---
+function lovr.graphics.reset() end
+
+---
+---Rotates the coordinate system around an axis.
+---
+---The rotation will last until `lovr.draw` returns or the transformation is popped off the transformation stack.
+---
+---@param angle? number # The amount to rotate the coordinate system by, in radians.
+---@param ax? number # The x component of the axis of rotation.
+---@param ay? number # The y component of the axis of rotation.
+---@param az? number # The z component of the axis of rotation.
+function lovr.graphics.rotate(angle, ax, ay, az) end
+
+---
+---Scales the coordinate system in 3 dimensions. This will cause objects to appear bigger or smaller.
+---
+---The scaling will last until `lovr.draw` returns or the transformation is popped off the transformation stack.
+---
+---@param x? number # The amount to scale on the x axis.
+---@param y? number # The amount to scale on the y axis.
+---@param z? number # The amount to scale on the z axis.
+function lovr.graphics.scale(x, y, z) end
+
+---
+---Enables or disables alpha sampling. Alpha sampling is also known as alpha-to-coverage. When it is enabled, the alpha channel of a pixel is factored into how antialiasing is computed, so the edges of a transparent texture will be correctly antialiased.
+---
+---@param enabled boolean # Whether or not alpha sampling is enabled.
+function lovr.graphics.setAlphaSampling(enabled) end
+
+---
+---Sets the background color used to clear the screen. Color components are from 0.0 to 1.0.
+---
+---@overload fun(hex: number, a: number)
+---@overload fun(color: table)
+---@param r number # The red component of the background color.
+---@param g number # The green component of the background color.
+---@param b number # The blue component of the background color.
+---@param a? number # The alpha component of the background color.
+function lovr.graphics.setBackgroundColor(r, g, b, a) end
+
+---
+---Sets the blend mode. The blend mode controls how each pixel's color is blended with the previous pixel's color when drawn.
+---
+---@overload fun()
+---@param blend lovr.BlendMode # The blend mode.
+---@param alphaBlend lovr.BlendAlphaMode # The alpha blend mode.
+function lovr.graphics.setBlendMode(blend, alphaBlend) end
+
+---
+---Sets or disables the active Canvas object. If there is an active Canvas, things will be rendered to the Textures attached to that Canvas instead of to the headset.
+---
+---@param canvas? lovr.Canvas # The new active Canvas object, or `nil` to just render to the headset.
+function lovr.graphics.setCanvas(canvas) end
+
+---
+---Sets the color used for drawing objects. Color components are from 0.0 to 1.0. Every pixel drawn will be multiplied (i.e. tinted) by this color. This is a global setting, so it will affect all subsequent drawing operations.
+---
+---@overload fun(hex: number, a: number)
+---@overload fun(color: table)
+---@param r number # The red component of the color.
+---@param g number # The green component of the color.
+---@param b number # The blue component of the color.
+---@param a? number # The alpha component of the color.
+function lovr.graphics.setColor(r, g, b, a) end
+
+---
+---Enables and disables individual color channels. When a color channel is enabled, it will be affected by drawing commands and clear commands.
+---
+---@param r boolean # Whether the red color channel should be enabled.
+---@param g boolean # Whether the green color channel should be enabled.
+---@param b boolean # Whether the blue color channel should be enabled.
+---@param a boolean # Whether the alpha color channel should be enabled.
+function lovr.graphics.setColorMask(r, g, b, a) end
+
+---
+---Enables or disables culling. Culling is an optimization that avoids rendering the back face of polygons. This improves performance by reducing the number of polygons drawn, but requires that the vertices in triangles are specified in a consistent clockwise or counter clockwise order.
+---
+---@param isEnabled boolean # Whether or not culling should be enabled.
+function lovr.graphics.setCullingEnabled(isEnabled) end
+
+---
+---Sets the default filter mode for new Textures. This controls how textures are sampled when they are minified, magnified, or stretched.
+---
+---@param mode lovr.FilterMode # The filter mode.
+---@param anisotropy number # The level of anisotropy to use.
+function lovr.graphics.setDefaultFilter(mode, anisotropy) end
+
+---
+---Sets the current depth test. The depth test controls how overlapping objects are rendered.
+---
+---@param compareMode? lovr.CompareMode # The new depth test. Use `nil` to disable the depth test.
+---@param write? boolean # Whether pixels will have their z value updated when rendered to.
+function lovr.graphics.setDepthTest(compareMode, write) end
+
+---
+---Sets the active font used to render text with `lovr.graphics.print`.
+---
+---@param font? lovr.Font # The font to use. If `nil`, the default font is used (Varela Round).
+function lovr.graphics.setFont(font) end
+
+---
+---Sets the width of lines rendered using `lovr.graphics.line`.
+---
+---@param width? number # The new line width, in pixels.
+function lovr.graphics.setLineWidth(width) end
+
+---
+---Sets the width of drawn points, in pixels.
+---
+---@param size? number # The new point size.
+function lovr.graphics.setPointSize(size) end
+
+---
+---Sets the projection for a single view. 4 field of view angles can be used, similar to the field of view returned by `lovr.headset.getViewAngles`. Alternatively, a projection matrix can be used for other types of projections like orthographic, oblique, etc.
+---
+---Two views are supported, one for each eye. When rendering to the headset, both projections are changed to match the ones used by the headset.
+---
+---@overload fun(view: number, matrix: lovr.Mat4)
+---@param view number # The index of the view to update.
+---@param left number # The left field of view angle, in radians.
+---@param right number # The right field of view angle, in radians.
+---@param up number # The top field of view angle, in radians.
+---@param down number # The bottom field of view angle, in radians.
+function lovr.graphics.setProjection(view, left, right, up, down) end
+
+---
+---Sets or disables the Shader used for drawing.
+---
+---@overload fun()
+---@param shader lovr.Shader # The shader to use.
+function lovr.graphics.setShader(shader) end
+
+---
+---Sets the stencil test. The stencil test lets you mask out pixels that meet certain criteria, based on the contents of the stencil buffer. The stencil buffer can be modified using `lovr.graphics.stencil`. After rendering to the stencil buffer, the stencil test can be set to control how subsequent drawing functions are masked by the stencil buffer.
+---
+---@overload fun()
+---@param compareMode lovr.CompareMode # The comparison method used to decide if a pixel should be visible, or nil if the stencil test is disabled.
+---@param compareValue number # The value to compare stencil values to.
+function lovr.graphics.setStencilTest(compareMode, compareValue) end
+
+---
+---Sets the pose for a single view. Objects rendered in this view will appear as though the camera is positioned using the given pose.
+---
+---Two views are supported, one for each eye. When rendering to the headset, both views are changed to match the estimated eye positions. These view poses are also available using `lovr.headset.getViewPose`.
+---
+---@overload fun(view: number, matrix: lovr.Mat4, inverted: boolean)
+---@param view number # The index of the view to update.
+---@param x number # The x position of the viewer, in meters.
+---@param y number # The y position of the viewer, in meters.
+---@param z number # The z position of the viewer, in meters.
+---@param angle number # The number of radians the viewer is rotated around its axis of rotation.
+---@param ax number # The x component of the axis of rotation.
+---@param ay number # The y component of the axis of rotation.
+---@param az number # The z component of the axis of rotation.
+function lovr.graphics.setViewPose(view, x, y, z, angle, ax, ay, az) end
+
+---
+---Sets the polygon winding. The winding direction determines which face of a triangle is the front face and which is the back face. This lets the graphics engine cull the back faces of polygons, improving performance. The default is counterclockwise.
+---
+---@param winding lovr.Winding # The new winding direction.
+function lovr.graphics.setWinding(winding) end
+
+---
+---Enables or disables wireframe rendering. This is meant to be used as a debugging tool.
+---
+---@param wireframe boolean # Whether or not wireframe rendering should be enabled.
+function lovr.graphics.setWireframe(wireframe) end
+
+---
+---Render a skybox from a texture. Two common kinds of skybox textures are supported: A 2D equirectangular texture with a spherical coordinates can be used, or a "cubemap" texture created from 6 images.
+---
+---@param texture lovr.Texture # The texture to use.
+function lovr.graphics.skybox(texture) end
+
+---
+---Draws a sphere.
+---
+---@overload fun(material: lovr.Material, x: number, y: number, z: number, radius: number, angle: number, ax: number, ay: number, az: number)
+---@param x? number # The x coordinate of the center of the sphere.
+---@param y? number # The y coordinate of the center of the sphere.
+---@param z? number # The z coordinate of the center of the sphere.
+---@param radius? number # The radius of the sphere, in meters.
+---@param angle? number # The rotation of the sphere around its rotation axis, in radians.
+---@param ax? number # The x coordinate of the sphere's axis of rotation.
+---@param ay? number # The y coordinate of the sphere's axis of rotation.
+---@param az? number # The z coordinate of the sphere's axis of rotation.
+function lovr.graphics.sphere(x, y, z, radius, angle, ax, ay, az) end
+
+---
+---Renders to the stencil buffer using a function.
+---
+---@overload fun(callback: function, action: lovr.StencilAction, value: number, initial: number)
+---@param callback function # The function that will be called to render to the stencil buffer.
+---@param action? lovr.StencilAction # How to modify the stencil value of pixels that are rendered to.
+---@param value? number # If `action` is "replace", this is the value that pixels are replaced with.
+---@param keep? boolean # If false, the stencil buffer will be cleared to zero before rendering.
+function lovr.graphics.stencil(callback, action, value, keep) end
+
+---
+---Starts a named timer on the GPU, which can be stopped using `lovr.graphics.tock`.
+---
+---@param label string # The name of the timer.
+function lovr.graphics.tick(label) end
+
+---
+---Stops a named timer on the GPU, previously started with `lovr.graphics.tick`.
+---
+---@param label string # The name of the timer.
+---@return number time # The number of seconds elapsed, or `nil` if the data isn't ready yet.
+function lovr.graphics.tock(label) end
+
+---
+---Apply a transform to the coordinate system, changing its translation, rotation, and scale using a single function. A `mat4` can also be used.
+---
+---The transformation will last until `lovr.draw` returns or the transformation is popped off the transformation stack.
+---
+---@overload fun(transform: lovr.mat4)
+---@param x? number # The x component of the translation.
+---@param y? number # The y component of the translation.
+---@param z? number # The z component of the translation.
+---@param sx? number # The x scale factor.
+---@param sy? number # The y scale factor.
+---@param sz? number # The z scale factor.
+---@param angle? number # The number of radians to rotate around the rotation axis.
+---@param ax? number # The x component of the axis of rotation.
+---@param ay? number # The y component of the axis of rotation.
+---@param az? number # The z component of the axis of rotation.
+function lovr.graphics.transform(x, y, z, sx, sy, sz, angle, ax, ay, az) end
+
+---
+---Translates the coordinate system in three dimensions. All graphics operations that use coordinates will behave as if they are offset by the translation value.
+---
+---The translation will last until `lovr.draw` returns or the transformation is popped off the transformation stack.
+---
+---@param x? number # The amount to translate on the x axis.
+---@param y? number # The amount to translate on the y axis.
+---@param z? number # The amount to translate on the z axis.
+function lovr.graphics.translate(x, y, z) end
+
+---
+---A Canvas is also known as a framebuffer or render-to-texture. It allows you to render to a texture instead of directly to the screen. This lets you postprocess or transform the results later before finally rendering them to the screen.
+---
+---After creating a Canvas, you can attach Textures to it using `Canvas:setTexture`.
+---
+---@class lovr.Canvas
+local Canvas = {}
+
+---
+---Returns the depth buffer used by the Canvas as a Texture. If the Canvas was not created with a readable depth buffer (the `depth.readable` flag in `lovr.graphics.newCanvas`), then this function will return `nil`.
+---
+---@return lovr.Texture texture # The depth Texture of the Canvas.
+function Canvas:getDepthTexture() end
+
+---
+---Returns the dimensions of the Canvas, its Textures, and its depth buffer.
+---
+---@return number width # The width of the Canvas, in pixels.
+---@return number height # The height of the Canvas, in pixels.
+function Canvas:getDimensions() end
+
+---
+---Returns the height of the Canvas, its Textures, and its depth buffer.
+---
+---@return number height # The height of the Canvas, in pixels.
+function Canvas:getHeight() end
+
+---
+---Returns the number of multisample antialiasing samples to use when rendering to the Canvas. Increasing this number will make the contents of the Canvas appear more smooth at the cost of performance. It is common to use powers of 2 for this value.
+---
+---@return number samples # The number of MSAA samples.
+function Canvas:getMSAA() end
+
+---
+---Returns the set of Textures currently attached to the Canvas.
+---
+function Canvas:getTexture() end
+
+---
+---Returns the width of the Canvas, its Textures, and its depth buffer.
+---
+---@return number width # The width of the Canvas, in pixels.
+function Canvas:getWidth() end
+
+---
+---Returns whether the Canvas was created with the `stereo` flag. Drawing something to a stereo Canvas will draw it to two viewports in the left and right half of the Canvas, using transform information from two different eyes.
+---
+---@return boolean stereo # Whether the Canvas is stereo.
+function Canvas:isStereo() end
+
+---
+---Returns a new Image containing the contents of a Texture attached to the Canvas.
+---
+---@param index? number # The index of the Texture to read from.
+---@return lovr.Image image # The new Image.
+function Canvas:newImage(index) end
+
+---
+---Renders to the Canvas using a function. All graphics functions inside the callback will affect the Canvas contents instead of directly rendering to the headset. This can be used in `lovr.update`.
+---
+---@param callback function # The function to use to render to the Canvas.
+function Canvas:renderTo(callback) end
+
+---
+---Attaches one or more Textures to the Canvas. When rendering to the Canvas, everything will be drawn to all attached Textures. You can attach different layers of an array, cubemap, or volume texture, and also attach different mipmap levels of Textures.
+---
+function Canvas:setTexture() end
+
+---
+---A Font is an object created from a TTF file. It can be used to render text with `lovr.graphics.print`.
+---
+---@class lovr.Font
+local Font = {}
+
+---
+---Returns the maximum distance that any glyph will extend above the Font's baseline. Units are generally in meters, see `Font:getPixelDensity`.
+---
+---@return number ascent # The ascent of the Font.
+function Font:getAscent() end
+
+---
+---Returns the baseline of the Font. This is where the characters "rest on", relative to the y coordinate of the drawn text. Units are generally in meters, see `Font:setPixelDensity`.
+---
+---@return number baseline # The baseline of the Font.
+function Font:getBaseline() end
+
+---
+---Returns the maximum distance that any glyph will extend below the Font's baseline. Units are generally in meters, see `Font:getPixelDensity` for more information. Note that due to the coordinate system for fonts, this is a negative value.
+---
+---@return number descent # The descent of the Font.
+function Font:getDescent() end
+
+---
+---Returns the height of a line of text. Units are in meters, see `Font:setPixelDensity`.
+---
+---@return number height # The height of a rendered line of text.
+function Font:getHeight() end
+
+---
+---Returns the current line height multiplier of the Font. The default is 1.0.
+---
+---@return number lineHeight # The line height.
+function Font:getLineHeight() end
+
+---
+---Returns the current pixel density for the Font. The default is 1.0. Normally, this is in pixels per meter. When rendering to a 2D texture, the units are pixels.
+---
+---@return number pixelDensity # The current pixel density.
+function Font:getPixelDensity() end
+
+---
+---Returns the underlying `Rasterizer` object for a Font.
+---
+---@return lovr.Rasterizer rasterizer # The rasterizer.
+function Font:getRasterizer() end
+
+---
+---Returns the width and line count of a string when rendered using the font, taking into account an optional wrap limit.
+---
+---@param text string # The text to get the width of.
+---@param wrap? number # The width at which to wrap lines, or 0 for no wrap.
+---@return number width # The maximum width of any line in the text.
+---@return number lines # The number of lines in the wrapped text.
+function Font:getWidth(text, wrap) end
+
+---
+---Returns whether the Font has a set of glyphs. Any combination of strings and numbers (corresponding to character codes) can be specified. This function will return true if the Font is able to render *all* of the glyphs.
+---
+---@return boolean has # Whether the Font has the glyphs.
+function Font:hasGlyphs() end
+
+---
+---Sets the line height of the Font, which controls how far lines apart lines are vertically separated. This value is a ratio and the default is 1.0.
+---
+---@param lineHeight number # The new line height.
+function Font:setLineHeight(lineHeight) end
+
+---
+---Sets the pixel density for the Font. Normally, this is in pixels per meter. When rendering to a 2D texture, the units are pixels.
+---
+---@overload fun()
+---@param pixelDensity number # The new pixel density.
+function Font:setPixelDensity(pixelDensity) end
+
+---
+---A Material is an object used to control how objects appear, through coloring, texturing, and shading. The Material itself holds sets of colors, textures, and other parameters that are made available to Shaders.
+---
+---@class lovr.Material
+local Material = {}
+
+---
+---Returns a color property for a Material. Different types of colors are supported for different lighting parameters. Colors default to `(1.0, 1.0, 1.0, 1.0)` and are gamma corrected.
+---
+---@param colorType? lovr.MaterialColor # The type of color to get.
+---@return number r # The red component of the color.
+---@return number g # The green component of the color.
+---@return number b # The blue component of the color.
+---@return number a # The alpha component of the color.
+function Material:getColor(colorType) end
+
+---
+---Returns a numeric property of a Material. Scalar properties default to 1.0.
+---
+---@param scalarType lovr.MaterialScalar # The type of property to get.
+---@return number x # The value of the property.
+function Material:getScalar(scalarType) end
+
+---
+---Returns a texture for a Material. Several predefined `MaterialTexture`s are supported. Any texture that is `nil` will use a single white pixel as a fallback.
+---
+---@param textureType? lovr.MaterialTexture # The type of texture to get.
+---@return lovr.Texture texture # The texture that is set, or `nil` if no texture is set.
+function Material:getTexture(textureType) end
+
+---
+---Returns the transformation applied to texture coordinates of the Material.
+---
+---@return number ox # The texture coordinate x offset.
+---@return number oy # The texture coordinate y offset.
+---@return number sx # The texture coordinate x scale.
+---@return number sy # The texture coordinate y scale.
+---@return number angle # The texture coordinate rotation, in radians.
+function Material:getTransform() end
+
+---
+---Sets a color property for a Material. Different types of colors are supported for different lighting parameters. Colors default to `(1.0, 1.0, 1.0, 1.0)` and are gamma corrected.
+---
+---@overload fun(r: number, g: number, b: number, a: number)
+---@overload fun(colorType: lovr.MaterialColor, hex: number, a: number)
+---@overload fun(hex: number, a: number)
+---@param colorType? lovr.MaterialColor # The type of color to set.
+---@param r number # The red component of the color.
+---@param g number # The green component of the color.
+---@param b number # The blue component of the color.
+---@param a? number # The alpha component of the color.
+function Material:setColor(colorType, r, g, b, a) end
+
+---
+---Sets a numeric property of a Material. Scalar properties default to 1.0.
+---
+---@param scalarType lovr.MaterialScalar # The type of property to set.
+---@param x number # The value of the property.
+function Material:setScalar(scalarType, x) end
+
+---
+---Sets a texture for a Material. Several predefined `MaterialTexture`s are supported. Any texture that is `nil` will use a single white pixel as a fallback.
+---
+---@overload fun(texture: lovr.Texture)
+---@param textureType? lovr.MaterialTexture # The type of texture to set.
+---@param texture lovr.Texture # The texture to apply, or `nil` to use the default.
+function Material:setTexture(textureType, texture) end
+
+---
+---Sets the transformation applied to texture coordinates of the Material. This lets you offset, scale, or rotate textures as they are applied to geometry.
+---
+---@param ox number # The texture coordinate x offset.
+---@param oy number # The texture coordinate y offset.
+---@param sx number # The texture coordinate x scale.
+---@param sy number # The texture coordinate y scale.
+---@param angle number # The texture coordinate rotation, in radians.
+function Material:setTransform(ox, oy, sx, sy, angle) end
+
+---
+---A Mesh is a low-level graphics object that stores and renders a list of vertices.
+---
+---Meshes are really flexible since you can pack pretty much whatever you want in them. This makes them great for rendering arbitrary geometry, but it also makes them kinda difficult to use since you have to place each vertex yourself.
+---
+---It's possible to batch geometry with Meshes too. Instead of drawing a shape 100 times, it's much faster to pack 100 copies of the shape into a Mesh and draw the Mesh once. Even storing just one copy in the Mesh and drawing that 100 times is usually faster.
+---
+---Meshes are also a good choice if you have an object that changes its shape over time.
+---
+---@class lovr.Mesh
+local Mesh = {}
+
+---
+---Attaches attributes from another Mesh onto this one. This can be used to share vertex data across multiple meshes without duplicating the data, and can also be used for instanced rendering by using the `divisor` parameter.
+---
+---@overload fun(mesh: lovr.Mesh, divisor: number, ...)
+---@overload fun(mesh: lovr.Mesh, divisor: number, attributes: table)
+---@param mesh lovr.Mesh # The Mesh to attach attributes from.
+---@param divisor? number # The attribute divisor for all attached attributes.
+function Mesh:attachAttributes(mesh, divisor) end
+
+---
+---Detaches attributes that were attached using `Mesh:attachAttributes`.
+---
+---@overload fun(mesh: lovr.Mesh, ...)
+---@overload fun(mesh: lovr.Mesh, attributes: table)
+---@param mesh lovr.Mesh # A Mesh. The names of all of the attributes from this Mesh will be detached.
+function Mesh:detachAttributes(mesh) end
+
+---
+---Draws the contents of the Mesh.
+---
+---@overload fun(transform: lovr.mat4, instances: number)
+---@param x? number # The x coordinate to draw the Mesh at.
+---@param y? number # The y coordinate to draw the Mesh at.
+---@param z? number # The z coordinate to draw the Mesh at.
+---@param scale? number # The scale to draw the Mesh at.
+---@param angle? number # The angle to rotate the Mesh around the axis of rotation, in radians.
+---@param ax? number # The x component of the axis of rotation.
+---@param ay? number # The y component of the axis of rotation.
+---@param az? number # The z component of the axis of rotation.
+---@param instances? number # The number of copies of the Mesh to draw.
+function Mesh:draw(x, y, z, scale, angle, ax, ay, az, instances) end
+
+---
+---Get the draw mode of the Mesh, which controls how the vertices are connected together.
+---
+---@return lovr.DrawMode mode # The draw mode of the Mesh.
+function Mesh:getDrawMode() end
+
+---
+---Retrieve the current draw range for the Mesh. The draw range is a subset of the vertices of the Mesh that will be drawn.
+---
+---@return number start # The index of the first vertex that will be drawn, or nil if no draw range is set.
+---@return number count # The number of vertices that will be drawn, or nil if no draw range is set.
+function Mesh:getDrawRange() end
+
+---
+---Get the Material applied to the Mesh.
+---
+---@return lovr.Material material # The current material applied to the Mesh.
+function Mesh:getMaterial() end
+
+---
+---Gets the data for a single vertex in the Mesh. The set of data returned depends on the Mesh's vertex format. The default vertex format consists of 8 floating point numbers: the vertex position, the vertex normal, and the texture coordinates.
+---
+---@param index number # The index of the vertex to retrieve.
+function Mesh:getVertex(index) end
+
+---
+---Returns the components of a specific attribute of a single vertex in the Mesh.
+---
+---@param index number # The index of the vertex to retrieve the attribute of.
+---@param attribute number # The index of the attribute to retrieve the components of.
+function Mesh:getVertexAttribute(index, attribute) end
+
+---
+---Returns the maximum number of vertices the Mesh can hold.
+---
+---@return number size # The number of vertices the Mesh can hold.
+function Mesh:getVertexCount() end
+
+---
+---Get the format table of the Mesh's vertices. The format table describes the set of data that each vertex contains.
+---
+---@return table format # The table of vertex attributes. Each attribute is a table containing the name of the attribute, the `AttributeType`, and the number of components.
+function Mesh:getVertexFormat() end
+
+---
+---Returns the current vertex map for the Mesh. The vertex map is a list of indices in the Mesh, allowing the reordering or reuse of vertices.
+---
+---@overload fun(t: table):table
+---@overload fun(blob: lovr.Blob)
+---@return table map # The list of indices in the vertex map, or `nil` if no vertex map is set.
+function Mesh:getVertexMap() end
+
+---
+---Returns whether or not a vertex attribute is enabled. Disabled attributes won't be sent to shaders.
+---
+---@param attribute string # The name of the attribute.
+---@return boolean enabled # Whether or not the attribute is enabled when drawing the Mesh.
+function Mesh:isAttributeEnabled(attribute) end
+
+---
+---Sets whether a vertex attribute is enabled. Disabled attributes won't be sent to shaders.
+---
+---@param attribute string # The name of the attribute.
+---@param enabled boolean # Whether or not the attribute is enabled when drawing the Mesh.
+function Mesh:setAttributeEnabled(attribute, enabled) end
+
+---
+---Set a new draw mode for the Mesh.
+---
+---@param mode lovr.DrawMode # The new draw mode for the Mesh.
+function Mesh:setDrawMode(mode) end
+
+---
+---Set the draw range for the Mesh. The draw range is a subset of the vertices of the Mesh that will be drawn.
+---
+---@overload fun()
+---@param start number # The first vertex that will be drawn.
+---@param count number # The number of vertices that will be drawn.
+function Mesh:setDrawRange(start, count) end
+
+---
+---Applies a Material to the Mesh. This will cause it to use the Material's properties whenever it is rendered.
+---
+---@param material lovr.Material # The Material to apply.
+function Mesh:setMaterial(material) end
+
+---
+---Update a single vertex in the Mesh.
+---
+---@param index number # The index of the vertex to set.
+function Mesh:setVertex(index) end
+
+---
+---Set the components of a specific attribute of a vertex in the Mesh.
+---
+---@param index number # The index of the vertex to update.
+---@param attribute number # The index of the attribute to update.
+function Mesh:setVertexAttribute(index, attribute) end
+
+---
+---Sets the vertex map. The vertex map is a list of indices in the Mesh, allowing the reordering or reuse of vertices.
+---
+---Often, a vertex map is used to improve performance, since it usually requires less data to specify the index of a vertex than it does to specify all of the data for a vertex.
+---
+---@overload fun(blob: lovr.Blob, size: number)
+---@param map table # The new vertex map. Each element of the table is an index of a vertex.
+function Mesh:setVertexMap(map) end
+
+---
+---Updates multiple vertices in the Mesh.
+---
+---@overload fun(blob: lovr.Blob, start: number, count: number)
+---@param vertices table # The new set of vertices.
+---@param start? number # The index of the vertex to start replacing at.
+---@param count? number # The number of vertices to replace. If nil, all vertices will be used.
+function Mesh:setVertices(vertices, start, count) end
+
+---
+---A Model is a drawable object loaded from a 3D file format. The supported 3D file formats are OBJ, glTF, and STL.
+---
+---@class lovr.Model
+local Model = {}
+
+---
+---Applies an animation to the current pose of the Model.
+---
+---The animation is evaluated at the specified timestamp, and mixed with the current pose of the Model using the alpha value. An alpha value of 1.0 will completely override the pose of the Model with the animation's pose.
+---
+---@overload fun(index: number, time: number, alpha: number)
+---@param name string # The name of an animation.
+---@param time number # The timestamp to evaluate the keyframes at, in seconds.
+---@param alpha? number # How much of the animation to mix in, from 0 to 1.
+function Model:animate(name, time, alpha) end
+
+---
+---Draw the Model.
+---
+---@overload fun(transform: lovr.mat4, instances: number)
+---@param x? number # The x coordinate to draw the Model at.
+---@param y? number # The y coordinate to draw the Model at.
+---@param z? number # The z coordinate to draw the Model at.
+---@param scale? number # The scale to draw the Model at.
+---@param angle? number # The angle to rotate the Model around the axis of rotation, in radians.
+---@param ax? number # The x component of the axis of rotation.
+---@param ay? number # The y component of the axis of rotation.
+---@param az? number # The z component of the axis of rotation.
+---@param instances? number # The number of copies of the Model to draw.
+function Model:draw(x, y, z, scale, angle, ax, ay, az, instances) end
+
+---
+---Returns a bounding box that encloses the vertices of the Model.
+---
+---@return number minx # The minimum x coordinate of the box.
+---@return number maxx # The maximum x coordinate of the box.
+---@return number miny # The minimum y coordinate of the box.
+---@return number maxy # The maximum y coordinate of the box.
+---@return number minz # The minimum z coordinate of the box.
+---@return number maxz # The maximum z coordinate of the box.
+function Model:getAABB() end
+
+---
+---Returns the number of animations in the Model.
+---
+---@return number count # The number of animations in the Model.
+function Model:getAnimationCount() end
+
+---
+---Returns the duration of an animation in the Model, in seconds.
+---
+function Model:getAnimationDuration() end
+
+---
+---Returns the name of one of the animations in the Model.
+---
+---@param index number # The index of the animation to get the name of.
+---@return string name # The name of the animation.
+function Model:getAnimationName(index) end
+
+---
+---Returns a Material loaded from the Model, by name or index.
+---
+---This includes `Texture` objects and other properties like colors, metalness/roughness, and more.
+---
+---@overload fun(index: number):lovr.Material
+---@param name string # The name of the Material to return.
+---@return lovr.Material material # The material.
+function Model:getMaterial(name) end
+
+---
+---Returns the number of materials in the Model.
+---
+---@return number count # The number of materials in the Model.
+function Model:getMaterialCount() end
+
+---
+---Returns the name of one of the materials in the Model.
+---
+---@param index number # The index of the material to get the name of.
+---@return string name # The name of the material.
+function Model:getMaterialName(index) end
+
+---
+---Returns the number of nodes (bones) in the Model.
+---
+---@return number count # The number of nodes in the Model.
+function Model:getNodeCount() end
+
+---
+---Returns the name of one of the nodes (bones) in the Model.
+---
+---@param index number # The index of the node to get the name of.
+---@return string name # The name of the node.
+function Model:getNodeName(index) end
+
+---
+---Returns the pose of a single node in the Model in a given `CoordinateSpace`.
+---
+---@overload fun(index: number, space: lovr.CoordinateSpace):number, number, number, number, number, number, number
+---@param name string # The name of the node.
+---@param space? lovr.CoordinateSpace # Whether the pose should be returned relative to the node's parent or relative to the root node of the Model.
+---@return number x # The x position of the node.
+---@return number y # The y position of the node.
+---@return number z # The z position of the node.
+---@return number angle # The number of radians the node is rotated around its rotational axis.
+---@return number ax # The x component of the axis of rotation.
+---@return number ay # The y component of the axis of rotation.
+---@return number az # The z component of the axis of rotation.
+function Model:getNodePose(name, space) end
+
+---
+---Returns 2 tables containing mesh data for the Model.
+---
+---The first table is a list of vertex positions and contains 3 numbers for the x, y, and z coordinate of each vertex. The second table is a list of triangles and contains 1-based indices into the first table representing the first, second, and third vertices that make up each triangle.
+---
+---The vertex positions will be affected by node transforms.
+---
+---@return table vertices # A flat table of numbers containing vertex positions.
+---@return table indices # A flat table of numbers containing triangle vertex indices.
+function Model:getTriangles() end
+
+---
+---Returns whether the Model has any nodes associated with animated joints. This can be used to approximately determine whether an animated shader needs to be used with an arbitrary Model.
+---
+---@return boolean skeletal # Whether the Model has any nodes that use skeletal animation.
+function Model:hasJoints() end
+
+---
+---Applies a pose to a single node of the Model. The input pose is assumed to be relative to the pose of the node's parent. This is useful for applying inverse kinematics (IK) to a chain of bones in a skeleton.
+---
+---The alpha parameter can be used to mix between the node's current pose and the input pose.
+---
+---@overload fun(index: number, x: number, y: number, z: number, angle: number, ax: number, ay: number, az: number, alpha: number)
+---@overload fun()
+---@param name string # The name of the node.
+---@param x number # The x position.
+---@param y number # The y position.
+---@param z number # The z position.
+---@param angle number # The angle of rotation around the axis, in radians.
+---@param ax number # The x component of the rotation axis.
+---@param ay number # The y component of the rotation axis.
+---@param az number # The z component of the rotation axis.
+---@param alpha? number # How much of the pose to mix in, from 0 to 1.
+function Model:pose(name, x, y, z, angle, ax, ay, az, alpha) end
+
+---
+---Shaders are GLSL programs that transform the way vertices and pixels show up on the screen. They can be used for lighting, postprocessing, particles, animation, and much more. You can use `lovr.graphics.setShader` to change the active Shader.
+---
+---@class lovr.Shader
+local Shader = {}
+
+---
+---Returns the type of the Shader, which will be "graphics" or "compute".
+---
+---Graphics shaders are created with `lovr.graphics.newShader` and can be used for rendering with `lovr.graphics.setShader`. Compute shaders are created with `lovr.graphics.newComputeShader` and can be run using `lovr.graphics.compute`.
+---
+---@return lovr.ShaderType type # The type of the Shader.
+function Shader:getType() end
+
+---
+---Returns whether a Shader has a block.
+---
+---A block is added to the Shader code at creation time using `ShaderBlock:getShaderCode`. The block name (not the namespace) is used to link up the ShaderBlock object to the Shader. This function can be used to check if a Shader was created with a block using the given name.
+---
+---@param block string # The name of the block.
+---@return boolean present # Whether the shader has the specified block.
+function Shader:hasBlock(block) end
+
+---
+---Returns whether a Shader has a particular uniform variable.
+---
+---@param uniform string # The name of the uniform variable.
+---@return boolean present # Whether the shader has the specified uniform.
+function Shader:hasUniform(uniform) end
+
+---
+---Updates a uniform variable in the Shader.
+---
+---@param uniform string # The name of the uniform to update.
+---@param value any # The new value of the uniform.
+---@return boolean success # Whether the uniform exists and was updated.
+function Shader:send(uniform, value) end
+
+---
+---Sends a ShaderBlock to a Shader. After the block is sent, you can update the data in the block without needing to resend the block. The block can be sent to multiple shaders and they will all see the same data from the block.
+---
+---@param name string # The name of the block to send to.
+---@param block lovr.ShaderBlock # The ShaderBlock to associate with the specified block.
+---@param access? lovr.UniformAccess # How the Shader will use this block (used as an optimization hint).
+function Shader:sendBlock(name, block, access) end
+
+---
+---Sends a Texture to a Shader for writing. This is meant to be used with compute shaders and only works with uniforms declared as `image2D`, `imageCube`, `image2DArray`, and `image3D`. The normal `Shader:send` function accepts Textures and should be used most of the time.
+---
+---@overload fun(name: string, index: number, texture: lovr.Texture, slice: number, mipmap: number, access: lovr.UniformAccess)
+---@param name string # The name of the image uniform.
+---@param texture lovr.Texture # The Texture to assign.
+---@param slice? number # The slice of a cube, array, or volume texture to use, or `nil` for all slices.
+---@param mipmap? number # The mipmap of the texture to use.
+---@param access? lovr.UniformAccess # Whether the image will be read from, written to, or both.
+function Shader:sendImage(name, texture, slice, mipmap, access) end
+
+---
+---ShaderBlocks are objects that can hold large amounts of data and can be sent to Shaders. It is common to use "uniform" variables to send data to shaders, but uniforms are usually limited to a few kilobytes in size. ShaderBlocks are useful for a few reasons:
+---
+---- They can hold a lot more data.
+---- Shaders can modify the data in them, which is really useful for compute shaders.
+---- Setting the data in a ShaderBlock updates the data for all Shaders using the block, so you
+--- don't need to go around setting the same uniforms in lots of different shaders.
+---
+---On systems that support compute shaders, ShaderBlocks can optionally be "writable". A writable ShaderBlock is a little bit slower than a non-writable one, but shaders can modify its contents and it can be much, much larger than a non-writable ShaderBlock.
+---
+---@class lovr.ShaderBlock
+local ShaderBlock = {}
+
+---
+---Returns the byte offset of a variable in a ShaderBlock. This is useful if you want to manually send binary data to the ShaderBlock using a `Blob` in `ShaderBlock:send`.
+---
+---@param field string # The name of the variable to get the offset of.
+---@return number offset # The byte offset of the variable.
+function ShaderBlock:getOffset(field) end
+
+---
+---Before a ShaderBlock can be used in a Shader, the Shader has to have the block's variables defined in its source code. This can be a tedious process, so you can call this function to return a GLSL string that contains this definition. Roughly, it will look something like this:
+---
+--- layout(std140) uniform <label> {
+--- <type> <name>[<count>];
+--- } <namespace>;
+---
+---@param label string # The label of the block in the shader code. This will be used to identify it when using `Shader:sendBlock`.
+---@param namespace? string # The namespace to use when accessing the block's variables in the shader code. This can be used to prevent naming conflicts if two blocks have variables with the same name. If the namespace is nil, the block's variables will be available in the global scope.
+---@return string code # The code that can be prepended to `Shader` code.
+function ShaderBlock:getShaderCode(label, namespace) end
+
+---
+---Returns the size of the ShaderBlock's data, in bytes.
+---
+---@return number size # The size of the ShaderBlock, in bytes.
+function ShaderBlock:getSize() end
+
+---
+---Returns the type of the ShaderBlock.
+---
+---@return lovr.BlockType type # The type of the ShaderBlock.
+function ShaderBlock:getType() end
+
+---
+---Returns a variable in the ShaderBlock.
+---
+---@param name string # The name of the variable to read.
+---@return any value # The value of the variable.
+function ShaderBlock:read(name) end
+
+---
+---Updates a variable in the ShaderBlock.
+---
+---@overload fun(blob: lovr.Blob, offset: number, extent: number):number
+---@param variable string # The name of the variable to update.
+---@param value any # The new value of the uniform.
+function ShaderBlock:send(variable, value) end
+
+---
+---A Texture is an image that can be applied to `Material`s. The supported file formats are `.png`, `.jpg`, `.hdr`, `.dds`, `.ktx`, and `.astc`. DDS and ASTC are compressed formats, which are recommended because they're smaller and faster.
+---
+---@class lovr.Texture
+local Texture = {}
+
+---
+---Returns the compare mode for the texture.
+---
+---@return lovr.CompareMode compareMode # The current compare mode, or `nil` if none is set.
+function Texture:getCompareMode() end
+
+---
+---Returns the depth of the Texture, or the number of images stored in the Texture.
+---
+---@param mipmap? number # The mipmap level to get the depth of. This is only valid for volume textures.
+---@return number depth # The depth of the Texture.
+function Texture:getDepth(mipmap) end
+
+---
+---Returns the dimensions of the Texture.
+---
+---@param mipmap? number # The mipmap level to get the dimensions of.
+---@return number width # The width of the Texture, in pixels.
+---@return number height # The height of the Texture, in pixels.
+---@return number depth # The number of images stored in the Texture, for non-2D textures.
+function Texture:getDimensions(mipmap) end
+
+---
+---Returns the current FilterMode for the Texture.
+---
+---@return lovr.FilterMode mode # The filter mode for the Texture.
+---@return number anisotropy # The level of anisotropic filtering.
+function Texture:getFilter() end
+
+---
+---Returns the format of the Texture. This describes how many color channels are in the texture as well as the size of each one. The most common format used is `rgba`, which contains red, green, blue, and alpha color channels. See `TextureFormat` for all of the possible formats.
+---
+---@return lovr.TextureFormat format # The format of the Texture.
+function Texture:getFormat() end
+
+---
+---Returns the height of the Texture.
+---
+---@param mipmap? number # The mipmap level to get the height of.
+---@return number height # The height of the Texture, in pixels.
+function Texture:getHeight(mipmap) end
+
+---
+---Returns the number of mipmap levels of the Texture.
+---
+---@return number mipmaps # The number of mipmap levels in the Texture.
+function Texture:getMipmapCount() end
+
+---
+---Returns the type of the Texture.
+---
+---@return lovr.TextureType type # The type of the Texture.
+function Texture:getType() end
+
+---
+---Returns the width of the Texture.
+---
+---@param mipmap? number # The mipmap level to get the width of.
+---@return number width # The width of the Texture, in pixels.
+function Texture:getWidth(mipmap) end
+
+---
+---Returns the current WrapMode for the Texture.
+---
+---@return lovr.WrapMode horizontal # How the texture wraps horizontally.
+---@return lovr.WrapMode vertical # How the texture wraps vertically.
+function Texture:getWrap() end
+
+---
+---Replaces pixels in the Texture, sourcing from an `Image` object.
+---
+---@param image lovr.Image # The Image containing the pixels to use. Currently, the Image needs to have the same dimensions as the source Texture.
+---@param x? number # The x offset to replace at.
+---@param y? number # The y offset to replace at.
+---@param slice? number # The slice to replace. Not applicable for 2D textures.
+---@param mipmap? number # The mipmap to replace.
+function Texture:replacePixels(image, x, y, slice, mipmap) end
+
+---
+---Sets the compare mode for a texture. This is only used for "shadow samplers", which are uniform variables in shaders with type `sampler2DShadow`. Sampling a shadow sampler uses a sort of virtual depth test, and the compare mode of the texture is used to control how the depth test is performed.
+---
+---@param compareMode? lovr.CompareMode # The new compare mode. Use `nil` to disable the compare mode.
+function Texture:setCompareMode(compareMode) end
+
+---
+---Sets the `FilterMode` used by the texture.
+---
+---@param mode lovr.FilterMode # The filter mode.
+---@param anisotropy number # The level of anisotropy to use.
+function Texture:setFilter(mode, anisotropy) end
+
+---
+---Sets the wrap mode of a texture. The wrap mode controls how the texture is sampled when texture coordinates lie outside the usual 0 - 1 range. The default for both directions is `repeat`.
+---
+---@param horizontal lovr.WrapMode # How the texture should wrap horizontally.
+---@param vertical? lovr.WrapMode # How the texture should wrap vertically.
+function Texture:setWrap(horizontal, vertical) end
+
+---
+---Different ways arcs can be drawn with `lovr.graphics.arc`.
+---
+---@class lovr.ArcMode
+---
+---The arc is drawn with the center of its circle included in the list of points (default).
+---
+---@field pie integer
+---
+---The curve of the arc is drawn as a single line.
+---
+---@field open integer
+---
+---The starting and ending points of the arc's curve are connected.
+---
+---@field closed integer
+
+---
+---Here are the different data types available for vertex attributes in a Mesh. The ones that have a smaller range take up less memory, which improves performance a bit. The "u" stands for "unsigned", which means it can't hold negative values but instead has a larger positive range.
+---
+---@class lovr.AttributeType
+---
+---A signed 8 bit number, from -128 to 127.
+---
+---@field byte integer
+---
+---An unsigned 8 bit number, from 0 to 255.
+---
+---@field ubyte integer
+---
+---A signed 16 bit number, from -32768 to 32767.
+---
+---@field short integer
+---
+---An unsigned 16 bit number, from 0 to 65535.
+---
+---@field ushort integer
+---
+---A signed 32 bit number, from -2147483648 to 2147483647.
+---
+---@field int integer
+---
+---An unsigned 32 bit number, from 0 to 4294967295.
+---
+---@field uint integer
+---
+---A 32 bit floating-point number (large range, but can start to lose precision).
+---
+---@field float integer
+
+---
+---Different ways the alpha channel of pixels affects blending.
+---
+---@class lovr.BlendAlphaMode
+---
+---Color channel values are multiplied by the alpha channel during blending.
+---
+---@field alphamultiply integer
+---
+---Color channels are not multiplied by the alpha channel. This should be used if the pixels being drawn have already been blended, or "pre-multiplied", by the alpha channel.
+---
+---@field premultiplied integer
+
+---
+---Blend modes control how overlapping pixels are blended together, similar to layers in Photoshop.
+---
+---@class lovr.BlendMode
+---
+---Normal blending where the alpha value controls how the colors are blended.
+---
+---@field alpha integer
+---
+---The incoming pixel color is added to the destination pixel color.
+---
+---@field add integer
+---
+---The incoming pixel color is subtracted from the destination pixel color.
+---
+---@field subtract integer
+---
+---The color channels from the two pixel values are multiplied together to produce a result.
+---
+---@field multiply integer
+---
+---The maximum value from each color channel is used, resulting in a lightening effect.
+---
+---@field lighten integer
+---
+---The minimum value from each color channel is used, resulting in a darkening effect.
+---
+---@field darken integer
+---
+---The opposite of multiply: The pixel values are inverted, multiplied, and inverted again, resulting in a lightening effect.
+---
+---@field screen integer
+
+---
+---There are two types of ShaderBlocks that can be used: `uniform` and `compute`.
+---
+---Uniform blocks are read only in shaders, can sometimes be a bit faster than compute blocks, and have a limited size (but the limit will be at least 16KB, you can check `lovr.graphics.getLimits` to check).
+---
+---Compute blocks can be written to by compute shaders, might be slightly slower than uniform blocks, and have a much, much larger maximum size.
+---
+---@class lovr.BlockType
+---
+---A uniform block.
+---
+---@field uniform integer
+---
+---A compute block.
+---
+---@field compute integer
+
+---
+---This acts as a hint to the graphics driver about what kinds of data access should be optimized for.
+---
+---@class lovr.BufferUsage
+---
+---A buffer that you intend to create once and never modify.
+---
+---@field static integer
+---
+---A buffer which is modified occasionally.
+---
+---@field dynamic integer
+---
+---A buffer which is entirely replaced on the order of every frame.
+---
+---@field stream integer
+
+---
+---The method used to compare z values when deciding how to overlap rendered objects. This is called the "depth test", and it happens on a pixel-by-pixel basis every time new objects are drawn. If the depth test "passes" for a pixel, then the pixel color will be replaced by the new color and the depth value in the depth buffer will be updated. Otherwise, the pixel will not be changed and the depth value will not be updated.
+---
+---@class lovr.CompareMode
+---
+---The depth test passes when the depth values are equal.
+---
+---@field equal integer
+---
+---The depth test passes when the depth values are not equal.
+---
+---@field notequal integer
+---
+---The depth test passes when the new depth value is less than the existing one.
+---
+---@field less integer
+---
+---The depth test passes when the new depth value is less than or equal to the existing one.
+---
+---@field lequal integer
+---
+---The depth test passes when the new depth value is greater than or equal to the existing one.
+---
+---@field gequal integer
+---
+---The depth test passes when the new depth value is greater than the existing one.
+---
+---@field greater integer
+
+---
+---Different coordinate spaces for nodes in a Model.
+---
+---@class lovr.CoordinateSpace
+---
+---The coordinate space relative to the node's parent.
+---
+---@field local integer
+---
+---The coordinate space relative to the root node of the Model.
+---
+---@field global integer
+
+---
+---The following shaders are built in to LÖVR, and can be used as an argument to `lovr.graphics.newShader` instead of providing raw GLSL shader code. The shaders can be further customized by using the `flags` argument. If you pass in `nil` to `lovr.graphics.setShader`, LÖVR will automatically pick a DefaultShader to use based on whatever is being drawn.
+---
+---@class lovr.DefaultShader
+---
+---A simple shader without lighting, using only colors and a diffuse texture.
+---
+---@field unlit integer
+---
+---A physically-based rendering (PBR) shader, using advanced material properties.
+---
+---@field standard integer
+---
+---A shader that renders a cubemap texture.
+---
+---@field cube integer
+---
+---A shader that renders a 2D equirectangular texture with spherical coordinates.
+---
+---@field pano integer
+---
+---A shader that renders font glyphs.
+---
+---@field font integer
+---
+---A shader that passes its vertex coordinates unmodified to the fragment shader, used to render view-independent fixed geometry like fullscreen quads.
+---
+---@field fill integer
+
+---
+---Meshes are lists of arbitrary vertices. These vertices can be connected in different ways, leading to different shapes like lines and triangles.
+---
+---@class lovr.DrawMode
+---
+---Draw each vertex as a single point.
+---
+---@field points integer
+---
+---The vertices represent a list of line segments. Each pair of vertices will have a line drawn between them.
+---
+---@field lines integer
+---
+---The first two vertices have a line drawn between them, and each vertex after that will be connected to the previous vertex with a line.
+---
+---@field linestrip integer
+---
+---Similar to linestrip, except the last vertex is connected back to the first.
+---
+---@field lineloop integer
+---
+---The first three vertices define a triangle. Each vertex after that creates a triangle using the new vertex and last two vertices.
+---
+---@field strip integer
+---
+---Each set of three vertices represents a discrete triangle.
+---
+---@field triangles integer
+---
+---Draws a set of triangles. Each one shares the first vertex as a common point, leading to a fan-like shape.
+---
+---@field fan integer
+
+---
+---Most graphics primitives can be drawn in one of two modes: a filled mode and a wireframe mode.
+---
+---@class lovr.DrawStyle
+---
+---The shape is drawn as a filled object.
+---
+---@field fill integer
+---
+---The shape is drawn as a wireframe object.
+---
+---@field line integer
+
+---
+---The method used to downsample (or upsample) a texture. "nearest" can be used for a pixelated effect, whereas "linear" leads to more smooth results. Nearest is slightly faster than linear.
+---
+---@class lovr.FilterMode
+---
+---Fast nearest-neighbor sampling. Leads to a pixelated style.
+---
+---@field nearest integer
+---
+---Smooth pixel sampling.
+---
+---@field bilinear integer
+---
+---Smooth pixel sampling, with smooth sampling across mipmap levels.
+---
+---@field trilinear integer
+
+---
+---Different ways to horizontally align text when using `lovr.graphics.print`.
+---
+---@class lovr.HorizontalAlign
+---
+---Left aligned lines of text.
+---
+---@field left integer
+---
+---Centered aligned lines of text.
+---
+---@field center integer
+---
+---Right aligned lines of text.
+---
+---@field right integer
+
+---
+---The different types of color parameters `Material`s can hold.
+---
+---@class lovr.MaterialColor
+---
+---The diffuse color.
+---
+---@field diffuse integer
+---
+---The emissive color.
+---
+---@field emissive integer
+
+---
+---The different types of float parameters `Material`s can hold.
+---
+---@class lovr.MaterialScalar
+---
+---The constant metalness factor.
+---
+---@field metalness integer
+---
+---The constant roughness factor.
+---
+---@field roughness integer
+
+---
+---The different types of texture parameters `Material`s can hold.
+---
+---@class lovr.MaterialTexture
+---
+---The diffuse texture.
+---
+---@field diffuse integer
+---
+---The emissive texture.
+---
+---@field emissive integer
+---
+---The metalness texture.
+---
+---@field metalness integer
+---
+---The roughness texture.
+---
+---@field roughness integer
+---
+---The ambient occlusion texture.
+---
+---@field occlusion integer
+---
+---The normal map.
+---
+---@field normal integer
+---
+---The environment map, should be specified as a cubemap texture.
+---
+---@field environment integer
+
+---
+---Meshes can have a usage hint, describing how they are planning on being updated. Setting the usage hint allows the graphics driver optimize how it handles the data in the Mesh.
+---
+---@class lovr.MeshUsage
+---
+---The Mesh contents will rarely change.
+---
+---@field static integer
+---
+---The Mesh contents will change often.
+---
+---@field dynamic integer
+---
+---The Mesh contents will change constantly, potentially multiple times each frame.
+---
+---@field stream integer
+
+---
+---Shaders can be used for either rendering operations or generic compute tasks. Graphics shaders are created with `lovr.graphics.newShader` and compute shaders are created with `lovr.graphics.newComputeShader`. `Shader:getType` can be used on an existing Shader to figure out what type it is.
+---
+---@class lovr.ShaderType
+---
+---A graphics shader.
+---
+---@field graphics integer
+---
+---A compute shader.
+---
+---@field compute integer
+
+---
+---How to modify pixels in the stencil buffer when using `lovr.graphics.stencil`.
+---
+---@class lovr.StencilAction
+---
+---Stencil values will be replaced with a custom value.
+---
+---@field replace integer
+---
+---Stencil values will increment every time they are rendered to.
+---
+---@field increment integer
+---
+---Stencil values will decrement every time they are rendered to.
+---
+---@field decrement integer
+---
+---Similar to `increment`, but the stencil value will be set to 0 if it exceeds 255.
+---
+---@field incrementwrap integer
+---
+---Similar to `decrement`, but the stencil value will be set to 255 if it drops below 0.
+---
+---@field decrementwrap integer
+---
+---Stencil values will be bitwise inverted every time they are rendered to.
+---
+---@field invert integer
+
+---
+---Textures can store their pixels in different formats. The set of color channels and the number of bits stored for each channel can differ, allowing Textures to optimize their storage for certain kinds of image formats or rendering techniques.
+---
+---@class lovr.TextureFormat
+---
+---Each pixel is 24 bits, or 8 bits for each channel.
+---
+---@field rgb integer
+---
+---Each pixel is 32 bits, or 8 bits for each channel (including alpha).
+---
+---@field rgba integer
+---
+---An rgba format where the colors occupy 4 bits instead of the usual 8.
+---
+---@field rgba4 integer
+---
+---Each pixel is 64 bits. Each channel is a 16 bit floating point number.
+---
+---@field rgba16f integer
+---
+---Each pixel is 128 bits. Each channel is a 32 bit floating point number.
+---
+---@field rgba32f integer
+---
+---A 16-bit floating point format with a single color channel.
+---
+---@field r16f integer
+---
+---A 32-bit floating point format with a single color channel.
+---
+---@field r32f integer
+---
+---A 16-bit floating point format with two color channels.
+---
+---@field rg16f integer
+---
+---A 32-bit floating point format with two color channels.
+---
+---@field rg32f integer
+---
+---A 16 bit format with 5-bit color channels and a single alpha bit.
+---
+---@field rgb5a1 integer
+---
+---A 32 bit format with 10-bit color channels and two alpha bits.
+---
+---@field rgb10a2 integer
+---
+---Each pixel is 32 bits, and packs three color channels into 10 or 11 bits each.
+---
+---@field rg11b10f integer
+---
+---A 16 bit depth buffer.
+---
+---@field d16 integer
+---
+---A 32 bit floating point depth buffer.
+---
+---@field d32f integer
+---
+---A depth buffer with 24 bits for depth and 8 bits for stencil.
+---
+---@field d24s8 integer
+
+---
+---Different types of Textures.
+---
+---@class lovr.TextureType
+---
+---A 2D texture.
+---
+---@field ["2d"] integer
+---
+---A 2D array texture with multiple independent 2D layers.
+---
+---@field array integer
+---
+---A cubemap texture with 6 2D faces.
+---
+---@field cube integer
+---
+---A 3D volumetric texture consisting of multiple 2D layers.
+---
+---@field volume integer
+
+---
+---When binding writable resources to shaders using `Shader:sendBlock` and `Shader:sendImage`, an access pattern can be specified as a hint that says whether you plan to read or write to the resource (or both). Sometimes, LÖVR or the GPU driver can use this hint to get better performance or avoid stalling.
+---
+---@class lovr.UniformAccess
+---
+---The Shader will use the resource in a read-only fashion.
+---
+---@field read integer
+---
+---The Shader will use the resource in a write-only fashion.
+---
+---@field write integer
+---
+---The resource will be available for reading and writing.
+---
+---@field readwrite integer
+
+---
+---Different ways to vertically align text when using `lovr.graphics.print`.
+---
+---@class lovr.VerticalAlign
+---
+---Align the top of the text to the origin.
+---
+---@field top integer
+---
+---Vertically center the text.
+---
+---@field middle integer
+---
+---Align the bottom of the text to the origin.
+---
+---@field bottom integer
+
+---
+---Whether the points on triangles are specified in a clockwise or counterclockwise order.
+---
+---@class lovr.Winding
+---
+---Triangle vertices are specified in a clockwise order.
+---
+---@field clockwise integer
+---
+---Triangle vertices are specified in a counterclockwise order.
+---
+---@field counterclockwise integer
+
+---
+---The method used to render textures when texture coordinates are outside of the 0-1 range.
+---
+---@class lovr.WrapMode
+---
+---The texture will be clamped at its edges.
+---
+---@field clamp integer
+---
+---The texture repeats.
+---
+---@field repeat integer
+---
+---The texture will repeat, mirroring its appearance each time it repeats.
+---
+---@field mirroredrepeat integer
diff --git a/meta/3rd/lovr/library/lovr.headset.lua b/meta/3rd/lovr/library/lovr.headset.lua
new file mode 100644
index 00000000..c33226fc
--- /dev/null
+++ b/meta/3rd/lovr/library/lovr.headset.lua
@@ -0,0 +1,511 @@
+---@meta
+
+---
+---The `lovr.headset` module is where all the magical VR functionality is. With it, you can access connected VR hardware and get information about the available space the player has. Note that all units are reported in meters. Position `(0, 0, 0)` is the center of the play area.
+---
+---@class lovr.headset
+lovr.headset = {}
+
+---
+---Animates a device model to match its current input state. The buttons and joysticks on a controller will move as they're pressed/moved and hand models will move to match skeletal input.
+---
+---The model should have been created using `lovr.headset.newModel` with the `animated` flag set to `true`.
+---
+---@param device? lovr.Device # The device to use for the animation data.
+---@param model lovr.Model # The model to animate.
+---@return boolean success # Whether the animation was applied successfully to the Model. If the Model was not compatible or animation data for the device was not available, this will be `false`.
+function lovr.headset.animate(device, model) end
+
+---
+---Returns the current angular velocity of a device.
+---
+---@param device? lovr.Device # The device to get the velocity of.
+---@return number x # The x component of the angular velocity.
+---@return number y # The y component of the angular velocity.
+---@return number z # The z component of the angular velocity.
+function lovr.headset.getAngularVelocity(device) end
+
+---
+---Get the current state of an analog axis on a device. Some axes are multidimensional, for example a 2D touchpad or thumbstick with x/y axes. For multidimensional axes, this function will return multiple values, one number for each axis. In these cases, it can be useful to use the `select` function built in to Lua to select a particular axis component.
+---
+---@param device lovr.Device # The device.
+---@param axis lovr.DeviceAxis # The axis.
+function lovr.headset.getAxis(device, axis) end
+
+---
+---Returns the depth of the play area, in meters.
+---
+---@return number depth # The depth of the play area, in meters.
+function lovr.headset.getBoundsDepth() end
+
+---
+---Returns the size of the play area, in meters.
+---
+---@return number width # The width of the play area, in meters.
+---@return number depth # The depth of the play area, in meters.
+function lovr.headset.getBoundsDimensions() end
+
+---
+---Returns a list of points representing the boundaries of the play area, or `nil` if the current headset driver does not expose this information.
+---
+---@param t? table # A table to fill with the points. If `nil`, a new table will be created.
+---@return table points # A flat table of 3D points representing the play area boundaries.
+function lovr.headset.getBoundsGeometry(t) end
+
+---
+---Returns the width of the play area, in meters.
+---
+---@return number width # The width of the play area, in meters.
+function lovr.headset.getBoundsWidth() end
+
+---
+---Returns the near and far clipping planes used to render to the headset. Objects closer than the near clipping plane or further than the far clipping plane will be clipped out of view.
+---
+---@return number near # The distance to the near clipping plane, in meters.
+---@return number far # The distance to the far clipping plane, in meters.
+function lovr.headset.getClipDistance() end
+
+---
+---Returns the texture dimensions of the headset display (for one eye), in pixels.
+---
+---@return number width # The width of the display.
+---@return number height # The height of the display.
+function lovr.headset.getDisplayDimensions() end
+
+---
+---Returns the refresh rate of the headset display, in Hz.
+---
+---@return number frequency # The frequency of the display, or `nil` if I have no idea what it is.
+function lovr.headset.getDisplayFrequency() end
+
+---
+---Returns the height of the headset display (for one eye), in pixels.
+---
+---@return number height # The height of the display.
+function lovr.headset.getDisplayHeight() end
+
+---
+---Returns 2D triangle vertices that represent areas of the headset display that will never be seen by the user (due to the circular lenses). This area can be masked out by rendering it to the depth buffer or stencil buffer. Then, further drawing operations can skip rendering those pixels using the depth test (`lovr.graphics.setDepthTest`) or stencil test (`lovr.graphics.setStencilTest`), which improves performance.
+---
+---@return table points # A table of points. Each point is a table with two numbers between 0 and 1.
+function lovr.headset.getDisplayMask() end
+
+---
+---Returns the width of the headset display (for one eye), in pixels.
+---
+---@return number width # The width of the display.
+function lovr.headset.getDisplayWidth() end
+
+---
+---Returns the `HeadsetDriver` that is currently in use, optionally for a specific device. The order of headset drivers can be changed using `lovr.conf` to prefer or exclude specific VR APIs.
+---
+---@overload fun(device: lovr.Device):lovr.HeadsetDriver
+---@return lovr.HeadsetDriver driver # The driver of the headset in use, e.g. "OpenVR".
+function lovr.headset.getDriver() end
+
+---
+---Returns a table with all of the currently tracked hand devices.
+---
+---@return table hands # The currently tracked hand devices.
+function lovr.headset.getHands() end
+
+---
+---Returns a Texture that contains whatever is currently rendered to the headset.
+---
+---Sometimes this can be `nil` if the current headset driver doesn't have a mirror texture, which can happen if the driver renders directly to the display. Currently the `desktop`, `webxr`, and `vrapi` drivers do not have a mirror texture.
+---
+---It also isn't guaranteed that the same Texture will be returned by subsequent calls to this function. Currently, the `oculus` driver exhibits this behavior.
+---
+---@return lovr.Texture mirror # The mirror texture.
+function lovr.headset.getMirrorTexture() end
+
+---
+---Returns the name of the headset as a string. The exact string that is returned depends on the hardware and VR SDK that is currently in use.
+---
+---@return string name # The name of the headset as a string.
+function lovr.headset.getName() end
+
+---
+---Returns the current orientation of a device, in angle/axis form.
+---
+---@param device? lovr.Device # The device to get the orientation of.
+---@return number angle # The amount of rotation around the axis of rotation, in radians.
+---@return number ax # The x component of the axis of rotation.
+---@return number ay # The y component of the axis of rotation.
+---@return number az # The z component of the axis of rotation.
+function lovr.headset.getOrientation(device) end
+
+---
+---Returns the type of origin used for the tracking volume. The different types of origins are explained on the `HeadsetOrigin` page.
+---
+---@return lovr.HeadsetOrigin origin # The type of origin.
+function lovr.headset.getOriginType() end
+
+---
+---Returns the current position and orientation of a device.
+---
+---@param device? lovr.Device # The device to get the pose of.
+---@return number x # The x position.
+---@return number y # The y position.
+---@return number z # The z position.
+---@return number angle # The amount of rotation around the axis of rotation, in radians.
+---@return number ax # The x component of the axis of rotation.
+---@return number ay # The y component of the axis of rotation.
+---@return number az # The z component of the axis of rotation.
+function lovr.headset.getPose(device) end
+
+---
+---Returns the current position of a device, in meters, relative to the play area.
+---
+---@param device? lovr.Device # The device to get the position of.
+---@return number x # The x position of the device.
+---@return number y # The y position of the device.
+---@return number z # The z position of the device.
+function lovr.headset.getPosition(device) end
+
+---
+---Returns a list of joint poses tracked by a device. Currently, only hand devices are able to track joints.
+---
+---@overload fun(device: lovr.Device, t: table):table
+---@param device lovr.Device # The Device to query.
+---@return table poses # A list of joint poses for the device. Each pose is a table with 3 numbers for the position of the joint followed by 4 numbers for the angle/axis orientation of the joint.
+function lovr.headset.getSkeleton(device) end
+
+---
+---Returns the estimated time in the future at which the light from the pixels of the current frame will hit the eyes of the user.
+---
+---This can be used as a replacement for `lovr.timer.getTime` for timestamps that are used for rendering to get a smoother result that is synchronized with the display of the headset.
+---
+---@return number time # The predicted display time, in seconds.
+function lovr.headset.getTime() end
+
+---
+---Returns the current linear velocity of a device, in meters per second.
+---
+---@param device? lovr.Device # The device to get the velocity of.
+---@return number vx # The x component of the linear velocity.
+---@return number vy # The y component of the linear velocity.
+---@return number vz # The z component of the linear velocity.
+function lovr.headset.getVelocity(device) end
+
+---
+---Returns the view angles of one of the headset views.
+---
+---These can be used with `Mat4:fov` to create a projection matrix.
+---
+---If tracking data is unavailable for the view or the index is invalid, `nil` is returned.
+---
+---@param view number # The view index.
+---@return number left # The left view angle, in radians.
+---@return number right # The right view angle, in radians.
+---@return number top # The top view angle, in radians.
+---@return number bottom # The bottom view angle, in radians.
+function lovr.headset.getViewAngles(view) end
+
+---
+---Returns the number of views used for rendering. Each view consists of a pose in space and a set of angle values that determine the field of view.
+---
+---This is usually 2 for stereo rendering configurations, but it can also be different. For example, one way of doing foveated rendering uses 2 views for each eye -- one low quality view with a wider field of view, and a high quality view with a narrower field of view.
+---
+---@return number count # The number of views.
+function lovr.headset.getViewCount() end
+
+---
+---Returns the pose of one of the headset views. This info can be used to create view matrices or do other eye-dependent calculations.
+---
+---If tracking data is unavailable for the view or the index is invalid, `nil` is returned.
+---
+---@param view number # The view index.
+---@return number x # The x coordinate of the view position, in meters.
+---@return number y # The y coordinate of the view position, in meters.
+---@return number z # The z coordinate of the view position, in meters.
+---@return number angle # The amount of rotation around the rotation axis, in radians.
+---@return number ax # The x component of the axis of rotation.
+---@return number ay # The y component of the axis of rotation.
+---@return number az # The z component of the axis of rotation.
+function lovr.headset.getViewPose(view) end
+
+---
+---Returns whether a button on a device is pressed.
+---
+---@param device lovr.Device # The device.
+---@param button lovr.DeviceButton # The button.
+---@return boolean down # Whether the button on the device is currently pressed, or `nil` if the device does not have the specified button.
+function lovr.headset.isDown(device, button) end
+
+---
+---Returns whether a button on a device is currently touched.
+---
+---@param device lovr.Device # The device.
+---@param button lovr.DeviceButton # The button.
+---@return boolean touched # Whether the button on the device is currently touched, or `nil` if the device does not have the button or it isn't touch-sensitive.
+function lovr.headset.isTouched(device, button) end
+
+---
+---Returns whether any active headset driver is currently returning pose information for a device.
+---
+---@param device? lovr.Device # The device to get the pose of.
+---@return boolean tracked # Whether the device is currently tracked.
+function lovr.headset.isTracked(device) end
+
+---
+---Returns a new Model for the specified device.
+---
+---@param device? lovr.Device # The device to load a model for.
+---@param options? {animated: boolean} # Options for loading the model.
+---@return lovr.Model model # The new Model, or `nil` if a model could not be loaded.
+function lovr.headset.newModel(device, options) end
+
+---
+---Renders to each eye of the headset using a function.
+---
+---This function takes care of setting the appropriate graphics transformations to ensure that the scene is rendered as though it is being viewed through each eye of the player. It also takes care of setting the correct projection for the headset lenses.
+---
+---If the headset module is enabled, this function is called automatically by `lovr.run` with `lovr.draw` as the callback.
+---
+---@param callback function # The function used to render. Any functions called will render to the headset instead of to the window.
+function lovr.headset.renderTo(callback) end
+
+---
+---Sets the near and far clipping planes used to render to the headset. Objects closer than the near clipping plane or further than the far clipping plane will be clipped out of view.
+---
+---@param near number # The distance to the near clipping plane, in meters.
+---@param far number # The distance to the far clipping plane, in meters.
+function lovr.headset.setClipDistance(near, far) end
+
+---
+---Causes the device to vibrate with a custom strength, duration, and frequency, if possible.
+---
+---@param device? lovr.Device # The device to vibrate.
+---@param strength? number # The strength of the vibration (amplitude), between 0 and 1.
+---@param duration? number # The duration of the vibration, in seconds.
+---@param frequency? number # The frequency of the vibration, in hertz. 0 will use a default frequency.
+---@return boolean vibrated # Whether the vibration was successfully triggered by an active headset driver.
+function lovr.headset.vibrate(device, strength, duration, frequency) end
+
+---
+---Returns whether a button on a device was pressed this frame.
+---
+---@param device lovr.Device # The device.
+---@param button lovr.DeviceButton # The button to check.
+---@return boolean pressed # Whether the button on the device was pressed this frame.
+function lovr.headset.wasPressed(device, button) end
+
+---
+---Returns whether a button on a device was released this frame.
+---
+---@param device lovr.Device # The device.
+---@param button lovr.DeviceButton # The button to check.
+---@return boolean released # Whether the button on the device was released this frame.
+function lovr.headset.wasReleased(device, button) end
+
+---
+---Different types of input devices supported by the `lovr.headset` module.
+---
+---@class lovr.Device
+---
+---The headset.
+---
+---@field head integer
+---
+---The left controller.
+---
+---@field ["hand/left"] integer
+---
+---The right controller.
+---
+---@field ["hand/right"] integer
+---
+---A shorthand for hand/left.
+---
+---@field left integer
+---
+---A shorthand for hand/right.
+---
+---@field right integer
+---
+---A device tracking the left elbow.
+---
+---@field ["elbow/left"] integer
+---
+---A device tracking the right elbow.
+---
+---@field ["elbow/right"] integer
+---
+---A device tracking the left shoulder.
+---
+---@field ["shoulder/left"] integer
+---
+---A device tracking the right shoulder.
+---
+---@field ["shoulder/right"] integer
+---
+---A device tracking the chest.
+---
+---@field chest integer
+---
+---A device tracking the waist.
+---
+---@field waist integer
+---
+---A device tracking the left knee.
+---
+---@field ["knee/left"] integer
+---
+---A device tracking the right knee.
+---
+---@field ["knee/right"] integer
+---
+---A device tracking the left foot or ankle.
+---
+---@field ["foot/left"] integer
+---
+---A device tracking the right foot or ankle.
+---
+---@field ["foot/right"] integer
+---
+---A device used as a camera in the scene.
+---
+---@field camera integer
+---
+---A tracked keyboard.
+---
+---@field keyboard integer
+---
+---The left eye.
+---
+---@field ["eye/left"] integer
+---
+---The right eye.
+---
+---@field ["eye/right"] integer
+---
+---The first tracking device (i.e. lighthouse).
+---
+---@field ["beacon/1"] integer
+---
+---The second tracking device (i.e. lighthouse).
+---
+---@field ["beacon/2"] integer
+---
+---The third tracking device (i.e. lighthouse).
+---
+---@field ["beacon/3"] integer
+---
+---The fourth tracking device (i.e. lighthouse).
+---
+---@field ["beacon/4"] integer
+
+---
+---Axes on an input device.
+---
+---@class lovr.DeviceAxis
+---
+---A trigger (1D).
+---
+---@field trigger integer
+---
+---A thumbstick (2D).
+---
+---@field thumbstick integer
+---
+---A touchpad (2D).
+---
+---@field touchpad integer
+---
+---A grip button or grab gesture (1D).
+---
+---@field grip integer
+
+---
+---Buttons on an input device.
+---
+---@class lovr.DeviceButton
+---
+---The trigger button.
+---
+---@field trigger integer
+---
+---The thumbstick.
+---
+---@field thumbstick integer
+---
+---The touchpad.
+---
+---@field touchpad integer
+---
+---The grip button.
+---
+---@field grip integer
+---
+---The menu button.
+---
+---@field menu integer
+---
+---The A button.
+---
+---@field a integer
+---
+---The B button.
+---
+---@field b integer
+---
+---The X button.
+---
+---@field x integer
+---
+---The Y button.
+---
+---@field y integer
+---
+---The proximity sensor on a headset.
+---
+---@field proximity integer
+
+---
+---These are all of the supported VR APIs that LÖVR can use to power the lovr.headset module. You can change the order of headset drivers using `lovr.conf` to prefer or exclude specific VR APIs.
+---
+---At startup, LÖVR searches through the list of drivers in order. One headset driver will be used for rendering to the VR display, and all supported headset drivers will be used for device input. The way this works is that when poses or button input is requested, the input drivers are queried (in the order they appear in `conf.lua`) to see if any of them currently have data for the specified device. The first one that returns data will be used to provide the result. This allows projects to support multiple types of hardware devices.
+---
+---@class lovr.HeadsetDriver
+---
+---A VR simulator using keyboard/mouse.
+---
+---@field desktop integer
+---
+---Oculus Desktop SDK.
+---
+---@field oculus integer
+---
+---OpenVR.
+---
+---@field openvr integer
+---
+---OpenXR.
+---
+---@field openxr integer
+---
+---Oculus Mobile SDK.
+---
+---@field vrapi integer
+---
+---Pico.
+---
+---@field pico integer
+---
+---WebXR.
+---
+---@field webxr integer
+
+---
+---Represents the different types of origins for coordinate spaces. An origin of "floor" means that the origin is on the floor in the middle of a room-scale play area. An origin of "head" means that no positional tracking is available, and consequently the origin is always at the position of the headset.
+---
+---@class lovr.HeadsetOrigin
+---
+---The origin is at the head.
+---
+---@field head integer
+---
+---The origin is on the floor.
+---
+---@field floor integer
diff --git a/meta/3rd/lovr/library/lovr.lovr.lua b/meta/3rd/lovr/library/lovr.lovr.lua
new file mode 100644
index 00000000..6367c768
--- /dev/null
+++ b/meta/3rd/lovr/library/lovr.lovr.lua
@@ -0,0 +1,15 @@
+---@meta
+
+---
+---`lovr` is the single global table that is exposed to every LÖVR app. It contains a set of **modules** and a set of **callbacks**.
+---
+---@class lovr.lovr
+lovr.lovr = {}
+
+---
+---Get the current major, minor, and patch version of LÖVR.
+---
+---@return number major # The major version.
+---@return number minor # The minor version.
+---@return number patch # The patch number.
+function lovr.lovr.getVersion() end
diff --git a/meta/3rd/lovr/library/lovr.lua b/meta/3rd/lovr/library/lovr.lua
new file mode 100644
index 00000000..00a8f4b7
--- /dev/null
+++ b/meta/3rd/lovr/library/lovr.lua
@@ -0,0 +1,28 @@
+---@meta
+
+---
+---`lovr` is the single global table that is exposed to every LÖVR app. It contains a set of **modules** and a set of **callbacks**.
+---
+---@class lovr
+lovr = {}
+
+---
+---Get the current major, minor, and patch version of LÖVR.
+---
+---@return number major # The major version.
+---@return number minor # The minor version.
+---@return number patch # The patch number.
+function lovr.getVersion() end
+
+---
+---This is not a real object, but describes the behavior shared by all objects. Think of it as the superclass of all LÖVR objects.
+---
+---In addition to the methods here, all objects have a `__tostring` metamethod that returns the name of the object's type. So to check if a LÖVR object is an instance of "Blob", you can do `tostring(object) == 'Blob'`.
+---
+---@class lovr.Object
+local Object = {}
+
+---
+---Immediately destroys Lua's reference to the object it's called on. After calling this function on an object, it is an error to do anything with the object from Lua (call methods on it, pass it to other functions, etc.). If nothing else is using the object, it will be destroyed immediately, which can be used to destroy something earlier than it would normally be garbage collected in order to reduce memory.
+---
+function Object:release() end
diff --git a/meta/3rd/lovr/library/lovr.math.lua b/meta/3rd/lovr/library/lovr.math.lua
new file mode 100644
index 00000000..007d8055
--- /dev/null
+++ b/meta/3rd/lovr/library/lovr.math.lua
@@ -0,0 +1,791 @@
+---@meta
+
+---
+---The `lovr.math` module provides math helpers commonly used for 3D applications.
+---
+---@class lovr.math
+lovr.math = {}
+
+---
+---Drains the temporary vector pool, invalidating existing temporary vectors.
+---
+---This is called automatically at the end of each frame.
+---
+function lovr.math.drain() end
+
+---
+---Converts a color from gamma space to linear space.
+---
+---@overload fun(color: table):number, number, number
+---@overload fun(x: number):number
+---@param gr number # The red component of the gamma-space color.
+---@param gg number # The green component of the gamma-space color.
+---@param gb number # The blue component of the gamma-space color.
+---@return number lr # The red component of the resulting linear-space color.
+---@return number lg # The green component of the resulting linear-space color.
+---@return number lb # The blue component of the resulting linear-space color.
+function lovr.math.gammaToLinear(gr, gg, gb) end
+
+---
+---Get the seed used to initialize the random generator.
+---
+---@return number seed # The new seed.
+function lovr.math.getRandomSeed() end
+
+---
+---Converts a color from linear space to gamma space.
+---
+---@overload fun(color: table):number, number, number
+---@overload fun(x: number):number
+---@param lr number # The red component of the linear-space color.
+---@param lg number # The green component of the linear-space color.
+---@param lb number # The blue component of the linear-space color.
+---@return number gr # The red component of the resulting gamma-space color.
+---@return number gg # The green component of the resulting gamma-space color.
+---@return number gb # The blue component of the resulting gamma-space color.
+function lovr.math.linearToGamma(lr, lg, lb) end
+
+---
+---Creates a temporary 4D matrix. This function takes the same arguments as `Mat4:set`.
+---
+function lovr.math.mat4() end
+
+---
+---Creates a new `Curve` from a list of control points.
+---
+---@overload fun(points: table):lovr.Curve
+---@overload fun(n: number):lovr.Curve
+---@param x number # The x coordinate of the first control point.
+---@param y number # The y coordinate of the first control point.
+---@param z number # The z coordinate of the first control point.
+---@return lovr.Curve curve # The new Curve.
+function lovr.math.newCurve(x, y, z) end
+
+---
+---Creates a new 4D matrix. This function takes the same arguments as `Mat4:set`.
+---
+function lovr.math.newMat4() end
+
+---
+---Creates a new quaternion. This function takes the same arguments as `Quat:set`.
+---
+function lovr.math.newQuat() end
+
+---
+---Creates a new `RandomGenerator`, which can be used to generate random numbers. If you just want some random numbers, you can use `lovr.math.random`. Individual RandomGenerator objects are useful if you need more control over the random sequence used or need a random generator isolated from other instances.
+---
+---@overload fun(seed: number):lovr.RandomGenerator
+---@overload fun(low: number, high: number):lovr.RandomGenerator
+---@return lovr.RandomGenerator randomGenerator # The new RandomGenerator.
+function lovr.math.newRandomGenerator() end
+
+---
+---Creates a new 2D vector. This function takes the same arguments as `Vec2:set`.
+---
+function lovr.math.newVec2() end
+
+---
+---Creates a new 3D vector. This function takes the same arguments as `Vec3:set`.
+---
+function lovr.math.newVec3() end
+
+---
+---Creates a new 4D vector. This function takes the same arguments as `Vec4:set`.
+---
+function lovr.math.newVec4() end
+
+---
+---Returns a 1D, 2D, 3D, or 4D perlin noise value. The number will be between 0 and 1, and it will always be 0.5 when the inputs are integers.
+---
+---@overload fun(x: number, y: number):number
+---@overload fun(x: number, y: number, z: number):number
+---@overload fun(x: number, y: number, z: number, w: number):number
+---@param x number # The x coordinate of the input.
+---@return number noise # The noise value, between 0 and 1.
+function lovr.math.noise(x) end
+
+---
+---Creates a temporary quaternion. This function takes the same arguments as `Quat:set`.
+---
+function lovr.math.quat() end
+
+---
+---Returns a uniformly distributed pseudo-random number. This function has improved randomness over Lua's `math.random` and also guarantees that the sequence of random numbers will be the same on all platforms (given the same seed).
+---
+---@overload fun(high: number):number
+---@overload fun(low: number, high: number):number
+---@return number x # A pseudo-random number.
+function lovr.math.random() end
+
+---
+---Returns a pseudo-random number from a normal distribution (a bell curve). You can control the center of the bell curve (the mean value) and the overall width (sigma, or standard deviation).
+---
+---@param sigma? number # The standard deviation of the distribution. This can be thought of how "wide" the range of numbers is or how much variability there is.
+---@param mu? number # The average value returned.
+---@return number x # A normally distributed pseudo-random number.
+function lovr.math.randomNormal(sigma, mu) end
+
+---
+---Seed the random generator with a new seed. Each seed will cause `lovr.math.random` and `lovr.math.randomNormal` to produce a unique sequence of random numbers. This is done once automatically at startup by `lovr.run`.
+---
+---@param seed number # The new seed.
+function lovr.math.setRandomSeed(seed) end
+
+---
+---Creates a temporary 2D vector. This function takes the same arguments as `Vec2:set`.
+---
+function lovr.math.vec2() end
+
+---
+---Creates a temporary 3D vector. This function takes the same arguments as `Vec3:set`.
+---
+function lovr.math.vec3() end
+
+---
+---Creates a temporary 4D vector. This function takes the same arguments as `Vec4:set`.
+---
+function lovr.math.vec4() end
+
+---
+---A Curve is an object that represents a Bézier curve in three dimensions. Curves are defined by an arbitrary number of control points (note that the curve only passes through the first and last control point).
+---
+---Once a Curve is created with `lovr.math.newCurve`, you can use `Curve:evaluate` to get a point on the curve or `Curve:render` to get a list of all of the points on the curve. These points can be passed directly to `lovr.graphics.points` or `lovr.graphics.line` to render the curve.
+---
+---Note that for longer or more complicated curves (like in a drawing application) it can be easier to store the path as several Curve objects.
+---
+---@class lovr.Curve
+local Curve = {}
+
+---
+---Inserts a new control point into the Curve at the specified index.
+---
+---@param x number # The x coordinate of the control point.
+---@param y number # The y coordinate of the control point.
+---@param z number # The z coordinate of the control point.
+---@param index? number # The index to insert the control point at. If nil, the control point is added to the end of the list of control points.
+function Curve:addPoint(x, y, z, index) end
+
+---
+---Returns a point on the Curve given a parameter `t` from 0 to 1. 0 will return the first control point, 1 will return the last point, .5 will return a point in the "middle" of the Curve, etc.
+---
+---@param t number # The parameter to evaluate the Curve at.
+---@return number x # The x position of the point.
+---@return number y # The y position of the point.
+---@return number z # The z position of the point.
+function Curve:evaluate(t) end
+
+---
+---Returns a control point of the Curve.
+---
+---@param index number # The index to retrieve.
+---@return number x # The x coordinate of the control point.
+---@return number y # The y coordinate of the control point.
+---@return number z # The z coordinate of the control point.
+function Curve:getPoint(index) end
+
+---
+---Returns the number of control points in the Curve.
+---
+---@return number count # The number of control points.
+function Curve:getPointCount() end
+
+---
+---Returns a direction vector for the Curve given a parameter `t` from 0 to 1. 0 will return the direction at the first control point, 1 will return the direction at the last point, .5 will return the direction at the "middle" of the Curve, etc.
+---
+---@param t number # Where on the Curve to compute the direction.
+---@return number x # The x position of the point.
+---@return number y # The y position of the point.
+---@return number z # The z position of the point.
+function Curve:getTangent(t) end
+
+---
+---Removes a control point from the Curve.
+---
+---@param index number # The index of the control point to remove.
+function Curve:removePoint(index) end
+
+---
+---Returns a list of points on the Curve. The number of points can be specified to get a more or less detailed representation, and it is also possible to render a subsection of the Curve.
+---
+---@param n? number # The number of points to use.
+---@param t1? number # How far along the curve to start rendering.
+---@param t2? number # How far along the curve to stop rendering.
+---@return table t # A (flat) table of 3D points along the curve.
+function Curve:render(n, t1, t2) end
+
+---
+---Changes the position of a control point on the Curve.
+---
+---@param index number # The index to modify.
+---@param x number # The new x coordinate.
+---@param y number # The new y coordinate.
+---@param z number # The new z coordinate.
+function Curve:setPoint(index, x, y, z) end
+
+---
+---Returns a new Curve created by slicing the Curve at the specified start and end points.
+---
+---@param t1 number # The starting point to slice at.
+---@param t2 number # The ending point to slice at.
+---@return lovr.Curve curve # A new Curve.
+function Curve:slice(t1, t2) end
+
+---
+---A `mat4` is a math type that holds 16 values in a 4x4 grid.
+---
+---@class lovr.Mat4
+local Mat4 = {}
+
+---
+---Sets a projection matrix using raw projection angles and clipping planes.
+---
+---This can be used for asymmetric or oblique projections.
+---
+---@param left number # The left half-angle of the projection, in radians.
+---@param right number # The right half-angle of the projection, in radians.
+---@param up number # The top half-angle of the projection, in radians.
+---@param down number # The bottom half-angle of the projection, in radians.
+---@param near number # The near plane of the projection.
+---@param far number # The far plane of the projection.
+---@return lovr.Mat4 m # The original matrix.
+function Mat4:fov(left, right, up, down, near, far) end
+
+---
+---Resets the matrix to the identity, effectively setting its translation to zero, its scale to 1, and clearing any rotation.
+---
+---@return lovr.Mat4 m # The original matrix.
+function Mat4:identity() end
+
+---
+---Inverts the matrix, causing it to represent the opposite of its old transform.
+---
+---@return lovr.Mat4 m # The original matrix.
+function Mat4:invert() end
+
+---
+---Sets a view transform matrix that moves and orients camera to look at a target point.
+---
+---This is useful for changing camera position and orientation. The resulting Mat4 matrix can be passed to `lovr.graphics.transform()` directly (without inverting) before rendering the scene.
+---
+---The lookAt() function produces same result as target() after matrix inversion.
+---
+---@param from lovr.Vec3 # The position of the viewer.
+---@param to lovr.Vec3 # The position of the target.
+---@param up? lovr.Vec3 # The up vector of the viewer.
+---@return lovr.Mat4 m # The original matrix.
+function Mat4:lookAt(from, to, up) end
+
+---
+---Multiplies this matrix by another value. Multiplying by a matrix combines their two transforms together. Multiplying by a vector applies the transformation from the matrix to the vector and returns the vector.
+---
+---@overload fun(v3: lovr.Vec3):lovr.Vec3
+---@overload fun(v4: lovr.Vec4):lovr.Vec4
+---@param n lovr.Mat4 # The matrix.
+---@return lovr.Mat4 m # The original matrix, containing the result.
+function Mat4:mul(n) end
+
+---
+---Sets this matrix to represent an orthographic projection, useful for 2D/isometric rendering.
+---
+---This can be used with `lovr.graphics.setProjection`, or it can be sent to a `Shader` for use in GLSL.
+---
+---@param left number # The left edge of the projection.
+---@param right number # The right edge of the projection.
+---@param top number # The top edge of the projection.
+---@param bottom number # The bottom edge of the projection.
+---@param near number # The position of the near clipping plane.
+---@param far number # The position of the far clipping plane.
+---@return lovr.Mat4 m # The original matrix.
+function Mat4:orthographic(left, right, top, bottom, near, far) end
+
+---
+---Sets this matrix to represent a perspective projection.
+---
+---This can be used with `lovr.graphics.setProjection`, or it can be sent to a `Shader` for use in GLSL.
+---
+---@param near number # The near plane.
+---@param far number # The far plane.
+---@param fov number # The vertical field of view (in radians).
+---@param aspect number # The horizontal aspect ratio of the projection (width / height).
+---@return lovr.Mat4 m # The original matrix.
+function Mat4:perspective(near, far, fov, aspect) end
+
+---
+---Rotates the matrix using a quaternion or an angle/axis rotation.
+---
+---@overload fun(angle: number, ax: number, ay: number, az: number):lovr.Mat4
+---@param q lovr.Quat # The rotation to apply to the matrix.
+---@return lovr.Mat4 m # The original matrix.
+function Mat4:rotate(q) end
+
+---
+---Scales the matrix.
+---
+---@overload fun(sx: number, sy: number, sz: number):lovr.Mat4
+---@param scale lovr.Vec3 # The 3D scale to apply.
+---@return lovr.Mat4 m # The original matrix.
+function Mat4:scale(scale) end
+
+---
+---Sets the components of the matrix from separate position, rotation, and scale arguments or an existing matrix.
+---
+---@overload fun(n: lovr.mat4):lovr.Mat4
+---@overload fun(position: lovr.Vec3, scale: lovr.Vec3, rotation: lovr.Quat):lovr.Mat4
+---@overload fun(position: lovr.Vec3, rotation: lovr.Quat):lovr.Mat4
+---@overload fun(...):lovr.Mat4
+---@overload fun(d: number):lovr.Mat4
+---@return lovr.Mat4 m # The input matrix.
+function Mat4:set() end
+
+---
+---Sets a model transform matrix that moves to `from` and orients model towards `to` point.
+---
+---This is used when rendered model should always point torwards a point of interest. The resulting Mat4 object can be used as model pose.
+---
+---The target() function produces same result as lookAt() after matrix inversion.
+---
+---@param from lovr.Vec3 # The position of the viewer.
+---@param to lovr.Vec3 # The position of the target.
+---@param up? lovr.Vec3 # The up vector of the viewer.
+---@return lovr.Mat4 m # The original matrix.
+function Mat4:target(from, to, up) end
+
+---
+---Translates the matrix.
+---
+---@overload fun(x: number, y: number, z: number):lovr.Mat4
+---@param v lovr.Vec3 # The translation vector.
+---@return lovr.Mat4 m # The original matrix.
+function Mat4:translate(v) end
+
+---
+---Transposes the matrix, mirroring its values along the diagonal.
+---
+---@return lovr.Mat4 m # The original matrix.
+function Mat4:transpose() end
+
+---
+---Returns the components of matrix, either as 10 separated numbers representing the position, scale, and rotation, or as 16 raw numbers representing the individual components of the matrix in column-major order.
+---
+---@param raw boolean # Whether to return the 16 raw components.
+function Mat4:unpack(raw) end
+
+---
+---A `quat` is a math type that represents a 3D rotation, stored as four numbers.
+---
+---@class lovr.Quat
+local Quat = {}
+
+---
+---Conjugates the input quaternion in place, returning the input. If the quaternion is normalized, this is the same as inverting it. It negates the (x, y, z) components of the quaternion.
+---
+---@return lovr.Quat q # The original quaternion.
+function Quat:conjugate() end
+
+---
+---Creates a new temporary vec3 facing the forward direction, rotates it by this quaternion, and returns the vector.
+---
+---@return lovr.Vec3 v # The direction vector.
+function Quat:direction() end
+
+---
+---Returns the length of the quaternion.
+---
+---@return number length # The length of the quaternion.
+function Quat:length() end
+
+---
+---Multiplies this quaternion by another value. If the value is a quaternion, the rotations in the two quaternions are applied sequentially and the result is stored in the first quaternion. If the value is a vector, then the input vector is rotated by the quaternion and returned.
+---
+---@overload fun(v3: lovr.vec3):lovr.vec3
+---@param r lovr.quat # A quaternion to combine with the original.
+---@return lovr.quat q # The original quaternion.
+function Quat:mul(r) end
+
+---
+---Adjusts the values in the quaternion so that its length becomes 1.
+---
+---@return lovr.Quat q # The original quaternion.
+function Quat:normalize() end
+
+---
+---Sets the components of the quaternion. There are lots of different ways to specify the new components, the summary is:
+---
+---- Four numbers can be used to specify an angle/axis rotation, similar to other LÖVR functions.
+---- Four numbers plus the fifth `raw` flag can be used to set the raw values of the quaternion.
+---- An existing quaternion can be passed in to copy its values.
+---- A single direction vector can be specified to turn its direction (relative to the default
+--- forward direction of "negative z") into a rotation.
+---- Two direction vectors can be specified to set the quaternion equal to the rotation between the
+--- two vectors.
+---- A matrix can be passed in to extract the rotation of the matrix into a quaternion.
+---
+---@overload fun(r: lovr.quat):lovr.quat
+---@overload fun(v: lovr.vec3):lovr.quat
+---@overload fun(v: lovr.vec3, u: lovr.vec3):lovr.quat
+---@overload fun(m: lovr.mat4):lovr.quat
+---@overload fun():lovr.quat
+---@param angle? any # The angle to use for the rotation, in radians.
+---@param ax? number # The x component of the axis of rotation.
+---@param ay? number # The y component of the axis of rotation.
+---@param az? number # The z component of the axis of rotation.
+---@param raw? boolean # Whether the components should be interpreted as raw `(x, y, z, w)` components.
+---@return lovr.quat q # The original quaternion.
+function Quat:set(angle, ax, ay, az, raw) end
+
+---
+---Performs a spherical linear interpolation between this quaternion and another one, which can be used for smoothly animating between two rotations.
+---
+---The amount of interpolation is controlled by a parameter `t`. A `t` value of zero leaves the original quaternion unchanged, whereas a `t` of one sets the original quaternion exactly equal to the target. A value between `0` and `1` returns a rotation between the two based on the value.
+---
+---@param r lovr.Quat # The quaternion to slerp towards.
+---@param t number # The lerping parameter.
+---@return lovr.Quat q # The original quaternion, containing the new lerped values.
+function Quat:slerp(r, t) end
+
+---
+---Returns the components of the quaternion as numbers, either in an angle/axis representation or as raw quaternion values.
+---
+---@param raw? boolean # Whether the values should be returned as raw values instead of angle/axis.
+---@return number a # The angle in radians, or the x value.
+---@return number b # The x component of the rotation axis or the y value.
+---@return number c # The y component of the rotation axis or the z value.
+---@return number d # The z component of the rotation axis or the w value.
+function Quat:unpack(raw) end
+
+---
+---A RandomGenerator is a standalone object that can be used to independently generate pseudo-random numbers. If you just need basic randomness, you can use `lovr.math.random` without needing to create a random generator.
+---
+---@class lovr.RandomGenerator
+local RandomGenerator = {}
+
+---
+---Returns the seed used to initialize the RandomGenerator.
+---
+---@return number low # The lower 32 bits of the seed.
+---@return number high # The upper 32 bits of the seed.
+function RandomGenerator:getSeed() end
+
+---
+---Returns the current state of the RandomGenerator. This can be used with `RandomGenerator:setState` to reliably restore a previous state of the generator.
+---
+---@return string state # The serialized state.
+function RandomGenerator:getState() end
+
+---
+---Returns the next uniformly distributed pseudo-random number from the RandomGenerator's sequence.
+---
+---@overload fun(high: number):number
+---@overload fun(low: number, high: number):number
+---@return number x # A pseudo-random number.
+function RandomGenerator:random() end
+
+---
+---Returns a pseudo-random number from a normal distribution (a bell curve). You can control the center of the bell curve (the mean value) and the overall width (sigma, or standard deviation).
+---
+---@param sigma? number # The standard deviation of the distribution. This can be thought of how "wide" the range of numbers is or how much variability there is.
+---@param mu? number # The average value returned.
+---@return number x # A normally distributed pseudo-random number.
+function RandomGenerator:randomNormal(sigma, mu) end
+
+---
+---Seed the RandomGenerator with a new seed. Each seed will cause the RandomGenerator to produce a unique sequence of random numbers.
+---
+function RandomGenerator:setSeed() end
+
+---
+---Sets the state of the RandomGenerator, as previously obtained using `RandomGenerator:getState`. This can be used to reliably restore a previous state of the generator.
+---
+---@param state string # The serialized state.
+function RandomGenerator:setState(state) end
+
+---
+---A vector object that holds two numbers.
+---
+---@class lovr.Vec2
+local Vec2 = {}
+
+---
+---Adds a vector or a number to the vector.
+---
+---@overload fun(x: number, y: number):lovr.Vec2
+---@param u lovr.Vec2 # The other vector.
+---@return lovr.Vec2 v # The original vector.
+function Vec2:add(u) end
+
+---
+---Returns the distance to another vector.
+---
+---@overload fun(x: number, y: number):number
+---@param u lovr.Vec2 # The vector to measure the distance to.
+---@return number distance # The distance to `u`.
+function Vec2:distance(u) end
+
+---
+---Divides the vector by a vector or a number.
+---
+---@overload fun(x: number, y: number):lovr.Vec2
+---@param u lovr.Vec2 # The other vector to divide the components by.
+---@return lovr.Vec2 v # The original vector.
+function Vec2:div(u) end
+
+---
+---Returns the dot product between this vector and another one.
+---
+---@overload fun(x: number, y: number):number
+---@param u lovr.Vec2 # The vector to compute the dot product with.
+---@return number dot # The dot product between `v` and `u`.
+function Vec2:dot(u) end
+
+---
+---Returns the length of the vector.
+---
+---@return number length # The length of the vector.
+function Vec2:length() end
+
+---
+---Performs a linear interpolation between this vector and another one, which can be used to smoothly animate between two vectors, based on a parameter value. A parameter value of `0` will leave the vector unchanged, a parameter value of `1` will set the vector to be equal to the input vector, and a value of `.5` will set the components to be halfway between the two vectors.
+---
+---@overload fun(x: number, y: number):lovr.Vec2
+---@return lovr.Vec2 v # The original vector, containing the new lerped values.
+function Vec2:lerp() end
+
+---
+---Multiplies the vector by a vector or a number.
+---
+---@overload fun(x: number, y: number):lovr.Vec2
+---@param u lovr.Vec2 # The other vector to multiply the components by.
+---@return lovr.Vec2 v # The original vector.
+function Vec2:mul(u) end
+
+---
+---Adjusts the values in the vector so that its direction stays the same but its length becomes 1.
+---
+---@return lovr.Vec2 v # The original vector.
+function Vec2:normalize() end
+
+---
+---Sets the components of the vector, either from numbers or an existing vector.
+---
+---@overload fun(u: lovr.Vec2):lovr.Vec2
+---@param x? number # The new x value of the vector.
+---@param y? number # The new y value of the vector.
+---@return lovr.Vec2 v # The input vector.
+function Vec2:set(x, y) end
+
+---
+---Subtracts a vector or a number from the vector.
+---
+---@overload fun(x: number, y: number):lovr.Vec2
+---@param u lovr.Vec2 # The other vector.
+---@return lovr.Vec2 v # The original vector.
+function Vec2:sub(u) end
+
+---
+---Returns the 2 components of the vector as numbers.
+---
+---@return number x # The x value.
+---@return number y # The y value.
+function Vec2:unpack() end
+
+---
+---A vector object that holds three numbers.
+---
+---@class lovr.Vec3
+local Vec3 = {}
+
+---
+---Adds a vector or a number to the vector.
+---
+---@overload fun(x: number, y: number, z: number):lovr.Vec3
+---@param u lovr.Vec3 # The other vector.
+---@return lovr.Vec3 v # The original vector.
+function Vec3:add(u) end
+
+---
+---Sets this vector to be equal to the cross product between this vector and another one. The new `v` will be perpendicular to both the old `v` and `u`.
+---
+---@overload fun(x: number, y: number, z: number):lovr.Vec3
+---@param u lovr.Vec3 # The vector to compute the cross product with.
+---@return lovr.Vec3 v # The original vector, with the cross product as its values.
+function Vec3:cross(u) end
+
+---
+---Returns the distance to another vector.
+---
+---@overload fun(x: number, y: number, z: number):number
+---@param u lovr.Vec3 # The vector to measure the distance to.
+---@return number distance # The distance to `u`.
+function Vec3:distance(u) end
+
+---
+---Divides the vector by a vector or a number.
+---
+---@overload fun(x: number, y: number, z: number):lovr.Vec3
+---@param u lovr.Vec3 # The other vector to divide the components by.
+---@return lovr.Vec3 v # The original vector.
+function Vec3:div(u) end
+
+---
+---Returns the dot product between this vector and another one.
+---
+---@overload fun(x: number, y: number, z: number):number
+---@param u lovr.Vec3 # The vector to compute the dot product with.
+---@return number dot # The dot product between `v` and `u`.
+function Vec3:dot(u) end
+
+---
+---Returns the length of the vector.
+---
+---@return number length # The length of the vector.
+function Vec3:length() end
+
+---
+---Performs a linear interpolation between this vector and another one, which can be used to smoothly animate between two vectors, based on a parameter value. A parameter value of `0` will leave the vector unchanged, a parameter value of `1` will set the vector to be equal to the input vector, and a value of `.5` will set the components to be halfway between the two vectors.
+---
+---@overload fun(x: number, y: number, z: number, t: number):lovr.Vec3
+---@param u lovr.Vec3 # The vector to lerp towards.
+---@param t number # The lerping parameter.
+---@return lovr.Vec3 v # The original vector, containing the new lerped values.
+function Vec3:lerp(u, t) end
+
+---
+---Multiplies the vector by a vector or a number.
+---
+---@overload fun(x: number, y: number, z: number):lovr.Vec3
+---@param u lovr.Vec3 # The other vector to multiply the components by.
+---@return lovr.Vec3 v # The original vector.
+function Vec3:mul(u) end
+
+---
+---Adjusts the values in the vector so that its direction stays the same but its length becomes 1.
+---
+---@return lovr.Vec3 v # The original vector.
+function Vec3:normalize() end
+
+---
+---Sets the components of the vector, either from numbers or an existing vector.
+---
+---@overload fun(u: lovr.Vec3):lovr.Vec3
+---@overload fun(m: lovr.Mat4):lovr.Vec3
+---@param x? number # The new x value of the vector.
+---@param y? number # The new y value of the vector.
+---@param z? number # The new z value of the vector.
+---@return lovr.Vec3 v # The input vector.
+function Vec3:set(x, y, z) end
+
+---
+---Subtracts a vector or a number from the vector.
+---
+---@overload fun(x: number, y: number, z: number):lovr.Vec3
+---@param u lovr.Vec3 # The other vector.
+---@return lovr.Vec3 v # The original vector.
+function Vec3:sub(u) end
+
+---
+---Returns the 3 components of the vector as numbers.
+---
+---@return number x # The x value.
+---@return number y # The y value.
+---@return number z # The z value.
+function Vec3:unpack() end
+
+---
+---A vector object that holds four numbers.
+---
+---@class lovr.Vec4
+local Vec4 = {}
+
+---
+---Adds a vector or a number to the vector.
+---
+---@overload fun(x: number, y: number, z: number, w: number):lovr.Vec4
+---@param u lovr.Vec4 # The other vector.
+---@return lovr.Vec4 v # The original vector.
+function Vec4:add(u) end
+
+---
+---Returns the distance to another vector.
+---
+---@overload fun(x: number, y: number, z: number, w: number):number
+---@param u lovr.Vec4 # The vector to measure the distance to.
+---@return number distance # The distance to `u`.
+function Vec4:distance(u) end
+
+---
+---Divides the vector by a vector or a number.
+---
+---@overload fun(x: number, y: number, z: number, w: number):lovr.Vec4
+---@param u lovr.Vec4 # The other vector to divide the components by.
+---@return lovr.Vec4 v # The original vector.
+function Vec4:div(u) end
+
+---
+---Returns the dot product between this vector and another one.
+---
+---@overload fun(x: number, y: number, z: number, w: number):number
+---@param u lovr.Vec4 # The vector to compute the dot product with.
+---@return number dot # The dot product between `v` and `u`.
+function Vec4:dot(u) end
+
+---
+---Returns the length of the vector.
+---
+---@return number length # The length of the vector.
+function Vec4:length() end
+
+---
+---Performs a linear interpolation between this vector and another one, which can be used to smoothly animate between two vectors, based on a parameter value. A parameter value of `0` will leave the vector unchanged, a parameter value of `1` will set the vector to be equal to the input vector, and a value of `.5` will set the components to be halfway between the two vectors.
+---
+---@overload fun(x: number, y: number, z: number, w: number, t: number):lovr.Vec4
+---@param u lovr.Vec4 # The vector to lerp towards.
+---@param t number # The lerping parameter.
+---@return lovr.Vec4 v # The original vector, containing the new lerped values.
+function Vec4:lerp(u, t) end
+
+---
+---Multiplies the vector by a vector or a number.
+---
+---@overload fun(x: number, y: number, z: number, w: number):lovr.Vec4
+---@param u lovr.Vec4 # The other vector to multiply the components by.
+---@return lovr.Vec4 v # The original vector.
+function Vec4:mul(u) end
+
+---
+---Adjusts the values in the vector so that its direction stays the same but its length becomes 1.
+---
+---@return lovr.Vec4 v # The original vector.
+function Vec4:normalize() end
+
+---
+---Sets the components of the vector, either from numbers or an existing vector.
+---
+---@overload fun(u: lovr.Vec4):lovr.Vec4
+---@param x? number # The new x value of the vector.
+---@param y? number # The new y value of the vector.
+---@param z? number # The new z value of the vector.
+---@param w? number # The new w value of the vector.
+---@return lovr.Vec4 v # The input vector.
+function Vec4:set(x, y, z, w) end
+
+---
+---Subtracts a vector or a number from the vector.
+---
+---@overload fun(x: number, y: number, z: number, w: number):lovr.Vec4
+---@param u lovr.Vec4 # The other vector.
+---@return lovr.Vec4 v # The original vector.
+function Vec4:sub(u) end
+
+---
+---Returns the 4 components of the vector as numbers.
+---
+---@return number x # The x value.
+---@return number y # The y value.
+---@return number z # The z value.
+function Vec4:unpack() end
+
+---
+---LÖVR has math objects for vectors, matrices, and quaternions, collectively called "vector objects". Vectors are useful because they can represent a multidimensional quantity (like a 3D position) using just a single value.
+---
+---@class lovr.Vectors
+local Vectors = {}
diff --git a/meta/3rd/lovr/library/lovr.physics.lua b/meta/3rd/lovr/library/lovr.physics.lua
new file mode 100644
index 00000000..60e4904d
--- /dev/null
+++ b/meta/3rd/lovr/library/lovr.physics.lua
@@ -0,0 +1,1284 @@
+---@meta
+
+---
+---The `lovr.physics` module simulates 3D rigid body physics.
+---
+---@class lovr.physics
+lovr.physics = {}
+
+---
+---Creates a new BallJoint.
+---
+---@param colliderA lovr.Collider # The first collider to attach the Joint to.
+---@param colliderB lovr.Collider # The second collider to attach the Joint to.
+---@param x number # The x position of the joint anchor point, in world coordinates.
+---@param y number # The y position of the joint anchor point, in world coordinates.
+---@param z number # The z position of the joint anchor point, in world coordinates.
+---@return lovr.BallJoint ball # The new BallJoint.
+function lovr.physics.newBallJoint(colliderA, colliderB, x, y, z) end
+
+---
+---Creates a new BoxShape.
+---
+---@param width? number # The width of the box, in meters.
+---@param height? number # The height of the box, in meters.
+---@param depth? number # The depth of the box, in meters.
+---@return lovr.BoxShape box # The new BoxShape.
+function lovr.physics.newBoxShape(width, height, depth) end
+
+---
+---Creates a new CapsuleShape. Capsules are cylinders with hemispheres on each end.
+---
+---@param radius? number # The radius of the capsule, in meters.
+---@param length? number # The length of the capsule, not including the caps, in meters.
+---@return lovr.CapsuleShape capsule # The new CapsuleShape.
+function lovr.physics.newCapsuleShape(radius, length) end
+
+---
+---Creates a new CylinderShape.
+---
+---@param radius? number # The radius of the cylinder, in meters.
+---@param length? number # The length of the cylinder, in meters.
+---@return lovr.CylinderShape cylinder # The new CylinderShape.
+function lovr.physics.newCylinderShape(radius, length) end
+
+---
+---Creates a new DistanceJoint.
+---
+---@param colliderA lovr.Collider # The first collider to attach the Joint to.
+---@param colliderB lovr.Collider # The second collider to attach the Joint to.
+---@param x1 number # The x position of the first anchor point, in world coordinates.
+---@param y1 number # The y position of the first anchor point, in world coordinates.
+---@param z1 number # The z position of the first anchor point, in world coordinates.
+---@param x2 number # The x position of the second anchor point, in world coordinates.
+---@param y2 number # The y position of the second anchor point, in world coordinates.
+---@param z2 number # The z position of the second anchor point, in world coordinates.
+---@return lovr.DistanceJoint joint # The new DistanceJoint.
+function lovr.physics.newDistanceJoint(colliderA, colliderB, x1, y1, z1, x2, y2, z2) end
+
+---
+---Creates a new HingeJoint.
+---
+---@param colliderA lovr.Collider # The first collider to attach the Joint to.
+---@param colliderB lovr.Collider # The second collider to attach the Joint to.
+---@param x number # The x position of the hinge anchor, in world coordinates.
+---@param y number # The y position of the hinge anchor, in world coordinates.
+---@param z number # The z position of the hinge anchor, in world coordinates.
+---@param ax number # The x component of the hinge axis.
+---@param ay number # The y component of the hinge axis.
+---@param az number # The z component of the hinge axis.
+---@return lovr.HingeJoint hinge # The new HingeJoint.
+function lovr.physics.newHingeJoint(colliderA, colliderB, x, y, z, ax, ay, az) end
+
+---
+---Creates a new SliderJoint.
+---
+---@param colliderA lovr.Collider # The first collider to attach the Joint to.
+---@param colliderB lovr.Collider # The second collider to attach the Joint to.
+---@param ax number # The x component of the slider axis.
+---@param ay number # The y component of the slider axis.
+---@param az number # The z component of the slider axis.
+---@return lovr.SliderJoint slider # The new SliderJoint.
+function lovr.physics.newSliderJoint(colliderA, colliderB, ax, ay, az) end
+
+---
+---Creates a new SphereShape.
+---
+---@param radius? number # The radius of the sphere, in meters.
+---@return lovr.SphereShape sphere # The new SphereShape.
+function lovr.physics.newSphereShape(radius) end
+
+---
+---Creates a new physics World, which tracks the overall physics simulation, holds collider objects, and resolves collisions between them.
+---
+---@param xg? number # The x component of the gravity force.
+---@param yg? number # The y component of the gravity force.
+---@param zg? number # The z component of the gravity force.
+---@param allowSleep? boolean # Whether or not colliders will automatically be put to sleep.
+---@param tags? table # A list of collision tags colliders can be assigned to.
+---@return lovr.World world # A whole new World.
+function lovr.physics.newWorld(xg, yg, zg, allowSleep, tags) end
+
+---
+---A BallJoint is a type of `Joint` that acts like a ball and socket between two colliders. It allows the colliders to rotate freely around an anchor point, but does not allow the colliders' distance from the anchor point to change.
+---
+---@class lovr.BallJoint
+local BallJoint = {}
+
+---
+---Returns the anchor points of the BallJoint, in world coordinates. The first point is the anchor on the first collider, and the second point is on the second collider. The joint tries to keep these points the same, but they may be different if the joint is forced apart by some other means.
+---
+---@return number x1 # The x coordinate of the first anchor point, in world coordinates.
+---@return number y1 # The y coordinate of the first anchor point, in world coordinates.
+---@return number z1 # The z coordinate of the first anchor point, in world coordinates.
+---@return number x2 # The x coordinate of the second anchor point, in world coordinates.
+---@return number y2 # The y coordinate of the second anchor point, in world coordinates.
+---@return number z2 # The z coordinate of the second anchor point, in world coordinates.
+function BallJoint:getAnchors() end
+
+---
+---Returns the response time of the joint. See `World:setResponseTime` for more info.
+---
+---@return number responseTime # The response time setting for the joint.
+function BallJoint:getResponseTime() end
+
+---
+---Returns the tightness of the joint. See `World:setTightness` for how this affects the joint.
+---
+---@return number tightness # The tightness of the joint.
+function BallJoint:getTightness() end
+
+---
+---Sets a new anchor point for the BallJoint.
+---
+---@param x number # The x coordinate of the anchor point, in world coordinates.
+---@param y number # The y coordinate of the anchor point, in world coordinates.
+---@param z number # The z coordinate of the anchor point, in world coordinates.
+function BallJoint:setAnchor(x, y, z) end
+
+---
+---Sets the response time of the joint. See `World:setResponseTime` for more info.
+---
+---@param responseTime number # The new response time setting for the joint.
+function BallJoint:setResponseTime(responseTime) end
+
+---
+---Sets the tightness of the joint. See `World:setTightness` for how this affects the joint.
+---
+---@param tightness number # The tightness of the joint.
+function BallJoint:setTightness(tightness) end
+
+---
+---A type of `Shape` that can be used for cubes or boxes.
+---
+---@class lovr.BoxShape
+local BoxShape = {}
+
+---
+---Returns the width, height, and depth of the BoxShape.
+---
+---@return number width # The width of the box, in meters.
+---@return number height # The height of the box, in meters.
+---@return number depth # The depth of the box, in meters.
+function BoxShape:getDimensions() end
+
+---
+---Sets the width, height, and depth of the BoxShape.
+---
+---@param width number # The width of the box, in meters.
+---@param height number # The height of the box, in meters.
+---@param depth number # The depth of the box, in meters.
+function BoxShape:setDimensions(width, height, depth) end
+
+---
+---A type of `Shape` that can be used for capsule-shaped things.
+---
+---@class lovr.CapsuleShape
+local CapsuleShape = {}
+
+---
+---Returns the length of the CapsuleShape, not including the caps.
+---
+---@return number length # The length of the capsule, in meters.
+function CapsuleShape:getLength() end
+
+---
+---Returns the radius of the CapsuleShape.
+---
+---@return number radius # The radius of the capsule, in meters.
+function CapsuleShape:getRadius() end
+
+---
+---Sets the length of the CapsuleShape.
+---
+---@param length number # The new length, in meters, not including the caps.
+function CapsuleShape:setLength(length) end
+
+---
+---Sets the radius of the CapsuleShape.
+---
+---@param radius number # The new radius, in meters.
+function CapsuleShape:setRadius(radius) end
+
+---
+---Colliders are objects that represent a single rigid body in a physics simulation. They can have forces applied to them and collide with other colliders.
+---
+---@class lovr.Collider
+local Collider = {}
+
+---
+---Attaches a Shape to the collider. Attached shapes will collide with other shapes in the world.
+---
+---@param shape lovr.Shape # The Shape to attach.
+function Collider:addShape(shape) end
+
+---
+---Applies a force to the Collider.
+---
+---@overload fun(x: number, y: number, z: number, px: number, py: number, pz: number)
+---@param x number # The x component of the force to apply.
+---@param y number # The y component of the force to apply.
+---@param z number # The z component of the force to apply.
+function Collider:applyForce(x, y, z) end
+
+---
+---Applies torque to the Collider.
+---
+---@param x number # The x component of the torque.
+---@param y number # The y component of the torque.
+---@param z number # The z component of the torque.
+function Collider:applyTorque(x, y, z) end
+
+---
+---Destroy the Collider, removing it from the World.
+---
+function Collider:destroy() end
+
+---
+---Returns the bounding box for the Collider, computed from attached shapes.
+---
+---@return number minx # The minimum x coordinate of the box.
+---@return number maxx # The maximum x coordinate of the box.
+---@return number miny # The minimum y coordinate of the box.
+---@return number maxy # The maximum y coordinate of the box.
+---@return number minz # The minimum z coordinate of the box.
+---@return number maxz # The maximum z coordinate of the box.
+function Collider:getAABB() end
+
+---
+---Returns the angular damping parameters of the Collider. Angular damping makes things less "spinny", making them slow down their angular velocity over time.
+---
+---@return number damping # The angular damping.
+---@return number threshold # Velocity limit below which the damping is not applied.
+function Collider:getAngularDamping() end
+
+---
+---Returns the angular velocity of the Collider.
+---
+---@return number vx # The x component of the angular velocity.
+---@return number vy # The y component of the angular velocity.
+---@return number vz # The z component of the angular velocity.
+function Collider:getAngularVelocity() end
+
+---
+---Returns the friction of the Collider. By default, the friction of two Colliders is combined (multiplied) when they collide to generate a friction force. The initial friction is 0.
+---
+---@return number friction # The friction of the Collider.
+function Collider:getFriction() end
+
+---
+---Returns a list of Joints attached to the Collider.
+---
+---@return table joints # A list of Joints attached to the Collider.
+function Collider:getJoints() end
+
+---
+---Returns the Collider's linear damping parameters. Linear damping is similar to drag or air resistance, slowing the Collider down over time.
+---
+---@return number damping # The linear damping.
+---@return number threshold # Velocity limit below which the damping is not applied.
+function Collider:getLinearDamping() end
+
+---
+---Returns the linear velocity of the Collider. This is how fast the Collider is moving. There is also angular velocity, which is how fast the Collider is spinning.
+---
+---@return number vx # The x velocity of the Collider, in meters per second.
+---@return number vy # The y velocity of the Collider, in meters per second.
+---@return number vz # The z velocity of the Collider, in meters per second.
+function Collider:getLinearVelocity() end
+
+---
+---Returns the linear velocity of a point relative to the Collider.
+---
+---@param x number # The x coordinate.
+---@param y number # The y coordinate.
+---@param z number # The z coordinate.
+---@return number vx # The x component of the velocity of the point.
+---@return number vy # The y component of the velocity of the point.
+---@return number vz # The z component of the velocity of the point.
+function Collider:getLinearVelocityFromLocalPoint(x, y, z) end
+
+---
+---Returns the linear velocity of a point on the Collider specified in world space.
+---
+---@param x number # The x coordinate in world space.
+---@param y number # The y coordinate in world space.
+---@param z number # The z coordinate in world space.
+---@return number vx # The x component of the velocity of the point.
+---@return number vy # The y component of the velocity of the point.
+---@return number vz # The z component of the velocity of the point.
+function Collider:getLinearVelocityFromWorldPoint(x, y, z) end
+
+---
+---Returns the Collider's center of mass.
+---
+---@return number cx # The x position of the center of mass.
+---@return number cy # The y position of the center of mass.
+---@return number cz # The z position of the center of mass.
+function Collider:getLocalCenter() end
+
+---
+---Converts a point from world coordinates into local coordinates relative to the Collider.
+---
+---@param wx number # The x coordinate of the world point.
+---@param wy number # The y coordinate of the world point.
+---@param wz number # The z coordinate of the world point.
+---@return number x # The x position of the local-space point.
+---@return number y # The y position of the local-space point.
+---@return number z # The z position of the local-space point.
+function Collider:getLocalPoint(wx, wy, wz) end
+
+---
+---Converts a direction vector from world space to local space.
+---
+---@param wx number # The x component of the world vector.
+---@param wy number # The y component of the world vector.
+---@param wz number # The z component of the world vector.
+---@return number x # The x coordinate of the local vector.
+---@return number y # The y coordinate of the local vector.
+---@return number z # The z coordinate of the local vector.
+function Collider:getLocalVector(wx, wy, wz) end
+
+---
+---Returns the total mass of the Collider. The mass of a Collider depends on its attached shapes.
+---
+---@return number mass # The mass of the Collider, in kilograms.
+function Collider:getMass() end
+
+---
+---Computes mass properties for the Collider.
+---
+---@return number cx # The x position of the center of mass.
+---@return number cy # The y position of the center of mass.
+---@return number cz # The z position of the center of mass.
+---@return number mass # The computed mass of the Collider.
+---@return table inertia # A table containing 6 values of the rotational inertia tensor matrix. The table contains the 3 diagonal elements of the matrix (upper left to bottom right), followed by the 3 elements of the upper right portion of the 3x3 matrix.
+function Collider:getMassData() end
+
+---
+---Returns the orientation of the Collider in angle/axis representation.
+---
+---@return number angle # The number of radians the Collider is rotated around its axis of rotation.
+---@return number ax # The x component of the axis of rotation.
+---@return number ay # The y component of the axis of rotation.
+---@return number az # The z component of the axis of rotation.
+function Collider:getOrientation() end
+
+---
+---Returns the position and orientation of the Collider.
+---
+---@return number x # The x position of the Collider, in meters.
+---@return number y # The y position of the Collider, in meters.
+---@return number z # The z position of the Collider, in meters.
+---@return number angle # The number of radians the Collider is rotated around its axis of rotation.
+---@return number ax # The x component of the axis of rotation.
+---@return number ay # The y component of the axis of rotation.
+---@return number az # The z component of the axis of rotation.
+function Collider:getPose() end
+
+---
+---Returns the position of the Collider.
+---
+---@return number x # The x position of the Collider, in meters.
+---@return number y # The y position of the Collider, in meters.
+---@return number z # The z position of the Collider, in meters.
+function Collider:getPosition() end
+
+---
+---Returns the restitution (bounciness) of the Collider. By default, the restitution of two Colliders is combined (the max is used) when they collide to cause them to bounce away from each other. The initial restitution is 0.
+---
+---@return number restitution # The restitution of the Collider.
+function Collider:getRestitution() end
+
+---
+---Returns a list of Shapes attached to the Collider.
+---
+---@return table shapes # A list of Shapes attached to the Collider.
+function Collider:getShapes() end
+
+---
+---Returns the Collider's tag.
+---
+---@return string tag # The Collider's collision tag.
+function Collider:getTag() end
+
+---
+---Returns the user data associated with the Collider.
+---
+---@return any data # The custom value associated with the Collider.
+function Collider:getUserData() end
+
+---
+---Returns the World the Collider is in.
+---
+---@return lovr.World world # The World the Collider is in.
+function Collider:getWorld() end
+
+---
+---Convert a point relative to the collider to a point in world coordinates.
+---
+---@param x number # The x position of the point.
+---@param y number # The y position of the point.
+---@param z number # The z position of the point.
+---@return number wx # The x coordinate of the world point.
+---@return number wy # The y coordinate of the world point.
+---@return number wz # The z coordinate of the world point.
+function Collider:getWorldPoint(x, y, z) end
+
+---
+---Converts a direction vector from local space to world space.
+---
+---@param x number # The x coordinate of the local vector.
+---@param y number # The y coordinate of the local vector.
+---@param z number # The z coordinate of the local vector.
+---@return number wx # The x component of the world vector.
+---@return number wy # The y component of the world vector.
+---@return number wz # The z component of the world vector.
+function Collider:getWorldVector(x, y, z) end
+
+---
+---Returns whether the Collider is currently awake.
+---
+---@return boolean awake # Whether the Collider is awake.
+function Collider:isAwake() end
+
+---
+---Returns whether the Collider is currently ignoring gravity.
+---
+---@return boolean ignored # Whether gravity is ignored for this Collider.
+function Collider:isGravityIgnored() end
+
+---
+---Returns whether the Collider is kinematic.
+---
+---@return boolean kinematic # Whether the Collider is kinematic.
+function Collider:isKinematic() end
+
+---
+---Returns whether the Collider is allowed to sleep.
+---
+---@return boolean allowed # Whether the Collider can go to sleep.
+function Collider:isSleepingAllowed() end
+
+---
+---Removes a Shape from the Collider.
+---
+---@param shape lovr.Shape # The Shape to remove.
+function Collider:removeShape(shape) end
+
+---
+---Sets the angular damping of the Collider. Angular damping makes things less "spinny", causing them to slow down their angular velocity over time. Damping is only applied when angular velocity is over the threshold value.
+---
+---@param damping number # The angular damping.
+---@param threshold? number # Velocity limit below which the damping is not applied.
+function Collider:setAngularDamping(damping, threshold) end
+
+---
+---Sets the angular velocity of the Collider.
+---
+---@param vx number # The x component of the angular velocity.
+---@param vy number # The y component of the angular velocity.
+---@param vz number # The z component of the angular velocity.
+function Collider:setAngularVelocity(vx, vy, vz) end
+
+---
+---Manually puts the Collider to sleep or wakes it up. You can do this if you know a Collider won't be touched for a while or if you need to it be active.
+---
+---@param awake boolean # Whether the Collider should be awake.
+function Collider:setAwake(awake) end
+
+---
+---Sets the friction of the Collider. By default, the friction of two Colliders is combined (multiplied) when they collide to generate a friction force. The initial friction is 0.
+---
+---@param friction number # The new friction.
+function Collider:setFriction(friction) end
+
+---
+---Sets whether the Collider should ignore gravity.
+---
+---@param ignored boolean # Whether gravity should be ignored.
+function Collider:setGravityIgnored(ignored) end
+
+---
+---Sets whether the Collider is kinematic.
+---
+---@param kinematic boolean # Whether the Collider is kinematic.
+function Collider:setKinematic(kinematic) end
+
+---
+---Sets the Collider's linear damping parameter. Linear damping is similar to drag or air resistance, slowing the Collider down over time. Damping is only applied when linear velocity is over the threshold value.
+---
+---@param damping number # The linear damping.
+---@param threshold? number # Velocity limit below which the damping is not applied.
+function Collider:setLinearDamping(damping, threshold) end
+
+---
+---Sets the linear velocity of the Collider directly. Usually it's preferred to use `Collider:applyForce` to change velocity since instantaneous velocity changes can lead to weird glitches.
+---
+---@param vx number # The x velocity of the Collider, in meters per second.
+---@param vy number # The y velocity of the Collider, in meters per second.
+---@param vz number # The z velocity of the Collider, in meters per second.
+function Collider:setLinearVelocity(vx, vy, vz) end
+
+---
+---Sets the total mass of the Collider.
+---
+---@param mass number # The new mass for the Collider, in kilograms.
+function Collider:setMass(mass) end
+
+---
+---Sets mass properties for the Collider.
+---
+---@param cx number # The x position of the center of mass.
+---@param cy number # The y position of the center of mass.
+---@param cz number # The z position of the center of mass.
+---@param mass number # The computed mass of the Collider.
+---@param inertia table # A table containing 6 values of the rotational inertia tensor matrix. The table contains the 3 diagonal elements of the matrix (upper left to bottom right), followed by the 3 elements of the upper right portion of the 3x3 matrix.
+function Collider:setMassData(cx, cy, cz, mass, inertia) end
+
+---
+---Sets the orientation of the Collider in angle/axis representation.
+---
+---@param angle number # The number of radians the Collider is rotated around its axis of rotation.
+---@param ax number # The x component of the axis of rotation.
+---@param ay number # The y component of the axis of rotation.
+---@param az number # The z component of the axis of rotation.
+function Collider:setOrientation(angle, ax, ay, az) end
+
+---
+---Sets the position and orientation of the Collider.
+---
+---@param x number # The x position of the Collider, in meters.
+---@param y number # The y position of the Collider, in meters.
+---@param z number # The z position of the Collider, in meters.
+---@param angle number # The number of radians the Collider is rotated around its axis of rotation.
+---@param ax number # The x component of the axis of rotation.
+---@param ay number # The y component of the axis of rotation.
+---@param az number # The z component of the axis of rotation.
+function Collider:setPose(x, y, z, angle, ax, ay, az) end
+
+---
+---Sets the position of the Collider.
+---
+---@param x number # The x position of the Collider, in meters.
+---@param y number # The y position of the Collider, in meters.
+---@param z number # The z position of the Collider, in meters.
+function Collider:setPosition(x, y, z) end
+
+---
+---Sets the restitution (bounciness) of the Collider. By default, the restitution of two Colliders is combined (the max is used) when they collide to cause them to bounce away from each other. The initial restitution is 0.
+---
+---@param restitution number # The new restitution.
+function Collider:setRestitution(restitution) end
+
+---
+---Sets whether the Collider is allowed to sleep.
+---
+---@param allowed boolean # Whether the Collider can go to sleep.
+function Collider:setSleepingAllowed(allowed) end
+
+---
+---Sets the Collider's tag.
+---
+---@param tag string # The Collider's collision tag.
+function Collider:setTag(tag) end
+
+---
+---Associates a custom value with the Collider.
+---
+---@param data any # The custom value to associate with the Collider.
+function Collider:setUserData(data) end
+
+---
+---A type of `Shape` that can be used for cylinder-shaped things.
+---
+---@class lovr.CylinderShape
+local CylinderShape = {}
+
+---
+---Returns the length of the CylinderShape.
+---
+---@return number length # The length of the cylinder, in meters.
+function CylinderShape:getLength() end
+
+---
+---Returns the radius of the CylinderShape.
+---
+---@return number radius # The radius of the cylinder, in meters.
+function CylinderShape:getRadius() end
+
+---
+---Sets the length of the CylinderShape.
+---
+---@param length number # The new length, in meters.
+function CylinderShape:setLength(length) end
+
+---
+---Sets the radius of the CylinderShape.
+---
+---@param radius number # The new radius, in meters.
+function CylinderShape:setRadius(radius) end
+
+---
+---A DistanceJoint is a type of `Joint` that tries to keep two colliders a fixed distance apart. The distance is determined by the initial distance between the anchor points. The joint allows for rotation on the anchor points.
+---
+---@class lovr.DistanceJoint
+local DistanceJoint = {}
+
+---
+---Returns the anchor points of the DistanceJoint.
+---
+---@return number x1 # The x coordinate of the first anchor point, in world coordinates.
+---@return number y1 # The y coordinate of the first anchor point, in world coordinates.
+---@return number z1 # The z coordinate of the first anchor point, in world coordinates.
+---@return number x2 # The x coordinate of the second anchor point, in world coordinates.
+---@return number y2 # The y coordinate of the second anchor point, in world coordinates.
+---@return number z2 # The z coordinate of the second anchor point, in world coordinates.
+function DistanceJoint:getAnchors() end
+
+---
+---Returns the target distance for the DistanceJoint. The joint tries to keep the Colliders this far apart.
+---
+---@return number distance # The target distance.
+function DistanceJoint:getDistance() end
+
+---
+---Returns the response time of the joint. See `World:setResponseTime` for more info.
+---
+---@return number responseTime # The response time setting for the joint.
+function DistanceJoint:getResponseTime() end
+
+---
+---Returns the tightness of the joint. See `World:setTightness` for how this affects the joint.
+---
+---@return number tightness # The tightness of the joint.
+function DistanceJoint:getTightness() end
+
+---
+---Sets the anchor points of the DistanceJoint.
+---
+---@param x1 number # The x coordinate of the first anchor point, in world coordinates.
+---@param y1 number # The y coordinate of the first anchor point, in world coordinates.
+---@param z1 number # The z coordinate of the first anchor point, in world coordinates.
+---@param x2 number # The x coordinate of the second anchor point, in world coordinates.
+---@param y2 number # The y coordinate of the second anchor point, in world coordinates.
+---@param z2 number # The z coordinate of the second anchor point, in world coordinates.
+function DistanceJoint:setAnchors(x1, y1, z1, x2, y2, z2) end
+
+---
+---Sets the target distance for the DistanceJoint. The joint tries to keep the Colliders this far apart.
+---
+---@param distance number # The new target distance.
+function DistanceJoint:setDistance(distance) end
+
+---
+---Sets the response time of the joint. See `World:setResponseTime` for more info.
+---
+---@param responseTime number # The new response time setting for the joint.
+function DistanceJoint:setResponseTime(responseTime) end
+
+---
+---Sets the tightness of the joint. See `World:setTightness` for how this affects the joint.
+---
+---@param tightness number # The tightness of the joint.
+function DistanceJoint:setTightness(tightness) end
+
+---
+---A HingeJoint is a type of `Joint` that only allows colliders to rotate on a single axis.
+---
+---@class lovr.HingeJoint
+local HingeJoint = {}
+
+---
+---Returns the anchor points of the HingeJoint.
+---
+---@return number x1 # The x coordinate of the first anchor point, in world coordinates.
+---@return number y1 # The y coordinate of the first anchor point, in world coordinates.
+---@return number z1 # The z coordinate of the first anchor point, in world coordinates.
+---@return number x2 # The x coordinate of the second anchor point, in world coordinates.
+---@return number y2 # The y coordinate of the second anchor point, in world coordinates.
+---@return number z2 # The z coordinate of the second anchor point, in world coordinates.
+function HingeJoint:getAnchors() end
+
+---
+---Get the angle between the two colliders attached to the HingeJoint. When the joint is created or when the anchor or axis is set, the current angle is the new "zero" angle.
+---
+---@return number angle # The hinge angle, in radians.
+function HingeJoint:getAngle() end
+
+---
+---Returns the axis of the hinge.
+---
+---@return number x # The x component of the axis.
+---@return number y # The y component of the axis.
+---@return number z # The z component of the axis.
+function HingeJoint:getAxis() end
+
+---
+---Returns the upper and lower limits of the hinge angle. These will be between -π and π.
+---
+---@return number lower # The lower limit, in radians.
+---@return number upper # The upper limit, in radians.
+function HingeJoint:getLimits() end
+
+---
+---Returns the lower limit of the hinge angle. This will be greater than -π.
+---
+---@return number limit # The lower limit, in radians.
+function HingeJoint:getLowerLimit() end
+
+---
+---Returns the upper limit of the hinge angle. This will be less than π.
+---
+---@return number limit # The upper limit, in radians.
+function HingeJoint:getUpperLimit() end
+
+---
+---Sets a new anchor point for the HingeJoint.
+---
+---@param x number # The x coordinate of the anchor point, in world coordinates.
+---@param y number # The y coordinate of the anchor point, in world coordinates.
+---@param z number # The z coordinate of the anchor point, in world coordinates.
+function HingeJoint:setAnchor(x, y, z) end
+
+---
+---Sets the axis of the hinge.
+---
+---@param x number # The x component of the axis.
+---@param y number # The y component of the axis.
+---@param z number # The z component of the axis.
+function HingeJoint:setAxis(x, y, z) end
+
+---
+---Sets the upper and lower limits of the hinge angle. These should be between -π and π.
+---
+---@param lower number # The lower limit, in radians.
+---@param upper number # The upper limit, in radians.
+function HingeJoint:setLimits(lower, upper) end
+
+---
+---Sets the lower limit of the hinge angle. This should be greater than -π.
+---
+---@param limit number # The lower limit, in radians.
+function HingeJoint:setLowerLimit(limit) end
+
+---
+---Sets the upper limit of the hinge angle. This should be less than π.
+---
+---@param limit number # The upper limit, in radians.
+function HingeJoint:setUpperLimit(limit) end
+
+---
+---A Joint is a physics object that constrains the movement of two Colliders.
+---
+---@class lovr.Joint
+local Joint = {}
+
+---
+---Destroy the Joint, removing it from Colliders it's attached to.
+---
+function Joint:destroy() end
+
+---
+---Returns the Colliders the Joint is attached to. All Joints are attached to two colliders.
+---
+---@return lovr.Collider colliderA # The first Collider.
+---@return lovr.Collider colliderB # The second Collider.
+function Joint:getColliders() end
+
+---
+---Returns the type of the Joint.
+---
+---@return lovr.JointType type # The type of the Joint.
+function Joint:getType() end
+
+---
+---Returns the user data associated with the Joint.
+---
+---@return any data # The custom value associated with the Joint.
+function Joint:getUserData() end
+
+---
+---Returns whether the Joint is enabled.
+---
+---@return boolean enabled # Whether the Joint is enabled.
+function Joint:isEnabled() end
+
+---
+---Enable or disable the Joint.
+---
+---@param enabled boolean # Whether the Joint should be enabled.
+function Joint:setEnabled(enabled) end
+
+---
+---Sets the user data associated with the Joint.
+---
+---@param data any # The custom value associated with the Joint.
+function Joint:setUserData(data) end
+
+---
+---A Shape is a physics object that can be attached to colliders to define their shape.
+---
+---@class lovr.Shape
+local Shape = {}
+
+---
+---Destroy the Shape, removing it from Colliders it's attached to.
+---
+function Shape:destroy() end
+
+---
+---Returns the bounding box for the Shape.
+---
+---@return number minx # The minimum x coordinate of the box.
+---@return number maxx # The maximum x coordinate of the box.
+---@return number miny # The minimum y coordinate of the box.
+---@return number maxy # The maximum y coordinate of the box.
+---@return number minz # The minimum z coordinate of the box.
+---@return number maxz # The maximum z coordinate of the box.
+function Shape:getAABB() end
+
+---
+---Returns the Collider the Shape is attached to.
+---
+---@return lovr.Collider collider # The Collider the Shape is attached to.
+function Shape:getCollider() end
+
+---
+---Computes mass properties of the Shape.
+---
+---@param density number # The density to use, in kilograms per cubic meter.
+---@return number cx # The x position of the center of mass.
+---@return number cy # The y position of the center of mass.
+---@return number cz # The z position of the center of mass.
+---@return number mass # The mass of the Shape.
+---@return table inertia # A table containing 6 values of the rotational inertia tensor matrix. The table contains the 3 diagonal elements of the matrix (upper left to bottom right), followed by the 3 elements of the upper right portion of the 3x3 matrix.
+function Shape:getMass(density) end
+
+---
+---Get the orientation of the Shape relative to its Collider.
+---
+---@return number angle # The number of radians the Shape is rotated.
+---@return number ax # The x component of the rotation axis.
+---@return number ay # The y component of the rotation axis.
+---@return number az # The z component of the rotation axis.
+function Shape:getOrientation() end
+
+---
+---Get the position of the Shape relative to its Collider.
+---
+---@return number x # The x offset.
+---@return number y # The y offset.
+---@return number z # The z offset.
+function Shape:getPosition() end
+
+---
+---Returns the type of the Shape.
+---
+---@return lovr.ShapeType type # The type of the Shape.
+function Shape:getType() end
+
+---
+---Returns the user data associated with the Shape.
+---
+---@return any data # The custom value associated with the Shape.
+function Shape:getUserData() end
+
+---
+---Returns whether the Shape is enabled.
+---
+---@return boolean enabled # Whether the Shape is enabled.
+function Shape:isEnabled() end
+
+---
+---Returns whether the Shape is a sensor. Sensors do not trigger any collision response, but they still report collisions in `World:collide`.
+---
+---@return boolean sensor # Whether the Shape is a sensor.
+function Shape:isSensor() end
+
+---
+---Enable or disable the Shape.
+---
+---@param enabled boolean # Whether the Shape should be enabled.
+function Shape:setEnabled(enabled) end
+
+---
+---Set the orientation of the Shape relative to its Collider.
+---
+---@param angle number # The number of radians the Shape is rotated.
+---@param ax number # The x component of the rotation axis.
+---@param ay number # The y component of the rotation axis.
+---@param az number # The z component of the rotation axis.
+function Shape:setOrientation(angle, ax, ay, az) end
+
+---
+---Set the position of the Shape relative to its Collider.
+---
+---@param x number # The x offset.
+---@param y number # The y offset.
+---@param z number # The z offset.
+function Shape:setPosition(x, y, z) end
+
+---
+---Sets whether this Shape is a sensor. Sensors do not trigger any collision response, but they still report collisions in `World:collide`.
+---
+---@param sensor boolean # Whether the Shape should be a sensor.
+function Shape:setSensor(sensor) end
+
+---
+---Sets the user data associated with the Shape.
+---
+---@param data any # The custom value associated with the Shape.
+function Shape:setUserData(data) end
+
+---
+---A SliderJoint is a type of `Joint` that only allows colliders to move on a single axis.
+---
+---@class lovr.SliderJoint
+local SliderJoint = {}
+
+---
+---Returns the axis of the slider.
+---
+---@return number x # The x component of the axis.
+---@return number y # The y component of the axis.
+---@return number z # The z component of the axis.
+function SliderJoint:getAxis() end
+
+---
+---Returns the upper and lower limits of the slider position.
+---
+---@return number lower # The lower limit.
+---@return number upper # The upper limit.
+function SliderJoint:getLimits() end
+
+---
+---Returns the lower limit of the slider position.
+---
+---@return number limit # The lower limit.
+function SliderJoint:getLowerLimit() end
+
+---
+---Returns the upper limit of the slider position.
+---
+---@return number limit # The upper limit.
+function SliderJoint:getUpperLimit() end
+
+---
+---Sets the axis of the slider.
+---
+---@param x number # The x component of the axis.
+---@param y number # The y component of the axis.
+---@param z number # The z component of the axis.
+function SliderJoint:setAxis(x, y, z) end
+
+---
+---Sets the upper and lower limits of the slider position.
+---
+---@param lower number # The lower limit.
+---@param upper number # The upper limit.
+function SliderJoint:setLimits(lower, upper) end
+
+---
+---Sets the lower limit of the slider position.
+---
+---@param limit number # The lower limit.
+function SliderJoint:setLowerLimit(limit) end
+
+---
+---Sets the upper limit of the slider position.
+---
+---@param limit number # The upper limit.
+function SliderJoint:setUpperLimit(limit) end
+
+---
+---A type of `Shape` that can be used for spheres.
+---
+---@class lovr.SphereShape
+local SphereShape = {}
+
+---
+---Returns the radius of the SphereShape.
+---
+---@return number radius # The radius of the sphere, in meters.
+function SphereShape:getDimensions() end
+
+---
+---Sets the radius of the SphereShape.
+---
+---@param radius number # The radius of the sphere, in meters.
+function SphereShape:setDimensions(radius) end
+
+---
+---A World is an object that holds the colliders, joints, and shapes in a physics simulation.
+---
+---@class lovr.World
+local World = {}
+
+---
+---Attempt to collide two shapes. Internally this uses joints and forces to ensure the colliders attached to the shapes do not pass through each other. Collisions can be customized using friction and restitution (bounciness) parameters, and default to using a mix of the colliders' friction and restitution parameters. Usually this is called automatically by `World:update`.
+---
+---@param shapeA lovr.Shape # The first shape.
+---@param shapeB lovr.Shape # The second shape.
+---@param friction? number # The friction parameter for the collision.
+---@param restitution? number # The restitution (bounciness) parameter for the collision.
+---@return boolean collided # Whether the shapes collided.
+function World:collide(shapeA, shapeB, friction, restitution) end
+
+---
+---Detects which pairs of shapes in the world are near each other and could be colliding. After calling this function, the `World:overlaps` iterator can be used to iterate over the overlaps, and `World:collide` can be used to resolve a collision for the shapes (if any). Usually this is called automatically by `World:update`.
+---
+function World:computeOverlaps() end
+
+---
+---Destroy the World!
+---
+function World:destroy() end
+
+---
+---Disables collision between two collision tags.
+---
+---@param tag1 string # The first tag.
+---@param tag2 string # The second tag.
+function World:disableCollisionBetween(tag1, tag2) end
+
+---
+---Enables collision between two collision tags.
+---
+---@param tag1 string # The first tag.
+---@param tag2 string # The second tag.
+function World:enableCollisionBetween(tag1, tag2) end
+
+---
+---Returns the angular damping parameters of the World. Angular damping makes things less "spinny", making them slow down their angular velocity over time.
+---
+---@return number damping # The angular damping.
+---@return number threshold # Velocity limit below which the damping is not applied.
+function World:getAngularDamping() end
+
+---
+---Returns a table of all Colliders in the World.
+---
+---@overload fun(t: table):table
+---@return table colliders # A table of `Collider` objects.
+function World:getColliders() end
+
+---
+---Returns the gravity of the World.
+---
+---@return number xg # The x component of the gravity force.
+---@return number yg # The y component of the gravity force.
+---@return number zg # The z component of the gravity force.
+function World:getGravity() end
+
+---
+---Returns the linear damping parameters of the World. Linear damping is similar to drag or air resistance, slowing down colliders over time as they move.
+---
+---@return number damping # The linear damping.
+---@return number threshold # Velocity limit below which the damping is not applied.
+function World:getLinearDamping() end
+
+---
+---Returns the response time factor of the World.
+---
+---The response time controls how relaxed collisions and joints are in the physics simulation, and functions similar to inertia. A low response time means collisions are resolved quickly, and higher values make objects more spongy and soft.
+---
+---The value can be any positive number. It can be changed on a per-joint basis for `DistanceJoint` and `BallJoint` objects.
+---
+---@return number responseTime # The response time setting for the World.
+function World:getResponseTime() end
+
+---
+---Returns the tightness of the joint. See `World:setTightness` for how this affects the joint.
+---
+---@return number tightness # The tightness of the joint.
+function World:getTightness() end
+
+---
+---Returns whether collisions are currently enabled between two tags.
+---
+---@param tag1 string # The first tag.
+---@param tag2 string # The second tag.
+---@return boolean enabled # Whether or not two colliders with the specified tags will collide.
+function World:isCollisionEnabledBetween(tag1, tag2) end
+
+---
+---Returns whether colliders can go to sleep in the World.
+---
+---@return boolean allowed # Whether colliders can sleep.
+function World:isSleepingAllowed() end
+
+---
+---Adds a new Collider to the World with a BoxShape already attached.
+---
+---@param x? number # The x coordinate of the center of the box.
+---@param y? number # The y coordinate of the center of the box.
+---@param z? number # The z coordinate of the center of the box.
+---@param width? number # The total width of the box, in meters.
+---@param height? number # The total height of the box, in meters.
+---@param depth? number # The total depth of the box, in meters.
+---@return lovr.Collider collider # The new Collider.
+function World:newBoxCollider(x, y, z, width, height, depth) end
+
+---
+---Adds a new Collider to the World with a CapsuleShape already attached.
+---
+---@param x? number # The x coordinate of the center of the capsule.
+---@param y? number # The y coordinate of the center of the capsule.
+---@param z? number # The z coordinate of the center of the capsule.
+---@param radius? number # The radius of the capsule, in meters.
+---@param length? number # The length of the capsule, not including the caps, in meters.
+---@return lovr.Collider collider # The new Collider.
+function World:newCapsuleCollider(x, y, z, radius, length) end
+
+---
+---Adds a new Collider to the World.
+---
+---@param x? number # The x position of the Collider.
+---@param y? number # The y position of the Collider.
+---@param z? number # The z position of the Collider.
+---@return lovr.Collider collider # The new Collider.
+function World:newCollider(x, y, z) end
+
+---
+---Adds a new Collider to the World with a CylinderShape already attached.
+---
+---@param x? number # The x coordinate of the center of the cylinder.
+---@param y? number # The y coordinate of the center of the cylinder.
+---@param z? number # The z coordinate of the center of the cylinder.
+---@param radius? number # The radius of the cylinder, in meters.
+---@param length? number # The length of the cylinder, in meters.
+---@return lovr.Collider collider # The new Collider.
+function World:newCylinderCollider(x, y, z, radius, length) end
+
+---
+---Adds a new Collider to the World with a MeshShape already attached.
+---
+---@overload fun(model: lovr.Model):lovr.Collider
+---@param vertices table # The table of vertices in the mesh. Each vertex is a table with 3 numbers.
+---@param indices table # A table of triangle indices representing how the vertices are connected in the Mesh.
+---@return lovr.Collider collider # The new Collider.
+function World:newMeshCollider(vertices, indices) end
+
+---
+---Adds a new Collider to the World with a SphereShape already attached.
+---
+---@param x? number # The x coordinate of the center of the sphere.
+---@param y? number # The y coordinate of the center of the sphere.
+---@param z? number # The z coordinate of the center of the sphere.
+---@param radius? number # The radius of the sphere, in meters.
+---@return lovr.Collider collider # The new Collider.
+function World:newSphereCollider(x, y, z, radius) end
+
+---
+---Returns an iterator that can be used to iterate over "overlaps", or potential collisions between pairs of shapes in the World. This should be called after using `World:detectOverlaps` to compute the list of overlaps. Usually this is called automatically by `World:update`.
+---
+---@return function iterator # A Lua iterator, usable in a for loop.
+function World:overlaps() end
+
+---
+---Casts a ray through the World, calling a function every time the ray intersects with a Shape.
+---
+---@param x1 number # The x coordinate of the starting position of the ray.
+---@param y1 number # The y coordinate of the starting position of the ray.
+---@param z1 number # The z coordinate of the starting position of the ray.
+---@param x2 number # The x coordinate of the ending position of the ray.
+---@param y2 number # The y coordinate of the ending position of the ray.
+---@param z2 number # The z coordinate of the ending position of the ray.
+---@param callback function # The function to call when an intersection is detected.
+function World:raycast(x1, y1, z1, x2, y2, z2, callback) end
+
+---
+---Sets the angular damping of the World. Angular damping makes things less "spinny", making them slow down their angular velocity over time. Damping is only applied when angular velocity is over the threshold value.
+---
+---@param damping number # The angular damping.
+---@param threshold? number # Velocity limit below which the damping is not applied.
+function World:setAngularDamping(damping, threshold) end
+
+---
+---Sets the gravity of the World.
+---
+---@param xg number # The x component of the gravity force.
+---@param yg number # The y component of the gravity force.
+---@param zg number # The z component of the gravity force.
+function World:setGravity(xg, yg, zg) end
+
+---
+---Sets the linear damping of the World. Linear damping is similar to drag or air resistance, slowing down colliders over time as they move. Damping is only applied when linear velocity is over the threshold value.
+---
+---@param damping number # The linear damping.
+---@param threshold? number # Velocity limit below which the damping is not applied.
+function World:setLinearDamping(damping, threshold) end
+
+---
+---Sets the response time factor of the World.
+---
+---The response time controls how relaxed collisions and joints are in the physics simulation, and functions similar to inertia. A low response time means collisions are resolved quickly, and higher values make objects more spongy and soft.
+---
+---The value can be any positive number. It can be changed on a per-joint basis for `DistanceJoint` and `BallJoint` objects.
+---
+---@param responseTime number # The new response time setting for the World.
+function World:setResponseTime(responseTime) end
+
+---
+---Sets whether colliders can go to sleep in the World.
+---
+---@param allowed boolean # Whether colliders can sleep.
+function World:setSleepingAllowed(allowed) end
+
+---
+---Sets the tightness of joints in the World.
+---
+---The tightness controls how much force is applied to colliders connected by joints. With a value of 0, no force will be applied and joints won't have any effect. With a tightness of 1, a strong force will be used to try to keep the Colliders constrained. A tightness larger than 1 will overcorrect the joints, which can sometimes be desirable. Negative tightness values are not supported.
+---
+---@param tightness number # The new tightness for the World.
+function World:setTightness(tightness) end
+
+---
+---Updates the World, advancing the physics simulation forward in time and resolving collisions between colliders in the World.
+---
+---@param dt number # The amount of time to advance the simulation forward.
+---@param resolver? function # The collision resolver function to use. This will be called before updating to allow for custom collision processing. If absent, a default will be used.
+function World:update(dt, resolver) end
+
+---
+---Represents the different types of physics Joints available.
+---
+---@class lovr.JointType
+---
+---A BallJoint.
+---
+---@field ball integer
+---
+---A DistanceJoint.
+---
+---@field distance integer
+---
+---A HingeJoint.
+---
+---@field hinge integer
+---
+---A SliderJoint.
+---
+---@field slider integer
+
+---
+---Represents the different types of physics Shapes available.
+---
+---@class lovr.ShapeType
+---
+---A BoxShape.
+---
+---@field box integer
+---
+---A CapsuleShape.
+---
+---@field capsule integer
+---
+---A CylinderShape.
+---
+---@field cylinder integer
+---
+---A SphereShape.
+---
+---@field sphere integer
diff --git a/meta/3rd/lovr/library/lovr.system.lua b/meta/3rd/lovr/library/lovr.system.lua
new file mode 100644
index 00000000..cd493f18
--- /dev/null
+++ b/meta/3rd/lovr/library/lovr.system.lua
@@ -0,0 +1,34 @@
+---@meta
+
+---
+---The `lovr.system` provides information about the current operating system, and platform, and hardware.
+---
+---@class lovr.system
+lovr.system = {}
+
+---
+---Returns the number of logical cores on the system.
+---
+---@return number cores # The number of logical cores on the system.
+function lovr.system.getCoreCount() end
+
+---
+---Returns the current operating system.
+---
+---@return string os # Either "Windows", "macOS", "Linux", "Android" or "Web".
+function lovr.system.getOS() end
+
+---
+---Requests permission to use a feature. Usually this will pop up a dialog box that the user needs to confirm. Once the permission request has been acknowledged, the `lovr.permission` callback will be called with the result. Currently, this is only used for requesting microphone access on Android devices.
+---
+---@param permission lovr.Permission # The permission to request.
+function lovr.system.requestPermission(permission) end
+
+---
+---These are the different permissions that need to be requested using `lovr.system.requestPermission` on some platforms.
+---
+---@class lovr.Permission
+---
+---Requests microphone access.
+---
+---@field audiocapture integer
diff --git a/meta/3rd/lovr/library/lovr.thread.lua b/meta/3rd/lovr/library/lovr.thread.lua
new file mode 100644
index 00000000..ca329a6b
--- /dev/null
+++ b/meta/3rd/lovr/library/lovr.thread.lua
@@ -0,0 +1,114 @@
+---@meta
+
+---
+---The `lovr.thread` module provides functions for creating threads and communicating between them.
+---
+---These are operating system level threads, which are different from Lua coroutines.
+---
+---Threads are useful for performing expensive background computation without affecting the framerate or performance of the main thread. Some examples of this include asset loading, networking and network requests, and physics simulation.
+---
+---Threads come with some caveats:
+---
+---- Threads run in a bare Lua environment. The `lovr` module (and any of lovr's modules) need to
+--- be required before they can be used.
+--- - To get `require` to work properly, add `require 'lovr.filesystem'` to the thread code.
+---- Threads are completely isolated from other threads. They do not have access to the variables
+--- or functions of other threads, and communication between threads must be coordinated through
+--- `Channel` objects.
+---- The graphics module (or any functions that perform rendering) cannot be used in a thread.
+--- Note that this includes creating graphics objects like Models and Textures. There are "data"
+--- equivalent `ModelData` and `Image` objects that can be used in threads though.
+---- `lovr.event.pump` cannot be called from a thread.
+---- Crashes or problems can happen if two threads access the same object at the same time, so
+--- special care must be taken to coordinate access to objects from multiple threads.
+---
+---@class lovr.thread
+lovr.thread = {}
+
+---
+---Returns a named Channel for communicating between threads.
+---
+---@param name string # The name of the Channel to get.
+---@return lovr.Channel channel # The Channel with the specified name.
+function lovr.thread.getChannel(name) end
+
+---
+---Creates a new Thread from Lua code.
+---
+---@overload fun(filename: string):lovr.Thread
+---@overload fun(blob: lovr.Blob):lovr.Thread
+---@param code string # The code to run in the Thread.
+---@return lovr.Thread thread # The new Thread.
+function lovr.thread.newThread(code) end
+
+---
+---A Channel is an object used to communicate between `Thread` objects. Channels are obtained by name using `lovr.thread.getChannel`. Different threads can send messages on the same Channel to communicate with each other. Messages can be sent and received on a Channel using `Channel:push` and `Channel:pop`, and are received in a first-in-first-out fashion. The following types of data can be passed through Channels: nil, boolean, number, string, and any LÖVR object.
+---
+---@class lovr.Channel
+local Channel = {}
+
+---
+---Removes all pending messages from the Channel.
+---
+function Channel:clear() end
+
+---
+---Returns whether or not the message with the given ID has been read. Every call to `Channel:push` returns a message ID.
+---
+---@param id number # The ID of the message to check.
+---@return boolean read # Whether the message has been read.
+function Channel:hasRead(id) end
+
+---
+---Returns a message from the Channel without popping it from the queue. If the Channel is empty, `nil` is returned. This can be useful to determine if the Channel is empty.
+---
+---@return any message # The message, or `nil` if there is no message.
+---@return boolean present # Whether a message was returned (use to detect nil).
+function Channel:peek() end
+
+---
+---Pops a message from the Channel. If the Channel is empty, an optional timeout argument can be used to wait for a message, otherwise `nil` is returned.
+---
+---@param wait? number # How long to wait for a message to be popped, in seconds. `true` can be used to wait forever and `false` can be used to avoid waiting.
+---@return any message # The received message, or `nil` if nothing was received.
+function Channel:pop(wait) end
+
+---
+---Pushes a message onto the Channel. The following types of data can be pushed: nil, boolean, number, string, and userdata. Tables should be serialized to strings.
+---
+---@param message any # The message to push.
+---@param wait? number # How long to wait for the message to be popped, in seconds. `true` can be used to wait forever and `false` can be used to avoid waiting.
+---@return number id # The ID of the pushed message.
+---@return boolean read # Whether the message was read by another thread before the wait timeout.
+function Channel:push(message, wait) end
+
+---
+---A Thread is an object that runs a chunk of Lua code in the background. Threads are completely isolated from other threads, meaning they have their own Lua context and can't access the variables and functions of other threads. Communication between threads is limited and is accomplished by using `Channel` objects.
+---
+---To get `require` to work properly, add `require 'lovr.filesystem'` to the thread code.
+---
+---@class lovr.Thread
+local Thread = {}
+
+---
+---Returns the message for the error that occurred on the Thread, or nil if no error has occurred.
+---
+---@return string error # The error message, or `nil` if no error has occurred on the Thread.
+function Thread:getError() end
+
+---
+---Returns whether or not the Thread is currently running.
+---
+---@return boolean running # Whether or not the Thread is running.
+function Thread:isRunning() end
+
+---
+---Starts the Thread.
+---
+---@param arguments any # Up to 4 arguments to pass to the Thread's function.
+function Thread:start(arguments) end
+
+---
+---Waits for the Thread to complete, then returns.
+---
+function Thread:wait() end
diff --git a/meta/3rd/lovr/library/lovr.timer.lua b/meta/3rd/lovr/library/lovr.timer.lua
new file mode 100644
index 00000000..b4693e4c
--- /dev/null
+++ b/meta/3rd/lovr/library/lovr.timer.lua
@@ -0,0 +1,43 @@
+---@meta
+
+---
+---The `lovr.timer` module provides a few functions that deal with time. All times are measured in seconds.
+---
+---@class lovr.timer
+lovr.timer = {}
+
+---
+---Returns the average delta over the last second.
+---
+---@return number delta # The average delta, in seconds.
+function lovr.timer.getAverageDelta() end
+
+---
+---Returns the time between the last two frames. This is the same value as the `dt` argument provided to `lovr.update`.
+---
+---@return number dt # The delta time, in seconds.
+function lovr.timer.getDelta() end
+
+---
+---Returns the current frames per second, averaged over the last 90 frames.
+---
+---@return number fps # The current FPS.
+function lovr.timer.getFPS() end
+
+---
+---Returns the time since some time in the past. This can be used to measure the difference between two points in time.
+---
+---@return number time # The current time, in seconds.
+function lovr.timer.getTime() end
+
+---
+---Sleeps the application for a specified number of seconds. While the game is asleep, no code will be run, no graphics will be drawn, and the window will be unresponsive.
+---
+---@param duration number # The number of seconds to sleep for.
+function lovr.timer.sleep(duration) end
+
+---
+---Steps the timer, returning the new delta time. This is called automatically in `lovr.run` and it's used to calculate the new `dt` to pass to `lovr.update`.
+---
+---@return number delta # The amount of time since the last call to this function, in seconds.
+function lovr.timer.step() end
diff --git a/meta/3rd/skynet/library/skynet.lua b/meta/3rd/skynet/library/skynet.lua
index 4fdb29d0..2ce96339 100644
--- a/meta/3rd/skynet/library/skynet.lua
+++ b/meta/3rd/skynet/library/skynet.lua
@@ -12,35 +12,35 @@
---|+'"debug"'
---|+'"trace"'
---@alias SERVICEADDR '".servicename"' | '":0000000C"' | integer
----@alias MESSAGEHANDLER fun(session:integer, source:integer, ...)
+---@alias MESSAGEHANDLER fun(session:integer, source:integer, cmd:string, ...)
local skynet = {
- -- read skynet.h
- PTYPE_TEXT = 0,
- PTYPE_RESPONSE = 1,
- PTYPE_MULTICAST = 2,
- PTYPE_CLIENT = 3,
- PTYPE_SYSTEM = 4,
- PTYPE_HARBOR = 5,
- PTYPE_SOCKET = 6,
- PTYPE_ERROR = 7,
- PTYPE_QUEUE = 8, -- used in deprecated mqueue, use skynet.queue instead
- PTYPE_DEBUG = 9,
- PTYPE_LUA = 10,
- PTYPE_SNAX = 11,
- PTYPE_TRACE = 12, -- use for debug trace
- PNAME_TEXT = "text",
- PNAME_RESPONSE = "response",
- PNAME_MULTICAST = "muliticast",
- PNAME_CLIENT = "client",
- PNAME_SYSTEM = "system",
- PNAME_HARBOR = "harbor",
- PNAME_SOCKET = "socket",
- PNAME_ERROR = "error",
- PNAME_QUEUE = "queue",
- PNAME_DEBUG = "debug",
- PNAME_LUA = "lua",
- PNAME_SNAX = "snax",
- PNAME_TRACE = "trace",
+ -- read skynet.h
+ PTYPE_TEXT = 0,
+ PTYPE_RESPONSE = 1,
+ PTYPE_MULTICAST = 2,
+ PTYPE_CLIENT = 3,
+ PTYPE_SYSTEM = 4,
+ PTYPE_HARBOR = 5,
+ PTYPE_SOCKET = 6,
+ PTYPE_ERROR = 7,
+ PTYPE_QUEUE = 8, -- used in deprecated mqueue, use skynet.queue instead
+ PTYPE_DEBUG = 9,
+ PTYPE_LUA = 10,
+ PTYPE_SNAX = 11,
+ PTYPE_TRACE = 12, -- use for debug trace
+ PNAME_TEXT = "text",
+ PNAME_RESPONSE = "response",
+ PNAME_MULTICAST = "muliticast",
+ PNAME_CLIENT = "client",
+ PNAME_SYSTEM = "system",
+ PNAME_HARBOR = "harbor",
+ PNAME_SOCKET = "socket",
+ PNAME_ERROR = "error",
+ PNAME_QUEUE = "queue",
+ PNAME_DEBUG = "debug",
+ PNAME_LUA = "lua",
+ PNAME_SNAX = "snax",
+ PNAME_TRACE = "trace",
}
@@ -97,9 +97,12 @@ end
---* 向当前会话返回数据
---* 会自动获取当前线程所关联的会话ID和返回地址
----* 由于某些历史原因(早期的 skynet 默认消息类别是文本,而没有经过特殊编码),这个 API 被设计成传递一个 C 指针和长度,而不是经过当前消息的 pack 函数打包。或者你也可以省略 size 而传入一个字符串。
+---* 由于某些历史原因(早期的 skynet 默认消息类别是文本,而没有经过特殊编码),
+---这个 API 被设计成传递一个 C 指针和长度,而不是经过当前消息的 pack 函数打包。或者你也可以省略 size 而传入一个字符串。
---* 在同一个消息处理的 coroutine 中只可以被调用一次,多次调用会触发异常。
----* 你需要挂起一个请求,等将来时机满足,再回应它。而回应的时候已经在别的 coroutine 中了。针对这种情况,你可以调用 skynet.response(skynet.pack) 获得一个闭包,以后调用这个闭包即可把回应消息发回。这里的参数 skynet.pack 是可选的,你可以传入其它打包函数,默认即是 skynet.pack 。
+---* 你需要挂起一个请求,等将来时机满足,再回应它。而回应的时候已经在别的 coroutine 中了。
+---针对这种情况,你可以调用 skynet.response(skynet.pack) 获得一个闭包,以后调用这个闭包即可把回应消息发回。
+---这里的参数 skynet.pack 是可选的,你可以传入其它打包函数,默认即是 skynet.pack 。
---@param msg lightuserdata
---@param sz integer
function skynet.ret(msg, sz)
@@ -110,8 +113,8 @@ function skynet.retpack(...)
end
---返回一个闭包以进行延迟回应
----@param pack fun(...):string| userdata,sz
----@return fun(isOK:boolean | 'TEST', ...):
+---@param pack fun(...):string|lightuserdata,integer #默认会用 skynet.pack
+---@return fun(isOK:boolean | 'TEST', ...)
function skynet.response(pack)
end
@@ -138,7 +141,9 @@ end
--------------------序列化相关API---------------
---* 可以将一组 lua 对象序列化为一个由 malloc 分配出来的 C 指针加一个数字长度
----* 你需要考虑 C 指针引用的数据块何时释放的问题。当然,如果你只是将 skynet.pack 填在消息处理框架里时,框架解决了这个管理问题。skynet 将 C 指针发送到其他服务,而接收方会在使用完后释放这个指针。
+---* 你需要考虑 C 指针引用的数据块何时释放的问题。当然,如果你只是将 skynet.pack 填在消息
+--- 处理框架里时,框架解决了这个管理问题。skynet 将 C 指针发送到其他服务,而接收方会在使用完
+--- 后释放这个指针。
---@vararg any
---@return lightuserdata, number
function skynet.pack(...)
@@ -159,8 +164,8 @@ function skynet.unpack(msg, sz)
end
---* 将 C 指针转换成 Lua 字符串
----@param msg lightuserdata
----@param sz number
+---@param msg lightuserdata|string
+---@param sz number #如果是传递的 string,则不需要 此参数
---@return string
function skynet.tostring(msg, sz)
end
@@ -176,7 +181,8 @@ end
---* **非阻塞API**
---* 这条 API 可以把一条类别为 typename 的消息发送给 address 。它会先经过事先注册的 pack 函数打包 ... 的内容。
---* 实际上也是利用了 c.send 不过传送的会话ID是0
----* 接收端接收完毕消息后,默认情况下,消息会由 skynet 释放。具体可以查看 skynet-server.c 中的 dispatch_message 的代码
+---* 接收端接收完毕消息后,默认情况下,消息会由 skynet 释放。
+--- 具体可以查看 skynet-server.c 中的 dispatch_message 的代码
---@param addr SERVICEADDR
---@param typename string @类型名
---@vararg any @传输的数据
@@ -239,7 +245,7 @@ end
function request:select(timeout)
end
----@param obj?
+---@param obj? table
---@return request
function skynet.request(obj)
end
@@ -286,6 +292,8 @@ end
--- 用于启动一个新的 Lua 服务。name 是脚本的名字(不用写 .lua 后缀)。只有被启动的脚本的 start 函数返回后,这个 API 才会返回启动的服务的地址,这是一个阻塞 API 。如果被启动的脚本在初始化环节抛出异常,或在初始化完成前就调用 skynet.exit 退出,skynet.newservice 都会抛出异常。如果被启动的脚本的 start 函数是一个永不结束的循环,那么 newservice 也会被永远阻塞住。
--- > 启动参数其实是以字符串拼接的方式传递过去的。所以不要在参数中传递复杂的 Lua 对象。接收到的参数都是字符串,且字符串中不可以有空格(否则会被分割成多个参数)。这种参数传递方式是历史遗留下来的,有很多潜在的问题。目前推荐的惯例是,让你的服务响应一个启动消息。在 newservice 之后,立刻调用 skynet.call 发送启动请求。
+---@param name string #脚本名字
+---@vararg string #可选参数
function skynet.newservice(name, ...)
end
@@ -475,25 +483,31 @@ function skynet.memlimit(bytes)
end
------------------以下是属于 skynet.manager 中的 api
+
+---* **skynet.manager API**
---* 启动一个C 服务,具体参数要看 C服务是怎么编写的
---@vararg any
function skynet.launch(...)
end
+---* **skynet.manager API**
--- 可以用来强制关闭别的服务。但强烈不推荐这样做。因为对象会在任意一条消息处理完毕后,毫无征兆的退出。所以推荐的做法是,发送一条消息,让对方自己善后以及调用 skynet.exit 。注:skynet.kill(skynet.self()) 不完全等价于 skynet.exit() ,后者更安全。
---@param name number|string
function skynet.kill(name)
end
+---* **skynet.manager API**
---* 向引擎发送一个 ABORT 命令,退出自身服务
function skynet.abort()
end
+---* **skynet.manager API**
---* 给服务注册一个名字
---@param name string
function skynet.register(name)
end
+---* **skynet.manager API**
---* 给服务命名 以 . 开头的名字是在同一 skynet 节点下有效的
---* skynet.name(name, skynet.self()) 和 skynet.register(name) 功能等价。
---@param name string
@@ -501,6 +515,7 @@ end
function skynet.name(name, handle)
end
+---* **skynet.manager API**
---* 将本服务实现为消息转发器,对一类消息进行转发
---* 设置指定类型的消息,不由 skynet 框架释放
---* 对于在 map 中的消息,不进行释放
@@ -510,12 +525,14 @@ end
function skynet.forward_type(map, start_func)
end
+---* **skynet.manager API**
---过滤消息再处理。(注:filter 可以将 type, msg, sz, session, source 五个参数先处理过再返回新的 5 个参数。)
---@param f any
---@param start_func any
function skynet.filter(f, start_func)
end
+---* **skynet.manager API**
---给当前 skynet 进程设置一个全局的服务监控。
---@param service any
---@param query any
diff --git a/meta/template/basic.lua b/meta/template/basic.lua
index 5665dc59..b26d3959 100644
--- a/meta/template/basic.lua
+++ b/meta/template/basic.lua
@@ -55,13 +55,15 @@ _G = {}
---@version 5.1
---#DES 'getfenv'
----@param f? function
+---@param f? async fun()
---@return table
+---@nodiscard
function getfenv(f) end
---#DES 'getmetatable'
---@param object any
---@return table metatable
+---@nodiscard
function getmetatable(object) end
---#DES 'ipairs'
@@ -83,6 +85,7 @@ function ipairs(t) end
---@param chunkname? string
---@return function
---@return string error_message
+---@nodiscard
function load(func, chunkname) end
---#else
---#DES 'load>5.2'
@@ -92,6 +95,7 @@ function load(func, chunkname) end
---@param env? table
---@return function
---@return string error_message
+---@nodiscard
function load(chunk, chunkname, mode, env) end
---#end
@@ -100,6 +104,7 @@ function load(chunk, chunkname, mode, env) end
---@param filename? string
---@return function
---@return string error_message
+---@nodiscard
function loadfile(filename) end
---#else
---#DES 'loadfile'
@@ -108,6 +113,7 @@ function loadfile(filename) end
---@param env? table
---@return function
---@return string error_message
+---@nodiscard
function loadfile(filename, mode, env) end
---#end
@@ -117,6 +123,7 @@ function loadfile(filename, mode, env) end
---@param chunkname? string
---@return function
---@return string error_message
+---@nodiscard
function loadstring(text, chunkname) end
---@version 5.1
@@ -130,6 +137,7 @@ function module(name, ...) end
---@param index? K
---@return K
---@return V
+---@nodiscard
function next(table, index) end
---#DES 'pairs'
@@ -140,7 +148,11 @@ function next(table, index) end
function pairs(t) end
---#DES 'pcall'
+---#if VERSION == 5.1 and not JIT then
---@param f function
+---#else
+---@param f async fun()
+---#end
---@param arg1? any
---@return boolean success
---@return any result
@@ -154,17 +166,20 @@ function print(...) end
---@param v1 any
---@param v2 any
---@return boolean
+---@nodiscard
function rawequal(v1, v2) end
---#DES 'rawget'
---@param table table
---@param index any
---@return any
+---@nodiscard
function rawget(table, index) end
---#DES 'rawlen'
---@param v table|string
---@return integer len
+---@nodiscard
function rawlen(v) end
---#DES 'rawset'
@@ -177,11 +192,12 @@ function rawset(table, index, value) end
---#DES 'select'
---@param index integer|'"#"'
---@return any
+---@nodiscard
function select(index, ...) end
---@version 5.1
---#DES 'setfenv'
----@param f function|integer
+---@param f async fun()|integer
---@param table table
---@return function
function setfenv(f, table) end
@@ -196,11 +212,13 @@ function setmetatable(table, metatable) end
---@param e string|number
---@param base? integer
---@return number?
+---@nodiscard
function tonumber(e, base) end
---#DES 'tostring'
---@param v any
---@return string
+---@nodiscard
function tostring(v) end
---@alias type
@@ -216,6 +234,7 @@ function tostring(v) end
---#DES 'type'
---@param v any
---@return type type
+---@nodiscard
function type(v) end
---#DES '_VERSION'
@@ -244,7 +263,7 @@ function warn(message, ...) end
function xpcall(f, err) end
---#else
---#DES 'xpcall>5.2'
----@param f function
+---@param f async fun()
---@param msgh function
---@param arg1? any
---@return boolean success
@@ -258,4 +277,5 @@ function xpcall(f, msgh, arg1, ...) end
---@param list table
---@param i? integer
---@param j? integer
+---@nodiscard
function unpack(list, i, j) end
diff --git a/meta/template/bit.lua b/meta/template/bit.lua
index d7cfd302..369c5f9d 100644
--- a/meta/template/bit.lua
+++ b/meta/template/bit.lua
@@ -7,62 +7,74 @@ bit = {}
---@param x integer
---@return integer y
+---@nodiscard
function bit.tobit(x) end
---@param x integer
---@param n? integer
---@return integer y
+---@nodiscard
function bit.tohex(x, n) end
---@param x integer
---@return integer y
+---@nodiscard
function bit.bnot(x) end
----@param x integer
----@param x2 integer
----@vararg integer
+---@param x integer
+---@param x2 integer
+---@param ... integer
---@return integer y
+---@nodiscard
function bit.bor(x, x2, ...) end
----@param x integer
----@param x2 integer
----@vararg integer
+---@param x integer
+---@param x2 integer
+---@param ... integer
---@return integer y
+---@nodiscard
function bit.band(x, x2, ...) end
----@param x integer
----@param x2 integer
----@vararg integer
+---@param x integer
+---@param x2 integer
+---@param ... integer
---@return integer y
+---@nodiscard
function bit.bxor(x, x2, ...) end
---@param x integer
---@param n integer
---@return integer y
+---@nodiscard
function bit.lshift(x, n) end
---@param x integer
---@param n integer
---@return integer y
+---@nodiscard
function bit.rshift(x, n) end
---@param x integer
---@param n integer
---@return integer y
+---@nodiscard
function bit.arshift(x, n) end
---@param x integer
---@param n integer
---@return integer y
+---@nodiscard
function bit.rol(x, n) end
---@param x integer
---@param n integer
---@return integer y
+---@nodiscard
function bit.ror(x, n) end
---@param x integer
---@return integer y
+---@nodiscard
function bit.bswap(x) end
return bit
diff --git a/meta/template/bit32.lua b/meta/template/bit32.lua
index 85bd04f1..bcb39c66 100644
--- a/meta/template/bit32.lua
+++ b/meta/template/bit32.lua
@@ -10,27 +10,33 @@ bit32 = {}
---@param x integer
---@param disp integer
---@return integer
+---@nodiscard
function bit32.arshift(x, disp) end
---#DES 'bit32.band'
---@return integer
+---@nodiscard
function bit32.band(...) end
---#DES 'bit32.bnot'
---@param x integer
---@return integer
+---@nodiscard
function bit32.bnot(x) end
---#DES 'bit32.bor'
---@return integer
+---@nodiscard
function bit32.bor(...) end
---#DES 'bit32.btest'
---@return boolean
+---@nodiscard
function bit32.btest(...) end
---#DES 'bit32.bxor'
---@return integer
+---@nodiscard
function bit32.bxor(...) end
---#DES 'bit32.extract'
@@ -38,6 +44,7 @@ function bit32.bxor(...) end
---@param field integer
---@param width? integer
---@return integer
+---@nodiscard
function bit32.extract(n, field, width) end
---#DES 'bit32.replace'
@@ -45,30 +52,35 @@ function bit32.extract(n, field, width) end
---@param v integer
---@param field integer
---@param width? integer
+---@nodiscard
function bit32.replace(n, v, field, width) end
---#DES 'bit32.lrotate'
---@param x integer
---@param distp integer
---@return integer
+---@nodiscard
function bit32.lrotate(x, distp) end
---#DES 'bit32.lshift'
---@param x integer
---@param distp integer
---@return integer
+---@nodiscard
function bit32.lshift(x, distp) end
---#DES 'bit32.rrotate'
---@param x integer
---@param distp integer
---@return integer
+---@nodiscard
function bit32.rrotate(x, distp) end
---#DES 'bit32.rshift'
---@param x integer
---@param distp integer
---@return integer
+---@nodiscard
function bit32.rshift(x, distp) end
return bit32
diff --git a/meta/template/coroutine.lua b/meta/template/coroutine.lua
index 804c84c6..0b07bf5c 100644
--- a/meta/template/coroutine.lua
+++ b/meta/template/coroutine.lua
@@ -5,18 +5,21 @@
coroutine = {}
---#DES 'coroutine.create'
----@param f function
+---@param f async fun()
---@return thread
+---@nodiscard
function coroutine.create(f) end
---#if VERSION >= 5.4 then
---#DES 'coroutine.isyieldable>5.4'
---@param co? thread
---@return boolean
+---@nodiscard
function coroutine.isyieldable(co) end
---#else
---#DES 'coroutine.isyieldable'
---@return boolean
+---@nodiscard
function coroutine.isyieldable() end
---#end
@@ -38,6 +41,7 @@ function coroutine.resume(co, val1, ...) end
---#DES 'coroutine.running'
---@return thread running
---@return boolean ismain
+---@nodiscard
function coroutine.running() end
---#DES 'coroutine.status'
@@ -47,14 +51,17 @@ function coroutine.running() end
---| '"suspended"' # ---#DESTAIL 'costatus.suspended'
---| '"normal"' # ---#DESTAIL 'costatus.normal'
---| '"dead"' # ---#DESTAIL 'costatus.dead'
+---@nodiscard
function coroutine.status(co) end
---#DES 'coroutine.wrap'
----@param f function
----@return fun(...):...
+---@param f async fun()
+---@return fun()
+---@nodiscard
function coroutine.wrap(f) end
---#DES 'coroutine.yield'
+---@async
---@return ...
function coroutine.yield(...) end
diff --git a/meta/template/debug.lua b/meta/template/debug.lua
index 2c72263f..c8b506f5 100644
--- a/meta/template/debug.lua
+++ b/meta/template/debug.lua
@@ -33,6 +33,7 @@ function debug.debug() end
---#DES 'debug.getfenv'
---@param o any
---@return table
+---@nodiscard
function debug.getfenv(o) end
---#DES 'debug.gethook'
@@ -40,6 +41,7 @@ function debug.getfenv(o) end
---@return function hook
---@return string mask
---@return integer count
+---@nodiscard
function debug.gethook(co) end
---@alias infowhat string
@@ -61,9 +63,10 @@ function debug.gethook(co) end
---#DES 'debug.getinfo'
---@overload fun(f: integer|function, what?: infowhat):debuginfo
---@param thread thread
----@param f integer|function
+---@param f integer|async fun()
---@param what? infowhat
---@return debuginfo
+---@nodiscard
function debug.getinfo(thread, f, what) end
---#if VERSION <= 5.1 and not JIT then
@@ -74,32 +77,37 @@ function debug.getinfo(thread, f, what) end
---@param index integer
---@return string name
---@return any value
+---@nodiscard
function debug.getlocal(thread, level, index) end
---#else
---#DES 'debug.getlocal>5.2'
----@overload fun(f: integer|function, index: integer):string, any
+---@overload fun(f: integer|async fun(), index: integer):string, any
---@param thread thread
----@param f integer|function
+---@param f integer|async fun()
---@param index integer
---@return string name
---@return any value
+---@nodiscard
function debug.getlocal(thread, f, index) end
---#end
---#DES 'debug.getmetatable'
---@param object any
---@return table metatable
+---@nodiscard
function debug.getmetatable(object) end
---#DES 'debug.getregistry'
---@return table
+---@nodiscard
function debug.getregistry() end
---#DES 'debug.getupvalue'
----@param f function
+---@param f async fun()
---@param up integer
---@return string name
---@return any value
+---@nodiscard
function debug.getupvalue(f, up) end
---#if VERSION >= 5.4 then
@@ -108,11 +116,13 @@ function debug.getupvalue(f, up) end
---@param n integer
---@return any
---@return boolean
+---@nodiscard
function debug.getuservalue(u, n) end
---#elseif VERSION >= 5.2 or JIT then
---#DES 'debug.getuservalue<5.3'
---@param u userdata
---@return any
+---@nodiscard
function debug.getuservalue(u) end
---#end
@@ -138,7 +148,7 @@ function debug.setfenv(object, env) end
---#DES 'debug.sethook'
---@overload fun(hook: function, mask: hookmask, count?: integer)
---@param thread thread
----@param hook function
+---@param hook async fun()
---@param mask hookmask
---@param count? integer
function debug.sethook(thread, hook, mask, count) end
@@ -160,7 +170,7 @@ function debug.setlocal(thread, level, index, value) end
function debug.setmetatable(value, meta) end
---#DES 'debug.setupvalue'
----@param f function
+---@param f async fun()
---@param up integer
---@param value any
---@return string name
@@ -187,20 +197,22 @@ function debug.setuservalue(udata, value) end
---@param message? any
---@param level? integer
---@return string message
+---@nodiscard
function debug.traceback(thread, message, level) end
---@version >5.2, JIT
---#DES 'debug.upvalueid'
----@param f function
+---@param f async fun()
---@param n integer
---@return lightuserdata id
+---@nodiscard
function debug.upvalueid(f, n) end
---@version >5.2, JIT
---#DES 'debug.upvaluejoin'
----@param f1 function
+---@param f1 async fun()
---@param n1 integer
----@param f2 function
+---@param f2 async fun()
---@param n2 integer
function debug.upvaluejoin(f1, n1, f2, n2) end
diff --git a/meta/template/ffi.lua b/meta/template/ffi.lua
index 97dd4bc2..833232d4 100644
--- a/meta/template/ffi.lua
+++ b/meta/template/ffi.lua
@@ -26,21 +26,24 @@ function ffi.cdef(def) end
---@param name string
---@param global? boolean
---@return ffi.namespace* clib
+---@nodiscard
function ffi.load(name, global) end
---@param ct ffi.ct*
---@param nelem? integer
---@param init? any
---@return ffi.cdata* cdata
+---@nodiscard
function ffi.new(ct, nelem, init, ...) end
---@param nelem? integer
---@param init? any
---@return ffi.cdata* cdata
-function ctype(nelem, init, ...) end
+function ffi.ctype(nelem, init, ...) end
---@param ct ffi.ct*
---@return ffi.ctype* ctype
+---@nodiscard
function ffi.typeof(ct) end
---@param ct ffi.ct*
@@ -61,10 +64,12 @@ function ffi.gc(cdata, finalizer) end
---@param ct ffi.ct*
---@param nelem? integer
---@return integer|nil size
+---@nodiscard
function ffi.sizeof(ct, nelem) end
---@param ct ffi.ct*
---@return integer align
+---@nodiscard
function ffi.alignof(ct) end
---@param ct ffi.ct*
@@ -72,15 +77,18 @@ function ffi.alignof(ct) end
---@return integer ofs
---@return integer? bpos
---@return integer? bsize
+---@nodiscard
function ffi.offsetof(ct, field) end
---@param ct ffi.ct*
---@param obj any
---@return boolean status
+---@nodiscard
function ffi.istype(ct, obj) end
---@param newerr? integer
---@return integer err
+---@nodiscard
function ffi.errno(newerr) end
---@param ptr any
diff --git a/meta/template/io.lua b/meta/template/io.lua
index d31027af..b2846878 100644
--- a/meta/template/io.lua
+++ b/meta/template/io.lua
@@ -41,7 +41,7 @@ function io.input(file) end
---#DES 'io.lines'
---@param filename string?
----@vararg readmode
+---@param ... readmode
---@return fun():string|number
function io.lines(filename, ...) end
@@ -50,6 +50,7 @@ function io.lines(filename, ...) end
---@param mode openmode
---@return file*?
---@return string? errmsg
+---@nodiscard
function io.open(filename, mode) end
---#DES 'io.output'
@@ -69,13 +70,15 @@ function io.output(file) end
function io.popen(prog, mode) end
---#DES 'io.read'
----@vararg readmode
+---@param ... readmode
---@return string|number
---@return ...
+---@nodiscard
function io.read(...) end
---#DES 'io.tmpfile'
---@return file*
+---@nodiscard
function io.tmpfile() end
---@alias filetype
@@ -86,6 +89,7 @@ function io.tmpfile() end
---#DES 'io.type'
---@param file file*
---@return filetype
+---@nodiscard
function io.type(file) end
---#DES 'io.write'
@@ -124,13 +128,14 @@ function file:close() end
function file:flush() end
---#DES 'file:lines'
----@vararg readmode
+---@param ... readmode
---@return fun():string|number
function file:lines(...) end
---#DES 'file:read'
----@vararg readmode
+---@param ... readmode
---@return string|number
+---@nodiscard
function file:read(...) end
---@alias seekwhence
@@ -156,7 +161,7 @@ function file:seek(whence, offset) end
function file:setvbuf(mode, size) end
---#DES 'file:write'
----@vararg string|number
+---@param ... string|number
---@return file*?
---@return string? errmsg
function file:write(...) end
diff --git a/meta/template/jit.lua b/meta/template/jit.lua
index f5571cb7..6397505e 100644
--- a/meta/template/jit.lua
+++ b/meta/template/jit.lua
@@ -27,6 +27,7 @@ function jit.flush(func, recursive) end
---@return boolean status
---@return ...
+---@nodiscard
function jit.status() end
return jit
diff --git a/meta/template/math.lua b/meta/template/math.lua
index e415bae6..09c75cc6 100644
--- a/meta/template/math.lua
+++ b/meta/template/math.lua
@@ -17,28 +17,33 @@ math = {}
---#DES 'math.abs'
---@param x number
---@return number
+---@nodiscard
function math.abs(x) end
---#DES 'math.acos'
---@param x number
---@return number
+---@nodiscard
function math.acos(x) end
---#DES 'math.asin'
---@param x number
---@return number
+---@nodiscard
function math.asin(x) end
---#if VERSION <= 5.2 then
---#DES 'math.atan<5.2'
---@param y number
---@return number
+---@nodiscard
function math.atan(y) end
---#else
---#DES 'math.atan>5.3'
---@param y number
---@param x? number
---@return number
+---@nodiscard
function math.atan(y, x) end
---#end
@@ -47,42 +52,50 @@ function math.atan(y, x) end
---@param y number
---@param x number
---@return number
+---@nodiscard
function math.atan2(y, x) end
---#DES 'math.ceil'
---@param x number
---@return integer
+---@nodiscard
function math.ceil(x) end
---#DES 'math.cos'
---@param x number
+---@nodiscard
function math.cos(x) end
---@version <5.2
---#DES 'math.cosh'
---@param x number
---@return number
+---@nodiscard
function math.cosh(x) end
---#DES 'math.deg'
---@param x number
---@return number
+---@nodiscard
function math.deg(x) end
---#DES 'math.exp'
---@param x number
---@return number
+---@nodiscard
function math.exp(x) end
---#DES 'math.floor'
---@param x number
---@return number
+---@nodiscard
function math.floor(x) end
---#DES 'math.fmod'
---@param x number
---@param y number
---@return number
+---@nodiscard
function math.fmod(x, y) end
---@version <5.2
@@ -90,6 +103,7 @@ function math.fmod(x, y) end
---@param x number
---@return number m
---@return number e
+---@nodiscard
function math.frexp(x) end
---@version <5.2
@@ -97,18 +111,21 @@ function math.frexp(x) end
---@param m number
---@param e number
---@return number
+---@nodiscard
function math.ldexp(m, e) end
---#if VERSION <= 5.1 and not JIT then
---#DES 'math.log<5.1'
---@param x number
---@return number
+---@nodiscard
function math.log(x) end
---#else
---#DES 'math.log>5.2'
---@param x number
---@param base? integer
---@return number
+---@nodiscard
function math.log(x, base) end
---#end
@@ -116,24 +133,28 @@ function math.log(x, base) end
---#DES 'math.log10'
---@param x number
---@return number
+---@nodiscard
function math.log10(x) end
---#DES 'math.max'
---@param x number
----@vararg number
+---@param ... number
---@return number
+---@nodiscard
function math.max(x, ...) end
---#DES 'math.min'
---@param x number
----@vararg number
+---@param ... number
---@return number
+---@nodiscard
function math.min(x, ...) end
---#DES 'math.modf'
---@param x number
---@return integer
---@return number
+---@nodiscard
function math.modf(x) end
---@version <5.2
@@ -141,11 +162,13 @@ function math.modf(x) end
---@param x number
---@param y number
---@return number
+---@nodiscard
function math.pow(x, y) end
---#DES 'math.rad'
---@param x number
---@return number
+---@nodiscard
function math.rad(x) end
---#DES 'math.random'
@@ -154,50 +177,59 @@ function math.rad(x) end
---@param m integer
---@param n integer
---@return integer
+---@nodiscard
function math.random(m, n) end
---#if VERSION >= 5.4 then
---#DES 'math.randomseed>5.4'
---@param x? integer
---@param y? integer
+---@nodiscard
function math.randomseed(x, y) end
---#else
---#DES 'math.randomseed<5.3'
---@param x integer
+---@nodiscard
function math.randomseed(x) end
---#end
---#DES 'math.sin'
---@param x number
---@return number
+---@nodiscard
function math.sin(x) end
---@version <5.2
---#DES 'math.sinh'
---@param x number
---@return number
+---@nodiscard
function math.sinh(x) end
---#DES 'math.sqrt'
---@param x number
---@return number
+---@nodiscard
function math.sqrt(x) end
---#DES 'math.tan'
---@param x number
---@return number
+---@nodiscard
function math.tan(x) end
---@version <5.2
---#DES 'math.tanh'
---@param x number
---@return number
+---@nodiscard
function math.tanh(x) end
---@version >5.3
---#DES 'math.tointeger'
---@param x number
---@return integer?
+---@nodiscard
function math.tointeger(x) end
---#DES 'math.type'
@@ -206,12 +238,14 @@ function math.tointeger(x) end
---| '"integer"'
---| '"float"'
---| 'nil'
+---@nodiscard
function math.type(x) end
---#DES 'math.ult'
---@param m integer
---@param n integer
---@return boolean
+---@nodiscard
function math.ult(m, n) end
return math
diff --git a/meta/template/os.lua b/meta/template/os.lua
index 4347076c..af9b3278 100644
--- a/meta/template/os.lua
+++ b/meta/template/os.lua
@@ -6,6 +6,7 @@ os = {}
---#DES 'os.clock'
---@return number
+---@nodiscard
function os.clock() end
---@class osdate
@@ -32,12 +33,14 @@ function os.clock() end
---@param format? string
---@param time? integer
---@return string|osdate
+---@nodiscard
function os.date(format, time) end
---#DES 'os.difftime'
---@param t2 integer
---@param t1 integer
---@return integer
+---@nodiscard
function os.difftime(t2, t1) end
---#DES 'os.execute'
@@ -67,6 +70,7 @@ function os.exit(code, close) end
---#DES 'os.getenv'
---@param varname string
---@return string
+---@nodiscard
function os.getenv(varname) end
---#DES 'os.remove'
@@ -99,10 +103,12 @@ function os.setlocale(locale, category) end
---#DES 'os.time'
---@param date? osdate
---@return integer
+---@nodiscard
function os.time(date) end
---#DES 'os.tmpname'
---@return string
+---@nodiscard
function os.tmpname() end
return os
diff --git a/meta/template/package.lua b/meta/template/package.lua
index 0b2c8c1b..5c08bbef 100644
--- a/meta/template/package.lua
+++ b/meta/template/package.lua
@@ -55,6 +55,7 @@ package.searchers = {}
---@param rep? string
---@return string? filename
---@return string? errmsg
+---@nodiscard
function package.searchpath(name, path, sep, rep) end
---#DES 'package.seeall'
diff --git a/meta/template/string.lua b/meta/template/string.lua
index c06570e8..d3b4c431 100644
--- a/meta/template/string.lua
+++ b/meta/template/string.lua
@@ -10,19 +10,22 @@ string = {}
---@param j? integer
---@return integer
---@return ...
+---@nodiscard
function string.byte(s, i, j) end
---#DES 'string.char'
---@param byte integer
----@vararg integer
+---@param ... integer
---@return string
---@return ...
+---@nodiscard
function string.char(byte, ...) end
---#DES 'string.dump'
----@param f function
+---@param f async fun()
---@param strip? boolean
---@return string
+---@nodiscard
function string.dump(f, strip) end
---#DES 'string.find'
@@ -33,12 +36,14 @@ function string.dump(f, strip) end
---@return integer start
---@return integer end
---@return ... captured
+---@nodiscard
function string.find(s, pattern, init, plain) end
---#DES 'string.format'
---@param s string
----@vararg string
+---@param ... string
---@return string
+---@nodiscard
function string.format(s, ...) end
---#DES 'string.gmatch'
@@ -62,16 +67,19 @@ function string.gmatch(s, pattern, init) end
---@param n integer
---@return string
---@return integer count
+---@nodiscard
function string.gsub(s, pattern, repl, n) end
---#DES 'string.len'
---@param s string
---@return integer
+---@nodiscard
function string.len(s) end
---#DES 'string.lower'
---@param s string
---@return string
+---@nodiscard
function string.lower(s) end
---#DES 'string.match'
@@ -79,6 +87,7 @@ function string.lower(s) end
---@param pattern string
---@param init? integer
---@return string | number captured
+---@nodiscard
function string.match(s, pattern, init) end
---@version >5.3
@@ -86,14 +95,16 @@ function string.match(s, pattern, init) end
---@param fmt string
---@param v1 string
---@param v2? string
----@vararg string
+---@param ... string
---@return string binary
+---@nodiscard
function string.pack(fmt, v1, v2, ...) end
---@version >5.3
---#DES 'string.packsize'
---@param fmt string
---@return integer
+---@nodiscard
function string.packsize(fmt) end
---#if VERSION <= 5.1 and not JIT then
@@ -101,6 +112,7 @@ function string.packsize(fmt) end
---@param s string
---@param n integer
---@return string
+---@nodiscard
function string.rep(s, n) end
---#else
---#DES 'string.rep>5.2'
@@ -108,12 +120,14 @@ function string.rep(s, n) end
---@param n integer
---@param sep? string
---@return string
+---@nodiscard
function string.rep(s, n, sep) end
---#end
---#DES 'string.reverse'
---@param s string
---@return string
+---@nodiscard
function string.reverse(s) end
---#DES 'string.sub'
@@ -121,6 +135,7 @@ function string.reverse(s) end
---@param i integer
---@param j? integer
---@return string
+---@nodiscard
function string.sub(s, i, j) end
---@version >5.3
@@ -130,11 +145,13 @@ function string.sub(s, i, j) end
---@param pos? integer
---@return ...
---@return integer offset
+---@nodiscard
function string.unpack(fmt, s, pos) end
---#DES 'string.upper'
---@param s string
---@return string
+---@nodiscard
function string.upper(s) end
return string
diff --git a/meta/template/table.lua b/meta/template/table.lua
index 12d69c43..c55c3160 100644
--- a/meta/template/table.lua
+++ b/meta/template/table.lua
@@ -10,6 +10,7 @@ table = {}
---@param i? integer
---@param j? integer
---@return string
+---@nodiscard
function table.concat(list, sep, i, j) end
---#DES 'table.insert'
@@ -23,6 +24,7 @@ function table.insert(list, pos, value) end
---#DES 'table.maxn'
---@param table table
---@return integer
+---@nodiscard
function table.maxn(table) end
---@version >5.3
@@ -38,6 +40,7 @@ function table.move(a1, f, e, t, a2) end
---@version >5.2, JIT
---#DES 'table.pack'
---@return table
+---@nodiscard
function table.pack(...) end
---#DES 'table.remove'
@@ -56,6 +59,7 @@ function table.sort(list, comp) end
---@param list table
---@param i? integer
---@param j? integer
+---@nodiscard
function table.unpack(list, i, j) end
return table
diff --git a/meta/template/utf8.lua b/meta/template/utf8.lua
index 43ce9961..bd474710 100644
--- a/meta/template/utf8.lua
+++ b/meta/template/utf8.lua
@@ -10,8 +10,9 @@ utf8 = {}
---#DES 'utf8.char'
---@param code integer
----@vararg integer
+---@param ... integer
---@return string
+---@nodiscard
function utf8.char(code, ...) end
---#DES 'utf8.codes'
@@ -33,6 +34,7 @@ function utf8.codes(s, lax) end
---@param j? integer
---@return integer code
---@return ...
+---@nodiscard
function utf8.codepoint(s, i, j) end
---#else
---@param s string
@@ -41,6 +43,7 @@ function utf8.codepoint(s, i, j) end
---@param lax? boolean
---@return integer code
---@return ...
+---@nodiscard
function utf8.codepoint(s, i, j, lax) end
---#end
@@ -51,6 +54,7 @@ function utf8.codepoint(s, i, j, lax) end
---@param j? integer
---@return integer?
---@return integer? errpos
+---@nodiscard
function utf8.len(s, i, j) end
---#else
---@param s string
@@ -59,6 +63,7 @@ function utf8.len(s, i, j) end
---@param lax? boolean
---@return integer?
---@return integer? errpos
+---@nodiscard
function utf8.len(s, i, j, lax) end
---#end
@@ -67,6 +72,7 @@ function utf8.len(s, i, j, lax) end
---@param n integer
---@param i integer
---@return integer p
+---@nodiscard
function utf8.offset(s, n, i) end
return utf8
diff --git a/script/await.lua b/script/await.lua
index e92af272..ff840956 100644
--- a/script/await.lua
+++ b/script/await.lua
@@ -25,7 +25,7 @@ local function setID(id, co, callback)
end
--- 设置错误处理器
----@param errHandle function {comment = '当有错误发生时,会以错误堆栈为参数调用该函数'}
+---@param errHandle function # 当有错误发生时,会以错误堆栈为参数调用该函数
function m.setErrorHandle(errHandle)
m.errorHandle = errHandle
end
@@ -39,6 +39,7 @@ function m.checkResult(co, ...)
end
--- 创建一个任务
+---@param callback async fun()
function m.call(callback, ...)
local co = coroutine.create(callback)
local closers = {}
@@ -66,6 +67,7 @@ function m.call(callback, ...)
end
--- 创建一个任务,并挂起当前线程,当任务完成后再延续当前线程/若任务被关闭,则返回nil
+---@async
function m.await(callback, ...)
if not coroutine.isyieldable() then
return callback(...)
@@ -109,6 +111,7 @@ end
--- 休眠一段时间
---@param time number
+---@async
function m.sleep(time)
if not coroutine.isyieldable() then
if m.errorHandle then
@@ -128,6 +131,7 @@ end
--- 等待直到唤醒
---@param callback function
+---@async
function m.wait(callback, ...)
if not coroutine.isyieldable() then
return
@@ -148,6 +152,7 @@ function m.wait(callback, ...)
end
--- 延迟
+---@async
function m.delay()
if not m._enable then
return
@@ -174,6 +179,7 @@ function m.delay()
end
--- stop then close
+---@async
function m.stop()
if not coroutine.isyieldable() then
return
@@ -239,6 +245,7 @@ function m.disable()
end
--- 注册事件
+---@param callback async fun(ev: string, ...)
function m.watch(callback)
m.watchList[#m.watchList+1] = callback
end
diff --git a/script/client.lua b/script/client.lua
index 93ac38b3..4d39cd0d 100644
--- a/script/client.lua
+++ b/script/client.lua
@@ -59,6 +59,23 @@ function m.getAbility(name)
return current
end
+function m.getOffsetEncoding()
+ if m._offsetEncoding then
+ return m._offsetEncoding
+ end
+ local clientEncodings = m.getAbility 'offsetEncoding'
+ if type(clientEncodings) == 'table' then
+ for _, encoding in ipairs(clientEncodings) do
+ if encoding == 'utf-8' then
+ m._offsetEncoding = 'utf-8'
+ return m._offsetEncoding
+ end
+ end
+ end
+ m._offsetEncoding = 'utf-16'
+ return m._offsetEncoding
+end
+
local function packMessage(...)
local strs = table.pack(...)
for i = 1, strs.n do
@@ -88,6 +105,7 @@ end
---@param titles string[]
---@return string action
---@return integer index
+---@async
function m.awaitRequestMessage(type, message, titles)
proto.notify('window/logMessage', {
type = define.MessageType[type] or 3,
@@ -254,6 +272,7 @@ function m.init(t)
m.client(t.clientInfo.name)
nonil.disable()
lang(LOCALE or t.locale)
+ converter.setOffsetEncoding(m.getOffsetEncoding())
hookPrint()
end
diff --git a/script/config/config.lua b/script/config/config.lua
index a361d68f..0e18428f 100644
--- a/script/config/config.lua
+++ b/script/config/config.lua
@@ -151,6 +151,7 @@ local Template = {
"?.lua",
"?/init.lua",
},
+ ['Lua.runtime.pathStrict'] = Type.Boolean >> false,
['Lua.runtime.special'] = Type.Hash(Type.String, Type.String),
['Lua.runtime.meta'] = Type.String >> '${version} ${language} ${encoding}',
['Lua.runtime.unicodeName'] = Type.Boolean,
@@ -198,6 +199,7 @@ local Template = {
['Lua.hint.paramType'] = Type.Boolean >> true,
['Lua.hint.setType'] = Type.Boolean >> false,
['Lua.hint.paramName'] = Type.String >> 'All',
+ ['Lua.hint.await'] = Type.Boolean >> true,
['Lua.window.statusBar'] = Type.Boolean >> true,
['Lua.window.progressBar'] = Type.Boolean >> true,
['Lua.IntelliSense.traceLocalSet'] = Type.Boolean >> false,
diff --git a/script/config/loader.lua b/script/config/loader.lua
index 03fe9456..e754be49 100644
--- a/script/config/loader.lua
+++ b/script/config/loader.lua
@@ -19,37 +19,43 @@ local m = {}
function m.loadRCConfig(filename)
local path = workspace.getAbsolutePath(filename)
if not path then
- return
+ m.lastRCConfig = nil
+ return nil
end
local buf = util.loadFile(path)
if not buf then
- return
+ m.lastRCConfig = nil
+ return nil
end
local suc, res = pcall(json.decode, buf)
if not suc then
errorMessage(lang.script('CONFIG_LOAD_ERROR', res))
- return
+ return m.lastRCConfig
end
+ m.lastRCConfig = res
return res
end
function m.loadLocalConfig(filename)
local path = workspace.getAbsolutePath(filename)
if not path then
- return
+ m.lastLocalConfig = nil
+ return nil
end
local buf = util.loadFile(path)
if not buf then
errorMessage(lang.script('CONFIG_LOAD_FAILED', path))
- return
+ m.lastLocalConfig = nil
+ return nil
end
local firstChar = buf:match '%S'
if firstChar == '{' then
local suc, res = pcall(json.decode, buf)
if not suc then
errorMessage(lang.script('CONFIG_LOAD_ERROR', res))
- return
+ return m.lastLocalConfig
end
+ m.lastLocalConfig = res
return res
else
local suc, res = pcall(function ()
@@ -57,12 +63,14 @@ function m.loadLocalConfig(filename)
end)
if not suc then
errorMessage(lang.script('CONFIG_LOAD_ERROR', res))
- return
+ return m.lastLocalConfig
end
+ m.lastLocalConfig = res
return res
end
end
+---@async
function m.loadClientConfig()
local configs = proto.awaitRequest('workspace/configuration', {
items = {
diff --git a/script/core/code-action.lua b/script/core/code-action.lua
index 8256107e..ad048c48 100644
--- a/script/core/code-action.lua
+++ b/script/core/code-action.lua
@@ -308,6 +308,44 @@ local function solveTrailingSpace(uri, diag, results)
}
end
+local function solveAwaitInSync(uri, diag, results)
+ local state = files.getState(uri)
+ if not state then
+ return
+ end
+ local start, finish = converter.unpackRange(uri, diag.range)
+ local parentFunction
+ guide.eachSourceType(state.ast, 'function', function (source)
+ if source.start > finish
+ or source.finish < start then
+ return
+ end
+ if not parentFunction or parentFunction.start < source.start then
+ parentFunction = source
+ end
+ end)
+ if not parentFunction then
+ return
+ end
+ local row = guide.rowColOf(parentFunction.start)
+ local pos = guide.positionOf(row, 0)
+ results[#results+1] = {
+ title = lang.script.ACTION_MARK_ASYNC,
+ kind = 'quickfix',
+ edit = {
+ changes = {
+ [uri] = {
+ {
+ start = pos,
+ finish = pos,
+ newText = '---@async\n',
+ }
+ }
+ }
+ },
+ }
+end
+
local function solveDiagnostic(uri, diag, start, results)
if diag.source == lang.script.DIAG_SYNTAX_CHECK then
solveSyntax(uri, diag, results)
@@ -326,6 +364,8 @@ local function solveDiagnostic(uri, diag, start, results)
solveAmbiguity1(uri, diag, results)
elseif diag.code == 'trailing-space' then
solveTrailingSpace(uri, diag, results)
+ elseif diag.code == 'await-in-sync' then
+ solveAwaitInSync(uri, diag, results)
end
disableDiagnostic(uri, diag.code, start, results)
end
diff --git a/script/core/command/autoRequire.lua b/script/core/command/autoRequire.lua
index aa641967..30bd13a1 100644
--- a/script/core/command/autoRequire.lua
+++ b/script/core/command/autoRequire.lua
@@ -63,6 +63,7 @@ local function findInsertRow(uri)
return row or 0, fmt
end
+---@async
local function askAutoRequire(visiblePaths)
local selects = {}
local nameMap = {}
@@ -125,6 +126,7 @@ local function applyAutoRequire(uri, row, name, result, fmt)
})
end
+---@async
return function (data)
local uri = data.uri
local target = data.target
@@ -135,7 +137,7 @@ return function (data)
end
local path = furi.decode(target)
- local visiblePaths = rpath.getVisiblePath(path, config.get 'Lua.runtime.path')
+ local visiblePaths = rpath.getVisiblePath(path)
if not visiblePaths or #visiblePaths == 0 then
return
end
diff --git a/script/core/command/jsonToLua.lua b/script/core/command/jsonToLua.lua
index 6aecee2c..d29ad608 100644
--- a/script/core/command/jsonToLua.lua
+++ b/script/core/command/jsonToLua.lua
@@ -7,6 +7,7 @@ local lang = require 'language'
local converter = require 'proto.converter'
local guide = require 'parser.guide'
+---@async
return function (data)
local state = files.getState(data.uri)
local text = files.getText(data.uri)
diff --git a/script/core/command/removeSpace.lua b/script/core/command/removeSpace.lua
index 3021d4a4..aa565f7f 100644
--- a/script/core/command/removeSpace.lua
+++ b/script/core/command/removeSpace.lua
@@ -12,6 +12,7 @@ local function isInString(ast, offset)
end) or false
end
+---@async
return function (data)
local uri = data.uri
local text = files.getText(uri)
diff --git a/script/core/command/solve.lua b/script/core/command/solve.lua
index f7831f7f..8065aa9d 100644
--- a/script/core/command/solve.lua
+++ b/script/core/command/solve.lua
@@ -27,6 +27,7 @@ local literalMap = {
['table'] = true,
}
+---@async
return function (data)
local uri = data.uri
local text = files.getText(uri)
diff --git a/script/core/completion.lua b/script/core/completion.lua
index cdd01f98..785d3054 100644
--- a/script/core/completion.lua
+++ b/script/core/completion.lua
@@ -20,6 +20,7 @@ local lookBackward = require 'core.look-backward'
local guide = require 'parser.guide'
local infer = require 'core.infer'
local noder = require 'core.noder'
+local await = require 'await'
local DiagnosticModes = {
'disable-next-line',
@@ -30,6 +31,8 @@ local DiagnosticModes = {
local stackID = 0
local stacks = {}
+
+---@param callback async fun()
local function stack(callback)
stackID = stackID + 1
stacks[stackID] = callback
@@ -40,6 +43,7 @@ local function clearStack()
stacks = {}
end
+---@async
local function resolveStack(id)
local callback = stacks[id]
if not callback then
@@ -87,7 +91,8 @@ local function findNearestTableField(state, position)
return source
end
-local function findParent(state, text, position)
+local function findParent(state, position)
+ local text = state.lua
local offset = guide.positionToOffset(state, position)
for i = offset, 1, -1 do
local char = text:sub(i, i)
@@ -124,7 +129,7 @@ local function findParent(state, text, position)
return nil, nil
end
-local function findParentInStringIndex(state, text, position)
+local function findParentInStringIndex(state, position)
local near, nearStart
guide.eachSourceContain(state.ast, position, function (source)
local start = guide.getStartFinish(source)
@@ -202,6 +207,7 @@ local function getSnip(source)
end
end
+---@async
local function buildDesc(source)
if source.type == 'dummy' then
return
@@ -228,7 +234,7 @@ local function buildFunction(results, source, value, oop, data)
title = 'trigger signature',
command = 'editor.action.triggerParameterHints',
}
- snipData.id = stack(function ()
+ snipData.id = stack(function () ---@async
return {
detail = buildDetail(source),
description = buildDesc(source),
@@ -291,7 +297,7 @@ local function checkLocal(state, word, position, results)
match = name,
insertText = name,
kind = define.CompletionItemKind.Function,
- id = stack(function ()
+ id = stack(function () ---@async
return {
detail = buildDetail(source),
description = buildDesc(source),
@@ -304,7 +310,7 @@ local function checkLocal(state, word, position, results)
results[#results+1] = {
label = name,
kind = define.CompletionItemKind.Variable,
- id = stack(function ()
+ id = stack(function () ---@async
return {
detail = buildDetail(source),
description = buildDesc(source),
@@ -369,7 +375,7 @@ local function checkModule(state, word, position, results)
},
},
},
- id = stack(function ()
+ id = stack(function () ---@async
local md = markdown()
md:add('md', lang.script('COMPLETION_IMPORT_FROM', ('[%s](%s)'):format(
workspace.getRelativePath(uri),
@@ -388,19 +394,16 @@ local function checkModule(state, word, position, results)
end
end
-local function checkFieldFromFieldToIndex(name, src, parent, word, startPos, position)
+local function checkFieldFromFieldToIndex(state, name, src, parent, word, startPos, position)
if name:match '^[%a_][%w_]*$' then
return nil
end
local textEdit, additionalTextEdits
- local uri = guide.getUri(parent)
- local text = files.getText(uri)
- local state = files.getState(uri)
local startOffset = guide.positionToOffset(state, startPos)
local offset = guide.positionToOffset(state, position)
local wordStartOffset
if word == '' then
- wordStartOffset = text:match('()%S', startOffset + 1)
+ wordStartOffset = state.lua:match('()%S', startOffset + 1)
if wordStartOffset then
wordStartOffset = wordStartOffset - 1
else
@@ -444,8 +447,8 @@ local function checkFieldFromFieldToIndex(name, src, parent, word, startPos, pos
}
end
else
- if config.get 'Lua.runtime.version' == 'Lua 5.1'
- or config.get 'Lua.runtime.version' == 'LuaJIT' then
+ if config.get 'Lua.runtime.version' == 'lua 5.1'
+ or config.get 'Lua.runtime.version' == 'luaJIT' then
textEdit.newText = '_G' .. textEdit.newText
else
textEdit.newText = '_ENV' .. textEdit.newText
@@ -454,7 +457,7 @@ local function checkFieldFromFieldToIndex(name, src, parent, word, startPos, pos
return textEdit, additionalTextEdits
end
-local function checkFieldThen(name, src, word, startPos, position, parent, oop, results)
+local function checkFieldThen(state, name, src, word, startPos, position, parent, oop, results)
local value = searcher.getObjectValue(src) or src
local kind = define.CompletionItemKind.Field
if value.type == 'function'
@@ -470,7 +473,7 @@ local function checkFieldThen(name, src, word, startPos, position, parent, oop,
match = name:match '^[^(]+',
insertText = name:match '^[^(]+',
deprecated = vm.isDeprecated(src) or nil,
- id = stack(function ()
+ id = stack(function () ---@async
return {
detail = buildDetail(src),
description = buildDesc(src),
@@ -495,7 +498,7 @@ local function checkFieldThen(name, src, word, startPos, position, parent, oop,
newText = name,
}
else
- textEdit, additionalTextEdits = checkFieldFromFieldToIndex(name, src, parent, word, startPos, position)
+ textEdit, additionalTextEdits = checkFieldFromFieldToIndex(state, name, src, parent, word, startPos, position)
end
results[#results+1] = {
label = name,
@@ -503,7 +506,7 @@ local function checkFieldThen(name, src, word, startPos, position, parent, oop,
deprecated = vm.isDeprecated(src) or nil,
textEdit = textEdit,
additionalTextEdits = additionalTextEdits,
- id = stack(function ()
+ id = stack(function () ---@async
return {
detail = buildDetail(src),
description = buildDesc(src),
@@ -512,6 +515,7 @@ local function checkFieldThen(name, src, word, startPos, position, parent, oop,
}
end
+---@async
local function checkFieldOfRefs(refs, state, word, startPos, position, parent, oop, results, locals, isGlobal)
local fields = {}
local funcs = {}
@@ -570,17 +574,20 @@ local function checkFieldOfRefs(refs, state, word, startPos, position, parent, o
end
for name, src in util.sortPairs(fields) do
if src then
- checkFieldThen(name, src, word, startPos, position, parent, oop, results)
+ checkFieldThen(state, name, src, word, startPos, position, parent, oop, results)
+ await.delay()
end
end
end
+---@async
local function checkGlobal(state, word, startPos, position, parent, oop, results)
local locals = guide.getVisibleLocals(state.ast, position)
local globals = vm.getGlobalSets '*'
checkFieldOfRefs(globals, state, word, startPos, position, parent, oop, results, locals, 'global')
end
+---@async
local function checkField(state, word, start, position, parent, oop, results)
if parent.tag == '_ENV' or parent.special == '_G' then
local globals = vm.getGlobalSets '*'
@@ -620,7 +627,8 @@ local function checkTableField(state, word, start, results)
end)
end
-local function checkCommon(myUri, word, text, position, results)
+local function checkCommon(state, word, position, results)
+ local myUri = state.uri
local showWord = config.get 'Lua.completion.showWord'
if showWord == 'Disable' then
return
@@ -688,8 +696,7 @@ local function checkCommon(myUri, word, text, position, results)
end
end
end
- local state = files.getState(myUri)
- for str, offset in text:gmatch '([%a_][%w_]+)()' do
+ for str, offset in state.lua:gmatch '([%a_][%w_]+)()' do
if #results >= 100 then
break
end
@@ -719,7 +726,8 @@ local function isInString(state, position)
end)
end
-local function checkKeyWord(state, text, start, position, word, hasSpace, afterLocal, results)
+local function checkKeyWord(state, start, position, word, hasSpace, afterLocal, results)
+ local text = state.lua
local snipType = config.get 'Lua.completion.keywordSnippet'
local symbol = lookBackward.findSymbol(text, guide.positionToOffset(state, start))
local isExp = symbol == '(' or symbol == ',' or symbol == '='
@@ -871,7 +879,8 @@ local function checkFunctionArgByDocParam(state, word, startPos, results)
end
end
-local function isAfterLocal(state, text, startPos)
+local function isAfterLocal(state, startPos)
+ local text = state.lua
local offset = guide.positionToOffset(state, startPos)
local pos = lookBackward.skipSpace(text, offset)
local word = lookBackward.findWord(text, pos)
@@ -886,7 +895,7 @@ local function collectRequireNames(mode, myUri, literal, source, smark, position
goto CONTINUE
end
local path = workspace.getRelativePath(uri)
- local infos = rpath.getVisiblePath(path, config.get 'Lua.runtime.path')
+ local infos = rpath.getVisiblePath(path)
for _, info in ipairs(infos) do
if matchKey(literal, info.expect) then
if not collect[info.expect] then
@@ -977,7 +986,7 @@ local function collectRequireNames(mode, myUri, literal, source, smark, position
end
end
-local function checkUri(state, text, position, results)
+local function checkUri(state, position, results)
local myUri = guide.getUri(state.ast)
guide.eachSourceContain(state.ast, position, function (source)
if source.type ~= 'string' then
@@ -1005,7 +1014,8 @@ local function checkUri(state, text, position, results)
end)
end
-local function checkLenPlusOne(state, text, position, results)
+local function checkLenPlusOne(state, position, results)
+ local text = state.lua
guide.eachSourceContain(state.ast, position, function (source)
if source.type == 'getindex'
or source.type == 'setindex' then
@@ -1097,7 +1107,7 @@ local function mergeEnums(a, b, source)
end
end
-local function checkTypingEnum(state, text, position, defs, str, results)
+local function checkTypingEnum(state, position, defs, str, results)
local enums = {}
for _, def in ipairs(defs) do
if def.type == 'doc.type.enum'
@@ -1119,7 +1129,7 @@ local function checkTypingEnum(state, text, position, defs, str, results)
end
end
-local function checkEqualEnumLeft(state, text, position, source, results)
+local function checkEqualEnumLeft(state, position, source, results)
if not source then
return
end
@@ -1129,10 +1139,11 @@ local function checkEqualEnumLeft(state, text, position, source, results)
end
end)
local defs = vm.getDefs(source)
- checkTypingEnum(state, text, position, defs, str, results)
+ checkTypingEnum(state, position, defs, str, results)
end
-local function checkEqualEnum(state, text, position, results)
+local function checkEqualEnum(state, position, results)
+ local text = state.lua
local start = lookBackward.findTargetSymbol(text, guide.positionToOffset(state, position), '=')
if not start then
return
@@ -1154,10 +1165,10 @@ local function checkEqualEnum(state, text, position, results)
if source.type == 'call' and not eqOrNeq then
return
end
- checkEqualEnumLeft(state, text, position, source, results)
+ checkEqualEnumLeft(state, position, source, results)
end
-local function checkEqualEnumInString(state, text, position, results)
+local function checkEqualEnumInString(state, position, results)
local source = findNearestSource(state, position)
local parent = source.parent
if parent.type == 'binary' then
@@ -1170,16 +1181,16 @@ local function checkEqualEnumInString(state, text, position, results)
if parent.op.type ~= '==' and parent.op.type ~= '~=' then
return
end
- checkEqualEnumLeft(state, text, position, parent[1], results)
+ checkEqualEnumLeft(state, position, parent[1], results)
end
if parent.type == 'local' then
- checkEqualEnumLeft(state, text, position, parent, results)
+ checkEqualEnumLeft(state, position, parent, results)
end
if parent.type == 'setlocal'
or parent.type == 'setglobal'
or parent.type == 'setfield'
or parent.type == 'setindex' then
- checkEqualEnumLeft(state, text, position, parent.node, results)
+ checkEqualEnumLeft(state, position, parent.node, results)
end
end
@@ -1191,20 +1202,21 @@ local function isFuncArg(state, position)
end)
end
-local function trySpecial(state, text, position, results)
+local function trySpecial(state, position, results)
if isInString(state, position) then
- checkUri(state, text, position, results)
- checkEqualEnumInString(state, text, position, results)
+ checkUri(state, position, results)
+ checkEqualEnumInString(state, position, results)
return
end
-- x[#x+1]
- checkLenPlusOne(state, text, position, results)
+ checkLenPlusOne(state, position, results)
-- type(o) ==
- checkEqualEnum(state, text, position, results)
+ checkEqualEnum(state, position, results)
end
-local function tryIndex(state, text, position, results)
- local parent, oop = findParentInStringIndex(state, text, position)
+---@async
+local function tryIndex(state, position, results)
+ local parent, oop = findParentInStringIndex(state, position)
if not parent then
return
end
@@ -1212,7 +1224,9 @@ local function tryIndex(state, text, position, results)
checkField(state, word, position, position, parent, oop, results)
end
-local function tryWord(state, text, position, triggerCharacter, results)
+---@async
+local function tryWord(state, position, triggerCharacter, results)
+ local text = state.lua
local offset = guide.positionToOffset(state, position)
local finish = lookBackward.skipSpace(text, offset)
local word, start = lookBackward.findWord(text, offset)
@@ -1226,11 +1240,11 @@ local function tryWord(state, text, position, triggerCharacter, results)
if isInString(state, position) then
if not hasSpace then
if #results == 0 then
- checkCommon(state.uri, word, text, position, results)
+ checkCommon(state, word, position, results)
end
end
else
- local parent, oop = findParent(state, text, startPos)
+ local parent, oop = findParent(state, startPos)
if parent then
if not hasSpace then
checkField(state, word, startPos, position, parent, oop, results)
@@ -1239,8 +1253,8 @@ local function tryWord(state, text, position, triggerCharacter, results)
checkProvideLocal(state, word, startPos, results)
checkFunctionArgByDocParam(state, word, startPos, results)
else
- local afterLocal = isAfterLocal(state, text, startPos)
- local stop = checkKeyWord(state, text, startPos, position, word, hasSpace, afterLocal, results)
+ local afterLocal = isAfterLocal(state, startPos)
+ local stop = checkKeyWord(state, startPos, position, word, hasSpace, afterLocal, results)
if stop then
return
end
@@ -1257,12 +1271,14 @@ local function tryWord(state, text, position, triggerCharacter, results)
end
end
if not hasSpace then
- checkCommon(state.uri, word, text, position, results)
+ checkCommon(state, word, position, results)
end
end
end
-local function trySymbol(state, text, position, results)
+---@async
+local function trySymbol(state, position, results)
+ local text = state.lua
local symbol, start = lookBackward.findSymbol(text, guide.positionToOffset(state, position))
if not symbol then
return nil
@@ -1273,7 +1289,7 @@ local function trySymbol(state, text, position, results)
local startPos = guide.offsetToPosition(state, start)
if symbol == '.'
or symbol == ':' then
- local parent, oop = findParent(state, text, startPos)
+ local parent, oop = findParent(state, startPos)
if parent then
tracy.ZoneBeginN 'completion.trySymbol'
checkField(state, '', startPos, position, parent, oop, results)
@@ -1411,7 +1427,7 @@ local function getCallEnumsAndFuncs(source, index, oop, call)
end
end
-local function findCall(state, text, position)
+local function findCall(state, position)
local call
guide.eachSourceContain(state.ast, position, function (src)
if src.type == 'call' then
@@ -1423,7 +1439,7 @@ local function findCall(state, text, position)
return call
end
-local function getCallArgInfo(call, text, position)
+local function getCallArgInfo(call, position)
if not call.args then
return 1, nil, nil
end
@@ -1448,7 +1464,8 @@ local function getFuncParamByCallIndex(func, index)
return func.args[index]
end
-local function checkTableLiteralField(state, text, position, tbl, fields, results)
+local function checkTableLiteralField(state, position, tbl, fields, results)
+ local text = state.lua
local mark = {}
for _, field in ipairs(tbl) do
if field.type == 'tablefield'
@@ -1480,7 +1497,7 @@ local function checkTableLiteralField(state, text, position, tbl, fields, result
label = guide.getKeyName(field),
kind = define.CompletionItemKind.Property,
insertText = ('%s = $0'):format(guide.getKeyName(field)),
- id = stack(function ()
+ id = stack(function () ---@async
return {
detail = buildDetail(field),
description = buildDesc(field),
@@ -1492,7 +1509,7 @@ local function checkTableLiteralField(state, text, position, tbl, fields, result
end
end
-local function checkTableLiteralFieldByCall(state, text, position, call, defs, index, results)
+local function checkTableLiteralFieldByCall(state, position, call, defs, index, results)
local source = findNearestTableField(state, position)
if not source then
return
@@ -1526,16 +1543,16 @@ local function checkTableLiteralFieldByCall(state, text, position, call, defs, i
end
::CONTINUE::
end
- checkTableLiteralField(state, text, position, tbl, fields, results)
+ checkTableLiteralField(state, position, tbl, fields, results)
end
-local function tryCallArg(state, text, position, results)
- local call = findCall(state, text, position)
+local function tryCallArg(state, position, results)
+ local call = findCall(state, position)
if not call then
return
end
local myResults = {}
- local argIndex, arg, oop = getCallArgInfo(call, text, position)
+ local argIndex, arg, oop = getCallArgInfo(call, position)
if arg and arg.type == 'function' then
return
end
@@ -1550,10 +1567,10 @@ local function tryCallArg(state, text, position, results)
for _, enum in ipairs(myResults) do
results[#results+1] = enum
end
- checkTableLiteralFieldByCall(state, text, position, call, defs, argIndex, results)
+ checkTableLiteralFieldByCall(state, position, call, defs, argIndex, results)
end
-local function tryTable(state, text, position, results)
+local function tryTable(state, position, results)
local source = findNearestTableField(state, position)
if not source then
return
@@ -1577,7 +1594,7 @@ local function tryTable(state, text, position, results)
fields[#fields+1] = field
end
end
- checkTableLiteralField(state, text, position, tbl, fields, results)
+ checkTableLiteralField(state, position, tbl, fields, results)
end
local function getComment(state, position)
@@ -1589,7 +1606,7 @@ local function getComment(state, position)
return nil
end
-local function getLuaDoc(state, position)
+local function getluaDoc(state, position)
for _, doc in ipairs(state.ast.docs) do
if position >= doc.start and position <= doc.range then
return doc
@@ -1598,7 +1615,7 @@ local function getLuaDoc(state, position)
return nil
end
-local function tryLuaDocCate(word, results)
+local function tryluaDocCate(word, results)
for _, docType in ipairs {
'class',
'type',
@@ -1615,6 +1632,8 @@ local function tryLuaDocCate(word, results)
'see',
'diagnostic',
'module',
+ 'async',
+ 'nodiscard',
} do
if matchKey(word, docType) then
results[#results+1] = {
@@ -1625,7 +1644,7 @@ local function tryLuaDocCate(word, results)
end
end
-local function getLuaDocByContain(state, position)
+local function getluaDocByContain(state, position)
local result
local range = math.huge
guide.eachSourceContain(state.ast.docs, position, function (src)
@@ -1641,12 +1660,12 @@ local function getLuaDocByContain(state, position)
return result
end
-local function getLuaDocByErr(state, text, start, position)
+local function getluaDocByErr(state, start, position)
local targetError
for _, err in ipairs(state.errs) do
if err.finish <= position
and err.start >= start then
- if not text:sub(err.finish + 1, position):find '%S' then
+ if not state.lua:sub(err.finish + 1, position):find '%S' then
targetError = err
break
end
@@ -1666,7 +1685,7 @@ local function getLuaDocByErr(state, text, start, position)
return targetError, targetDoc
end
-local function tryLuaDocBySource(state, position, source, results)
+local function tryluaDocBySource(state, position, source, results)
if source.type == 'doc.extends.name' then
if source.parent.type == 'doc.class' then
for _, doc in ipairs(vm.getDocDefines '*') do
@@ -1761,7 +1780,7 @@ local function tryLuaDocBySource(state, position, source, results)
return false
end
-local function tryLuaDocByErr(state, position, err, docState, results)
+local function tryluaDocByErr(state, position, err, docState, results)
if err.type == 'LUADOC_MISS_CLASS_EXTENDS_NAME' then
for _, doc in ipairs(vm.getDocDefines '*') do
if doc.type == 'doc.class.name'
@@ -1840,7 +1859,7 @@ local function tryLuaDocByErr(state, position, err, docState, results)
end
end
-local function buildLuaDocOfFunction(func)
+local function buildluaDocOfFunction(func)
local index = 1
local buf = {}
buf[#buf+1] = '${1:comment}'
@@ -1882,7 +1901,7 @@ local function buildLuaDocOfFunction(func)
return insertText
end
-local function tryLuaDocOfFunction(doc, results)
+local function tryluaDocOfFunction(doc, results)
if not doc.bindSources then
return
end
@@ -1902,7 +1921,7 @@ local function tryLuaDocOfFunction(doc, results)
return
end
end
- local insertText = buildLuaDocOfFunction(func)
+ local insertText = buildluaDocOfFunction(func)
results[#results+1] = {
label = '@param;@return',
kind = define.CompletionItemKind.Snippet,
@@ -1912,8 +1931,8 @@ local function tryLuaDocOfFunction(doc, results)
}
end
-local function tryLuaDoc(state, text, position, results)
- local doc = getLuaDoc(state, position)
+local function tryluaDoc(state, position, results)
+ local doc = getluaDoc(state, position)
if not doc then
return
end
@@ -1921,38 +1940,38 @@ local function tryLuaDoc(state, text, position, results)
local line = doc.originalComment.text
-- 尝试 ---$
if line == '-' then
- tryLuaDocOfFunction(doc, results)
+ tryluaDocOfFunction(doc, results)
return
end
-- 尝试 ---@$
local cate = line:match('^-+%s*@(%a*)$')
if cate then
- tryLuaDocCate(cate, results)
+ tryluaDocCate(cate, results)
return
end
end
-- 根据输入中的source来补全
- local source = getLuaDocByContain(state, position)
+ local source = getluaDocByContain(state, position)
if source then
- local suc = tryLuaDocBySource(state, position, source, results)
+ local suc = tryluaDocBySource(state, position, source, results)
if suc then
return
end
end
-- 根据附近的错误消息来补全
- local err, expectDoc = getLuaDocByErr(state, text, doc.start, position)
+ local err, expectDoc = getluaDocByErr(state, doc.start, position)
if err then
- tryLuaDocByErr(state, position, err, expectDoc, results)
+ tryluaDocByErr(state, position, err, expectDoc, results)
return
end
end
-local function tryComment(state, text, position, results)
+local function tryComment(state, position, results)
if #results > 0 then
return
end
- local word = lookBackward.findWord(text, guide.positionToOffset(state, position))
- local doc = getLuaDoc(state, position)
+ local word = lookBackward.findWord(state.lua, guide.positionToOffset(state, position))
+ local doc = getluaDoc(state, position)
if not word then
local comment = getComment(state, position)
if comment.type == 'comment.short'
@@ -1973,7 +1992,7 @@ local function tryComment(state, text, position, results)
if doc and doc.type ~= 'doc.comment' then
return
end
- checkCommon(state.uri, word, text, position, results)
+ checkCommon(state, word, position, results)
end
local function makeCache(uri, position, results)
@@ -2043,7 +2062,7 @@ local function getCache(uri, position)
end
if results.enableCommon then
- checkCommon(uri, word, text, position, results)
+ checkCommon(state, word, position, results)
end
return cache.results
@@ -2054,6 +2073,7 @@ local function clearCache()
cache.results = nil
end
+---@async
local function completion(uri, position, triggerCharacter)
tracy.ZoneBeginN 'completion cache'
local results = getCache(uri, position)
@@ -2061,29 +2081,30 @@ local function completion(uri, position, triggerCharacter)
if results then
return results
end
+ await.delay()
tracy.ZoneBeginN 'completion #1'
local state = files.getState(uri)
local text = files.getText(uri)
- results = {}
+ local results = {}
clearStack()
tracy.ZoneEnd()
tracy.ZoneBeginN 'completion #2'
if state then
if getComment(state, position) then
- tryLuaDoc(state, text, position, results)
- tryComment(state, text, position, results)
+ tryluaDoc(state, position, results)
+ tryComment(state, position, results)
else
- trySpecial(state, text, position, results)
- tryCallArg(state, text, position, results)
- tryTable(state, text, position, results)
- tryWord(state, text, position, triggerCharacter, results)
- tryIndex(state, text, position, results)
- trySymbol(state, text, position, results)
+ trySpecial(state, position, results)
+ tryCallArg(state, position, results)
+ tryTable(state, position, results)
+ tryWord(state, position, triggerCharacter, results)
+ tryIndex(state, position, results)
+ trySymbol(state, position, results)
end
else
local word = lookBackward.findWord(text, guide.positionToOffset(state, position))
if word then
- checkCommon(nil, word, text, position, results)
+ checkCommon(nil, word, position, results)
end
end
tracy.ZoneEnd()
@@ -2099,6 +2120,7 @@ local function completion(uri, position, triggerCharacter)
return results
end
+---@async
local function resolve(id)
local item = resolveStack(id)
local cache = workspace.getCache 'completion'
diff --git a/script/core/diagnostics/await-in-sync.lua b/script/core/diagnostics/await-in-sync.lua
new file mode 100644
index 00000000..558a5ff0
--- /dev/null
+++ b/script/core/diagnostics/await-in-sync.lua
@@ -0,0 +1,30 @@
+local files = require 'files'
+local guide = require 'parser.guide'
+local vm = require 'vm'
+local lang = require 'language'
+local await = require 'await'
+
+---@async
+return function (uri, callback)
+ local state = files.getState(uri)
+ if not state then
+ return
+ end
+
+ ---@async
+ guide.eachSourceType(state.ast, 'call', function (source)
+ local currentFunc = guide.getParentFunction(source)
+ if currentFunc and vm.isAsync(currentFunc, false) then
+ return
+ end
+ await.delay()
+ if vm.isAsyncCall(source) then
+ callback {
+ start = source.node.start,
+ finish = source.node.finish,
+ message = lang.script('DIAG_AWAIT_IN_SYNC'),
+ }
+ return
+ end
+ end)
+end
diff --git a/script/core/diagnostics/deprecated.lua b/script/core/diagnostics/deprecated.lua
index 0aeac9e9..e9a1fef7 100644
--- a/script/core/diagnostics/deprecated.lua
+++ b/script/core/diagnostics/deprecated.lua
@@ -8,6 +8,7 @@ local await = require 'await'
local noder = require 'core.noder'
local types = {'getglobal', 'getfield', 'getindex', 'getmethod'}
+---@async
return function (uri, callback)
local ast = files.getState(uri)
if not ast then
@@ -16,7 +17,7 @@ return function (uri, callback)
local cache = {}
- guide.eachSourceTypes(ast.ast, types, function (src)
+ guide.eachSourceTypes(ast.ast, types, function (src) ---@async
if src.type == 'getglobal' then
local key = src[1]
if not key then
diff --git a/script/core/diagnostics/discard-returns.lua b/script/core/diagnostics/discard-returns.lua
new file mode 100644
index 00000000..cef7ece5
--- /dev/null
+++ b/script/core/diagnostics/discard-returns.lua
@@ -0,0 +1,29 @@
+local files = require 'files'
+local guide = require 'parser.guide'
+local vm = require 'vm'
+local await = require 'await'
+local lang = require 'language'
+
+---@async
+return function (uri, callback)
+ local state = files.getState(uri)
+ if not state then
+ return
+ end
+ ---@async
+ guide.eachSourceType(state.ast, 'call', function (source)
+ local parent = source.parent
+ if parent.type ~= 'function'
+ and parent.type ~= 'main' then
+ return
+ end
+ await.delay()
+ if vm.isNoDiscard(source.node, true) then
+ callback {
+ start = source.start,
+ finish = source.finish,
+ message = lang.script('DIAG_DISCARD_RETURNS'),
+ }
+ end
+ end)
+end
diff --git a/script/core/diagnostics/duplicate-doc-class.lua b/script/core/diagnostics/duplicate-doc-class.lua
index 780d15b9..97e2089a 100644
--- a/script/core/diagnostics/duplicate-doc-class.lua
+++ b/script/core/diagnostics/duplicate-doc-class.lua
@@ -16,8 +16,7 @@ return function (uri, callback)
local cache = {}
for _, doc in ipairs(state.ast.docs) do
- if doc.type == 'doc.class'
- or doc.type == 'doc.alias' then
+ if doc.type == 'doc.alias' then
local name = guide.getKeyName(doc)
if not cache[name] then
local docs = vm.getDocDefines(name)
diff --git a/script/core/diagnostics/init.lua b/script/core/diagnostics/init.lua
index 63a1bcf0..4950900b 100644
--- a/script/core/diagnostics/init.lua
+++ b/script/core/diagnostics/init.lua
@@ -64,6 +64,7 @@ local function check(uri, name, results)
end
end
+---@async
return function (uri, response)
local ast = files.getState(uri)
if not ast then
diff --git a/script/core/diagnostics/not-yieldable.lua b/script/core/diagnostics/not-yieldable.lua
new file mode 100644
index 00000000..612b5b98
--- /dev/null
+++ b/script/core/diagnostics/not-yieldable.lua
@@ -0,0 +1,63 @@
+local files = require 'files'
+local await = require 'await'
+local guide = require 'parser.guide'
+local vm = require 'vm'
+local lang = require 'language'
+local infer = require 'core.infer'
+
+local function isYieldAble(defs, i)
+ local hasFuncDef
+ for _, def in ipairs(defs) do
+ if def.type == 'function' then
+ hasFuncDef = true
+ local arg = def.args and def.args[i]
+ if arg then
+ if infer.hasType(arg, 'any')
+ or vm.isAsync(arg, true) then
+ return true
+ end
+ end
+ end
+ if def.type == 'doc.type.function' then
+ hasFuncDef = true
+ local arg = def.args and def.args[i]
+ if arg then
+ if infer.hasType(arg.extends, 'any')
+ or vm.isAsync(arg.extends, true) then
+ return true
+ end
+ end
+ end
+ end
+ return not hasFuncDef
+end
+
+---@async
+return function (uri, callback)
+ local state = files.getState(uri)
+ if not state then
+ return
+ end
+
+ guide.eachSourceType(state.ast, 'call', function (source) ---@async
+ if not source.args then
+ return
+ end
+ await.delay()
+ local defs = vm.getDefs(source.node)
+ if #defs == 0 then
+ return
+ end
+ for i, arg in ipairs(source.args) do
+ if vm.isAsync(arg, true)
+ and not vm.isLinkedCall(source.node, i)
+ and not isYieldAble(defs, i) then
+ callback {
+ start = arg.start,
+ finish = arg.finish,
+ message = lang.script('DIAG_NOT_YIELDABLE', i),
+ }
+ end
+ end
+ end)
+end
diff --git a/script/core/diagnostics/redundant-value.lua b/script/core/diagnostics/redundant-value.lua
index 4c913330..6f60303b 100644
--- a/script/core/diagnostics/redundant-value.lua
+++ b/script/core/diagnostics/redundant-value.lua
@@ -4,13 +4,14 @@ local lang = require 'language'
local guide = require 'parser.guide'
local await = require 'await'
+---@async
return function (uri, callback)
local state = files.getState(uri)
if not state then
return
end
- guide.eachSource(state.ast, function (src)
+ guide.eachSource(state.ast, function (src) ---@async
await.delay()
if src.redundant then
callback {
diff --git a/script/core/diagnostics/type-check.lua b/script/core/diagnostics/type-check.lua
index 11678b38..8728b169 100644
--- a/script/core/diagnostics/type-check.lua
+++ b/script/core/diagnostics/type-check.lua
@@ -23,6 +23,9 @@ local typeNameMap = {
}
local function isTable(name)
+ if type(name) ~= 'string' then
+ return
+ end
if tableMap[name]
---table<K: number, V: string> table
or tableMap[name:sub(1, 5)]
@@ -84,7 +87,8 @@ local function compatibleType(param, args)
if param[1] and param[1]:sub(1,1) == '"' then
return true
end
- elseif isTable(v.type or v[1]) and isTable(param[1] or param.type) then
+ elseif (isTable(v.type) or isTable(v[1]))
+ and (isTable(param[1]) or isTable(param.type)) then
return true
end
end
@@ -114,14 +118,16 @@ end
local function addFatherClass(infers)
for k in pairs(infers) do
- local docDefs = vm.getDocDefines(k)
- for _, doc in ipairs(docDefs) do
- if doc.parent
- and doc.parent.type == 'doc.class'
- and doc.parent.extends then
- for _, tp in ipairs(doc.parent.extends) do
- if tp.type == 'doc.extends.name' then
- infers[tp[1]] = true
+ if type(k) == 'string' then
+ local docDefs = vm.getDocDefines(k)
+ for _, doc in ipairs(docDefs) do
+ if doc.parent
+ and doc.parent.type == 'doc.class'
+ and doc.parent.extends then
+ for _, tp in ipairs(doc.parent.extends) do
+ if tp.type == 'doc.extends.name' then
+ infers[tp[1]] = true
+ end
end
end
end
@@ -238,9 +244,6 @@ local function getInfoFromDefs(defs)
and isClassOralias(v.type) then
plusAlias[#plusAlias+1] = v
end
- if not v[1] or not v.type then
- log.warn('type-check: if not v[1] or not v.type')
- end
end
plusAlias[#plusAlias+1] = types[i]
end
@@ -409,12 +412,13 @@ local function matchParams(paramsTypes, i, arg)
return false, messages
end
+---@async
return function (uri, callback)
local ast = files.getState(uri)
if not ast then
return
end
- guide.eachSourceType(ast.ast, 'call', function (source)
+ guide.eachSourceType(ast.ast, 'call', function (source) ---@async
if not source.args then
return
end
diff --git a/script/core/diagnostics/undefined-doc-param.lua b/script/core/diagnostics/undefined-doc-param.lua
index 6140b4f0..86bf3871 100644
--- a/script/core/diagnostics/undefined-doc-param.lua
+++ b/script/core/diagnostics/undefined-doc-param.lua
@@ -12,6 +12,9 @@ local function hasParamName(func, name)
if arg[1] == name then
return true
end
+ if arg.type == '...' and name == '...' then
+ return true
+ end
end
return false
end
diff --git a/script/core/diagnostics/undefined-field.lua b/script/core/diagnostics/undefined-field.lua
index ff02728f..2e64f0cc 100644
--- a/script/core/diagnostics/undefined-field.lua
+++ b/script/core/diagnostics/undefined-field.lua
@@ -18,6 +18,7 @@ local SkipCheckClass = {
['lightuserdata'] = true,
}
+---@async
return function (uri, callback)
local ast = files.getState(uri)
if not ast then
@@ -26,6 +27,7 @@ return function (uri, callback)
local cache = {}
+ ---@async
local function checkUndefinedField(src)
local id = noder.getID(src)
if not id then
diff --git a/script/core/diagnostics/undefined-global.lua b/script/core/diagnostics/undefined-global.lua
index 14754c16..48c8a226 100644
--- a/script/core/diagnostics/undefined-global.lua
+++ b/script/core/diagnostics/undefined-global.lua
@@ -14,6 +14,7 @@ local requireLike = {
['load'] = true,
}
+---@async
return function (uri, callback)
local ast = files.getState(uri)
if not ast then
@@ -21,7 +22,7 @@ return function (uri, callback)
end
-- 遍历全局变量,检查所有没有 set 模式的全局变量
- guide.eachSourceType(ast.ast, 'getglobal', function (src)
+ guide.eachSourceType(ast.ast, 'getglobal', function (src) ---@async
local key = src[1]
if not key then
return
diff --git a/script/core/diagnostics/unused-function.lua b/script/core/diagnostics/unused-function.lua
index 8f6ccaac..0e0c0003 100644
--- a/script/core/diagnostics/unused-function.lua
+++ b/script/core/diagnostics/unused-function.lua
@@ -18,6 +18,7 @@ local function isToBeClosed(source)
return false
end
+---@async
return function (uri, callback)
local ast = files.getState(uri)
if not ast then
@@ -25,6 +26,7 @@ return function (uri, callback)
end
local cache = {}
+ ---@async
local function checkFunction(source)
if cache[source] ~= nil then
return cache[source]
@@ -81,7 +83,7 @@ return function (uri, callback)
end
-- 只检查局部函数
- guide.eachSourceType(ast.ast, 'function', function (source)
+ guide.eachSourceType(ast.ast, 'function', function (source) ---@async
checkFunction(source)
end)
end
diff --git a/script/core/document-symbol.lua b/script/core/document-symbol.lua
index cfabedab..07794e60 100644
--- a/script/core/document-symbol.lua
+++ b/script/core/document-symbol.lua
@@ -219,6 +219,7 @@ local function buildAnonymousFunction(source, text, used, symbols)
}
end
+---@async
local function buildSource(source, text, used, symbols)
if source.type == 'local'
or source.type == 'setlocal'
@@ -234,6 +235,7 @@ local function buildSource(source, text, used, symbols)
end
end
+---@async
local function makeSymbol(uri)
local ast = files.getState(uri)
local text = files.getText(uri)
@@ -243,7 +245,7 @@ local function makeSymbol(uri)
local symbols = {}
local used = {}
- guide.eachSource(ast.ast, function (source)
+ guide.eachSource(ast.ast, function (source) ---@async
buildSource(source, text, used, symbols)
end)
@@ -279,6 +281,7 @@ local function packChild(symbols)
return root
end
+---@async
local function packSymbols(symbols)
await.delay()
table.sort(symbols, function (a, b)
@@ -291,6 +294,7 @@ local function packSymbols(symbols)
return packChild(symbols)
end
+---@async
return function (uri)
local symbols = makeSymbol(uri)
if not symbols then
diff --git a/script/core/folding.lua b/script/core/folding.lua
index bd3ba5f3..2cf06d46 100644
--- a/script/core/folding.lua
+++ b/script/core/folding.lua
@@ -145,6 +145,7 @@ local Care = {
end,
}
+---@async
return function (uri)
local state = files.getState(uri)
local text = files.getText(uri)
@@ -154,7 +155,7 @@ return function (uri)
local regions = {}
local status = {}
- guide.eachSource(state.ast, function (source)
+ guide.eachSource(state.ast, function (source) ---@async
local tp = source.type
if Care[tp] then
await.delay()
diff --git a/script/core/generic.lua b/script/core/generic.lua
index 92e97362..b383ee5d 100644
--- a/script/core/generic.lua
+++ b/script/core/generic.lua
@@ -7,7 +7,7 @@ local noder = require "core.noder"
---@field proto parser.guide.object
---@field parent parser.guide.object
----@class generic.closure
+---@class generic.closure: parser.guide.object
---@field type string
---@field proto parser.guide.object
---@field upvalues table<string, generic.value[]>
diff --git a/script/core/hint.lua b/script/core/hint.lua
index 62d2f7bf..42390443 100644
--- a/script/core/hint.lua
+++ b/script/core/hint.lua
@@ -6,13 +6,14 @@ local guide = require 'parser.guide'
local await = require 'await'
local define = require 'proto.define'
+---@async
local function typeHint(uri, results, start, finish)
- local ast = files.getState(uri)
- if not ast then
+ local state = files.getState(uri)
+ if not state then
return
end
local mark = {}
- guide.eachSourceBetween(ast.ast, start, finish, function (source)
+ guide.eachSourceBetween(state.ast, start, finish, function (source) ---@async
if source.type ~= 'local'
and source.type ~= 'setglobal'
and source.type ~= 'tablefield'
@@ -96,17 +97,18 @@ local function hasLiteralArgInCall(call)
return false
end
+---@async
local function paramName(uri, results, start, finish)
local paramConfig = config.get 'Lua.hint.paramName'
if not paramConfig or paramConfig == 'None' then
return
end
- local ast = files.getState(uri)
- if not ast then
+ local state = files.getState(uri)
+ if not state then
return
end
local mark = {}
- guide.eachSourceBetween(ast.ast, start, finish, function (source)
+ guide.eachSourceBetween(state.ast, start, finish, function (source) ---@async
if source.type ~= 'call' then
return
end
@@ -158,9 +160,39 @@ local function paramName(uri, results, start, finish)
end)
end
+---@async
+local function awaitHint(uri, results, start, finish)
+ local awaitConfig = config.get 'Lua.hint.await'
+ if not awaitConfig then
+ return
+ end
+ local state = files.getState(uri)
+ if not state then
+ return
+ end
+ guide.eachSourceBetween(state.ast, start, finish, function (source) ---@async
+ if source.type ~= 'call' then
+ return
+ end
+ await.delay()
+ local node = source.node
+ if not vm.isAsyncCall(source) then
+ return
+ end
+ results[#results+1] = {
+ text = 'await ',
+ offset = node.start,
+ kind = define.InlayHintKind.Other,
+ where = 'left',
+ }
+ end)
+end
+
+---@async
return function (uri, start, finish)
local results = {}
typeHint(uri, results, start, finish)
+ awaitHint(uri, results, start, finish)
paramName(uri, results, start, finish)
return results
end
diff --git a/script/core/hover/arg.lua b/script/core/hover/arg.lua
index 822be2b6..4e6a1ace 100644
--- a/script/core/hover/arg.lua
+++ b/script/core/hover/arg.lua
@@ -38,7 +38,10 @@ local function asFunction(source, oop)
infer.searchAndViewInfers(arg)
)
elseif arg.type == '...' then
- args[#args+1] = '...'
+ args[#args+1] = ('%s: %s'):format(
+ '...',
+ infer.searchAndViewInfers(arg)
+ )
else
args[#args+1] = ('%s'):format(infer.searchAndViewInfers(arg))
end
@@ -60,18 +63,11 @@ local function asDocFunction(source)
for i = 1, #source.args do
local arg = source.args[i]
local name = arg.name[1]
- if arg.extends then
- args[i] = ('%s%s: %s'):format(
- name,
- arg.optional and '?' or '',
- infer.searchAndViewInfers(arg.extends)
- )
- else
- args[i] = ('%s%s'):format(
- name,
- arg.optional and '?' or ''
- )
- end
+ args[i] = ('%s%s: %s'):format(
+ name,
+ arg.optional and '?' or '',
+ arg.extends and infer.searchAndViewInfers(arg.extends) or 'any'
+ )
end
return table.concat(args, ', ')
end
diff --git a/script/core/hover/init.lua b/script/core/hover/init.lua
index 784ef75d..7d99a006 100644
--- a/script/core/hover/init.lua
+++ b/script/core/hover/init.lua
@@ -7,12 +7,14 @@ local findSource = require 'core.find-source'
local markdown = require 'provider.markdown'
local infer = require 'core.infer'
+---@async
local function getHover(source)
local md = markdown()
local defMark = {}
local labelMark = {}
local descMark = {}
+ ---@async
local function addHover(def, checkLable)
if defMark[def] then
return
@@ -37,12 +39,17 @@ local function getHover(source)
end
if infer.searchAndViewInfers(source) == 'function' then
+ local hasFunc
for _, def in ipairs(vm.getDefs(source)) do
if def.type == 'function'
or def.type == 'doc.type.function' then
+ hasFunc = true
addHover(def, true)
end
end
+ if not hasFunc then
+ addHover(source, true)
+ end
else
addHover(source, true)
for _, def in ipairs(vm.getDefs(source)) do
@@ -74,6 +81,7 @@ local accept = {
['doc.module'] = true,
}
+---@async
local function getHoverByUri(uri, position)
local ast = files.getState(uri)
if not ast then
diff --git a/script/core/hover/label.lua b/script/core/hover/label.lua
index 8906d54d..0bb4fe89 100644
--- a/script/core/hover/label.lua
+++ b/script/core/hover/label.lua
@@ -16,7 +16,11 @@ local function asFunction(source, oop)
local arg = buildArg(source, oop)
local rtn = buildReturn(source)
local lines = {}
- lines[1] = ('%s %s(%s)'):format(oop and 'method' or 'function', name or '', arg)
+ lines[1] = ('%s%s %s(%s)'):format(
+ vm.isAsync(source) and 'async ' or '',
+ oop and 'method' or 'function',
+ name or '', arg
+ )
lines[2] = rtn
return table.concat(lines, '\n')
end
@@ -44,6 +48,7 @@ local function asDocTypeName(source)
end
end
+---@async
local function asValue(source, title)
local name = buildName(source, false) or ''
local type = infer.searchAndViewInfers(source)
@@ -59,6 +64,9 @@ local function asValue(source, title)
local pack = {}
pack[#pack+1] = title
pack[#pack+1] = name .. ':'
+ if vm.isAsync(source, true) then
+ pack[#pack+1] = 'async'
+ end
if cont
and ( type == 'table'
or type == 'any'
@@ -76,10 +84,12 @@ local function asValue(source, title)
return table.concat(pack, ' ')
end
+---@async
local function asLocal(source)
return asValue(source, 'local')
end
+---@async
local function asGlobal(source)
return asValue(source, 'global')
end
@@ -111,6 +121,7 @@ local function isGlobalField(source)
end
end
+---@async
local function asField(source)
if isGlobalField(source) then
return asGlobal(source)
@@ -175,6 +186,7 @@ local function asNumber(source)
return formatNumber(num)
end
+---@async
return function (source, oop)
if source.type == 'function' then
return asFunction(source, oop)
diff --git a/script/core/hover/table.lua b/script/core/hover/table.lua
index 68a04b40..285d5c02 100644
--- a/script/core/hover/table.lua
+++ b/script/core/hover/table.lua
@@ -134,6 +134,7 @@ local function getOptionalMap(fields)
return optionals
end
+---@async
return function (source)
local maxFields = config.get 'Lua.hover.previewFields'
if maxFields <= 0 then
diff --git a/script/core/infer.lua b/script/core/infer.lua
index 2825578e..8da35289 100644
--- a/script/core/infer.lua
+++ b/script/core/infer.lua
@@ -385,7 +385,7 @@ function m.viewDocFunction(doc)
end
local args = {}
for i, arg in ipairs(doc.args) do
- args[i] = ('%s: %s'):format(arg.name[1], m.viewDocName(arg.extends))
+ args[i] = ('%s: %s'):format(arg.name[1], arg.extends and m.viewDocName(arg.extends) or 'any')
end
local label = ('fun(%s)'):format(table.concat(args, ', '))
if #doc.returns > 0 then
diff --git a/script/core/noder.lua b/script/core/noder.lua
index 371e0200..0fc83905 100644
--- a/script/core/noder.lua
+++ b/script/core/noder.lua
@@ -1187,46 +1187,6 @@ compileNodeMap = util.switch()
: call(function (noders, id, source)
local uri = guide.getUri(source)
collector.subscribe(uri, id, noders)
-
- local parent = source.parent
- if parent.type ~= 'doc.type' then
- goto BREAK
- end
- local bindSources = parent.bindSources
- if not bindSources then
- goto BREAK
- end
- for i = 1, #bindSources do
- local src = bindSources[i]
- if src.type ~= 'local' then
- goto CONTINUE1
- end
- local refs = src.ref
- if not refs then
- goto CONTINUE1
- end
- for j = 1, #refs do
- local ref = refs[j]
- if ref.type ~= 'getlocal' then
- goto CONTINUE2
- end
- local nxt = ref.next
- if not nxt then
- goto CONTINUE2
- end
- local nxtType = nxt.type
- if nxtType == 'setfield'
- or nxtType == 'setmethod'
- or nxtType == 'setindex' then
- local defID = 'def:' .. id
- collector.subscribe(uri, defID, noders)
- goto BREAK
- end
- ::CONTINUE2::
- end
- ::CONTINUE1::
- end
- ::BREAK::
end)
: case 'doc.class.name'
: case 'doc.alias.name'
diff --git a/script/core/semantic-tokens.lua b/script/core/semantic-tokens.lua
index dc0649d1..8389cbb4 100644
--- a/script/core/semantic-tokens.lua
+++ b/script/core/semantic-tokens.lua
@@ -373,6 +373,7 @@ config.watch(function (key, value)
end
end)
+---@async
return function (uri, start, finish)
local state = files.getState(uri)
local text = files.getText(uri)
@@ -381,7 +382,7 @@ return function (uri, start, finish)
end
local results = {}
- guide.eachSourceBetween(state.ast, start, finish, function (source)
+ guide.eachSourceBetween(state.ast, start, finish, function (source) ---@async
local method = Care[source.type]
if not method then
return
diff --git a/script/core/signature.lua b/script/core/signature.lua
index 007a3787..d55866f5 100644
--- a/script/core/signature.lua
+++ b/script/core/signature.lua
@@ -39,6 +39,7 @@ local function findNearCall(uri, ast, pos)
return nearCall
end
+---@async
local function makeOneSignature(source, oop, index)
local label = hoverLabel(source, oop)
-- 去掉返回值
@@ -65,7 +66,7 @@ local function makeOneSignature(source, oop, index)
if index > i and i > 0 then
local lastLabel = params[i].label
local text = label:sub(lastLabel[1] + 1, lastLabel[2])
- if text == '...' then
+ if text:sub(1, 3) == '...' then
index = i
end
end
@@ -77,6 +78,7 @@ local function makeOneSignature(source, oop, index)
}
end
+---@async
local function makeSignatures(text, call, pos)
local node = call.node
local oop = node.type == 'method'
@@ -136,6 +138,7 @@ local function makeSignatures(text, call, pos)
return signs
end
+---@async
return function (uri, pos)
local state = files.getState(uri)
if not state then
diff --git a/script/core/workspace-symbol.lua b/script/core/workspace-symbol.lua
index 265a8d92..5fb4a741 100644
--- a/script/core/workspace-symbol.lua
+++ b/script/core/workspace-symbol.lua
@@ -57,6 +57,7 @@ local function searchFile(uri, key, results)
end)
end
+---@async
return function (key)
local results = {}
diff --git a/script/files.lua b/script/files.lua
index 4d649b29..a779f0f6 100644
--- a/script/files.lua
+++ b/script/files.lua
@@ -120,16 +120,22 @@ end
--- 设置文件文本
---@param uri uri
---@param text string
-function m.setText(uri, text, isTrust, instance)
+---@param isTrust boolean
+---@param version integer
+function m.setText(uri, text, isTrust, version)
if not text then
return
end
+ if #text > 1024 * 1024 * 10 then
+ local client = require 'client'
+ client.showMessage('Warning', lang.script('WORKSPACE_SKIP_HUGE_FILE', uri))
+ return
+ end
--log.debug('setText', uri)
local create
if not m.fileMap[uri] then
m.fileMap[uri] = {
uri = uri,
- version = 0,
}
m.fileCount = m.fileCount + 1
create = true
@@ -154,7 +160,7 @@ function m.setText(uri, text, isTrust, instance)
m.astMap[uri] = nil
file.cache = {}
file.cacheActiveTime = math.huge
- file.version = file.version + 1
+ file.version = version
m.globalVersion = m.globalVersion + 1
await.close('files.version')
m.onWatch('version')
@@ -457,6 +463,7 @@ function m.compileState(uri, text)
--await.delay()
if state then
state.uri = uri
+ state.lua = text
state.ast.uri = uri
local clock = os.clock()
parser.luadoc(state)
@@ -488,14 +495,14 @@ function m.getState(uri)
if not file then
return nil
end
- local ast = m.astMap[uri]
- if not ast then
- ast = m.compileState(uri, file.text)
- m.astMap[uri] = ast
+ local state = m.astMap[uri]
+ if not state then
+ state = m.compileState(uri, file.text)
+ m.astMap[uri] = state
--await.delay()
end
file.cacheActiveTime = timer.clock()
- return ast
+ return state
end
---设置文件的当前可见范围
@@ -703,13 +710,16 @@ function m.getDllWords(uri)
end
--- 注册事件
+---@param callback async fun(ev: string, uri: uri)
function m.watch(callback)
m.watchList[#m.watchList+1] = callback
end
-function m.onWatch(ev, ...)
+function m.onWatch(ev, uri)
for _, callback in ipairs(m.watchList) do
- xpcall(callback, log.error, ev, ...)
+ await.call(function ()
+ callback(ev, uri)
+ end)
end
end
diff --git a/script/filewatch.lua b/script/filewatch.lua
index e2050dd9..dd46d1a3 100644
--- a/script/filewatch.lua
+++ b/script/filewatch.lua
@@ -30,6 +30,7 @@ function m.watch(path)
end
end
+---@param callback async fun()
function m.event(callback)
m._eventList[#m._eventList+1] = callback
end
diff --git a/script/glob/gitignore.lua b/script/glob/gitignore.lua
index 73e20cbf..09be1415 100644
--- a/script/glob/gitignore.lua
+++ b/script/glob/gitignore.lua
@@ -163,6 +163,8 @@ function mt:getRelativePath(path)
return path
end
+---@param callback async fun()
+---@async
function mt:scan(path, callback)
local files = {}
if type(callback) ~= 'function' then
@@ -170,6 +172,7 @@ function mt:scan(path, callback)
end
local list = {}
+ ---@async
local function check(current)
local fileType = self:callInterface('type', current)
if fileType == 'file' then
diff --git a/script/global.d.lua b/script/global.d.lua
index cc0aafbd..0435293e 100644
--- a/script/global.d.lua
+++ b/script/global.d.lua
@@ -11,7 +11,7 @@ DBGPORT = 0
DBGWAIT = false
---displayed language, use command line: --locale="en-us"
----@type '"en-us"'|'"zh-cn"'
+---@type '"en-us"'|'"zh-cn"'|'"pt-br"'
LOCALE = 'en-us'
---path of local config file, use command line: --configpath="config.lua"
@@ -27,4 +27,9 @@ SHOWSOURCE = false
TRACE = false
---trace searching with `too deep!` into log, use command line: --footprint=true
+---@type boolean
FOOTPRINT = false
+
+---trace rpc, use command line: --rpclog=true
+---@type boolean
+RPCLOG = false
diff --git a/script/library.lua b/script/library.lua
index 943e6d2d..81242a91 100644
--- a/script/library.lua
+++ b/script/library.lua
@@ -341,6 +341,7 @@ local function apply3rd(cfg, onlyMemory)
end
local hasAsked
+---@async
local function askFor3rd(cfg)
hasAsked = true
local yes1 = lang.script.WINDOW_APPLY_WHIT_SETTING
@@ -395,7 +396,7 @@ local function check3rdByWords(text, configs)
if hasAsked then
return
end
- await.call(function ()
+ await.call(function () ---@async
for _, cfg in ipairs(configs) do
if cfg.words then
for _, word in ipairs(cfg.words) do
@@ -419,7 +420,7 @@ local function check3rdByFileName(uri, configs)
if not path then
return
end
- await.call(function ()
+ await.call(function () ---@async
for _, cfg in ipairs(configs) do
if cfg.files then
for _, filename in ipairs(cfg.files) do
diff --git a/script/parser/luadoc.lua b/script/parser/luadoc.lua
index e21e7c19..d206e6d7 100644
--- a/script/parser/luadoc.lua
+++ b/script/parser/luadoc.lua
@@ -10,9 +10,8 @@ local Parser = re.compile([[
Main <- (Token / Sp)*
Sp <- %s+
X16 <- [a-fA-F0-9]
-Word <- [a-zA-Z0-9_]
Token <- Integer / Name / String / Symbol
-Name <- ({} {[a-zA-Z_0-9] [a-zA-Z0-9_.*-]*} {})
+Name <- ({} {%name} {})
-> Name
Integer <- ({} {[0-9]+} !'.' {})
-> Integer
@@ -45,7 +44,7 @@ EChar <- 'a' -> ea
/ ('z' (%nl / %s)*) -> ''
/ ('x' {X16 X16}) -> Char16
/ ([0-9] [0-9]? [0-9]?) -> Char10
- / ('u{' {Word*} '}') -> CharUtf8
+ / ('u{' {X16*} '}') -> CharUtf8
Symbol <- ({} {
[:|,<>()?+#`{}]
/ '[]'
@@ -63,6 +62,7 @@ Symbol <- ({} {
er = '\r',
et = '\t',
ev = '\v',
+ name = (m.R('az', 'AZ', '09', '\x80\xff') + m.S('_')) * (m.R('az', 'AZ', '__', '09', '\x80\xff') + m.S('_.*-'))^0,
Char10 = function (char)
char = tonumber(char)
if not char or char < 0 or char > 255 then
@@ -342,6 +342,21 @@ local function parseTypeUnitTable(parent, node)
return result
end
+local function parseDots(tp, parent)
+ if not checkToken('symbol', '...', 1) then
+ return
+ end
+ nextToken()
+ local dots = {
+ type = tp,
+ start = getStart(),
+ finish = getFinish(),
+ parent = parent,
+ [1] = '...',
+ }
+ return dots
+end
+
local function parseTypeUnitFunction()
local typeUnit = {
type = 'doc.type.function',
@@ -361,47 +376,29 @@ local function parseTypeUnitFunction()
type = 'doc.type.arg',
parent = typeUnit,
}
- if checkToken('symbol', '...', 1) then
- nextToken()
- local vararg = {
- type = 'doc.type.name',
- start = getStart(),
+ arg.name = parseName('doc.type.name', arg)
+ or parseDots('doc.type.name', arg)
+ if not arg.name then
+ pushError {
+ type = 'LUADOC_MISS_ARG_NAME',
+ start = getFinish(),
finish = getFinish(),
- parent = arg,
- [1] = '...',
}
- arg.name = vararg
- if not arg.start then
- arg.start = arg.name.start
- end
- arg.finish = getFinish()
- else
- arg.name = parseName('doc.type.name', arg)
- if not arg.name then
- pushError {
- type = 'LUADOC_MISS_ARG_NAME',
- start = getFinish(),
- finish = getFinish(),
- }
- break
- end
- if not arg.start then
- arg.start = arg.name.start
- end
- if checkToken('symbol', '?', 1) then
- nextToken()
- arg.optional = true
- end
- arg.finish = getFinish()
- if not nextSymbolOrError(':') then
- break
- end
+ break
+ end
+ if not arg.start then
+ arg.start = arg.name.start
+ end
+ if checkToken('symbol', '?', 1) then
+ nextToken()
+ arg.optional = true
+ end
+ arg.finish = getFinish()
+ if checkToken('symbol', ':', 1) then
+ nextToken()
arg.extends = parseType(arg)
- if not arg.extends then
- break
- end
- arg.finish = getFinish()
end
+ arg.finish = getFinish()
typeUnit.args[#typeUnit.args+1] = arg
if checkToken('symbol', ',', 1) then
nextToken()
@@ -492,6 +489,19 @@ local function parseTypeUnitLiteralTable()
end
local function parseTypeUnit(parent, content)
+ if content == 'async' then
+ local tp, cont = peekToken()
+ if tp == 'name' then
+ if cont == 'fun' then
+ nextToken()
+ local func = parseTypeUnit(parent, cont)
+ if func then
+ func.async = true
+ return func
+ end
+ end
+ end
+ end
local result
if content == 'fun' then
result = parseTypeUnitFunction()
@@ -749,6 +759,7 @@ local function parseParam()
type = 'doc.param',
}
result.param = parseName('doc.param.name', result)
+ or parseDots('doc.param.name', result)
if not result.param then
pushError {
type = 'LUADOC_MISS_PARAM_NAME',
@@ -1098,6 +1109,22 @@ local function parseModule()
return result
end
+local function parseAsync()
+ return {
+ type = 'doc.async',
+ start = getFinish(),
+ finish = getFinish(),
+ }
+end
+
+local function parseNoDiscard()
+ return {
+ type = 'doc.nodiscard',
+ start = getFinish(),
+ finish = getFinish(),
+ }
+end
+
local function convertTokens()
local tp, text = nextToken()
if not tp then
@@ -1141,6 +1168,10 @@ local function convertTokens()
return parseDiagnostic()
elseif text == 'module' then
return parseModule()
+ elseif text == 'async' then
+ return parseAsync()
+ elseif text == 'nodiscard' then
+ return parseNoDiscard()
end
end
diff --git a/script/parser/newparser.lua b/script/parser/newparser.lua
index 0b721a7a..0132350b 100644
--- a/script/parser/newparser.lua
+++ b/script/parser/newparser.lua
@@ -487,7 +487,13 @@ end
local function skipComment(isAction)
local token = Tokens[Index + 1]
if token == '--'
- or (token == '//' and isAction) then
+ or (
+ token == '//'
+ and (
+ isAction
+ or State.options.nonstandardSymbol['//']
+ )
+ ) then
local start = Tokens[Index]
local left = getPosition(start, 'left')
local chead = false
@@ -1527,7 +1533,7 @@ local function parseTable()
local index = 0
local wantSep = false
while true do
- skipSpace()
+ skipSpace(true)
local token = Tokens[Index + 1]
if token == '}' then
Index = Index + 2
@@ -2094,6 +2100,7 @@ local function parseParams(params)
start = getPosition(Tokens[Index], 'left'),
finish = getPosition(Tokens[Index] + 2, 'right'),
parent = params,
+ [1] = '...',
}
local chunk = Chunk[#Chunk]
chunk.vararg = vararg
@@ -2161,7 +2168,7 @@ local function parseFunction(isLocal, isAction)
Index = Index + 2
local LastLocalCount = LocalCount
LocalCount = 0
- skipSpace()
+ skipSpace(true)
local hasLeftParen = Tokens[Index + 1] == '('
if not hasLeftParen then
local name = parseName()
@@ -2191,7 +2198,7 @@ local function parseFunction(isLocal, isAction)
finish = simple.finish,
}
end
- skipSpace()
+ skipSpace(true)
hasLeftParen = Tokens[Index + 1] == '('
end
end
@@ -2222,7 +2229,7 @@ local function parseFunction(isLocal, isAction)
params.parent = func
func.args = params
end
- skipSpace()
+ skipSpace(true)
if Tokens[Index + 1] == ')' then
local parenRight = getPosition(Tokens[Index], 'right')
func.finish = parenRight
@@ -2230,7 +2237,7 @@ local function parseFunction(isLocal, isAction)
params.finish = parenRight
end
Index = Index + 2
- skipSpace()
+ skipSpace(true)
else
func.finish = lastRightPosition()
if params then
@@ -2339,6 +2346,9 @@ local function parseBinaryOP(asAction, level)
if not symbol then
return nil
end
+ if symbol == '//' and State.options.nonstandardSymbol['//'] then
+ return nil
+ end
local myLevel = BinarySymbol[symbol]
if level and myLevel < level then
return nil
diff --git a/script/plugin.lua b/script/plugin.lua
index 26f39226..f56dc9f9 100644
--- a/script/plugin.lua
+++ b/script/plugin.lua
@@ -50,6 +50,7 @@ local function resetFiles()
end
end
+---@async
local function checkTrustLoad()
local filePath = LOGPATH .. '/trusted'
local trusted = util.loadFile(filePath)
@@ -79,7 +80,7 @@ function m.init()
return
end
m.hasInited = true
- await.call(function ()
+ await.call(function () ---@async
local ws = require 'workspace'
m.interface = {}
@@ -100,7 +101,7 @@ function m.init()
m.showError(err)
return
end
- if not checkTrustLoad() then
+ if not client.isVSCode() and not checkTrustLoad() then
return
end
local suc, err = xpcall(f, log.error, f)
diff --git a/script/proto/converter.lua b/script/proto/converter.lua
index cf6331f1..9c75f056 100644
--- a/script/proto/converter.lua
+++ b/script/proto/converter.lua
@@ -2,7 +2,6 @@ local guide = require 'parser.guide'
local files = require 'files'
local encoder = require 'encoder'
--- TODO
local offsetEncoding = 'utf16'
local m = {}
@@ -178,4 +177,8 @@ function m.textEdit(range, newtext)
}
end
+function m.setOffsetEncoding(encoding)
+ offsetEncoding = encoding:lower():gsub('%-', '')
+end
+
return m
diff --git a/script/proto/define.lua b/script/proto/define.lua
index 713857af..dbb6ba85 100644
--- a/script/proto/define.lua
+++ b/script/proto/define.lua
@@ -44,6 +44,9 @@ m.DiagnosticDefaultSeverity = {
['no-implicit-any'] = 'Information',
['deprecated'] = 'Warning',
['different-requires'] = 'Warning',
+ ['await-in-sync'] = 'Warning',
+ ['not-yieldable'] = 'Warning',
+ ['discard-returns'] = 'Warning',
['type-check'] = 'Warning',
['duplicate-doc-class'] = 'Warning',
@@ -98,6 +101,9 @@ m.DiagnosticDefaultNeededFileStatus = {
['no-implicit-any'] = 'None',
['deprecated'] = 'Opened',
['different-requires'] = 'Any',
+ ['await-in-sync'] = 'None',
+ ['not-yieldable'] = 'None',
+ ['discard-returns'] = 'Opened',
['type-check'] = 'None',
['duplicate-doc-class'] = 'Any',
diff --git a/script/proto/proto.lua b/script/proto/proto.lua
index e380f54f..7cdc461c 100644
--- a/script/proto/proto.lua
+++ b/script/proto/proto.lua
@@ -8,6 +8,20 @@ local json = require 'json'
local reqCounter = util.counter()
+local function logSend(buf)
+ if not RPCLOG then
+ return
+ end
+ log.debug('rpc send:', buf)
+end
+
+local function logRecieve(proto)
+ if not RPCLOG then
+ return
+ end
+ log.debug('rpc recieve:', json.encode(proto))
+end
+
local m = {}
m.ability = {}
@@ -22,6 +36,7 @@ function m.getMethodName(proto)
end
end
+---@param callback async fun()
function m.on(method, callback)
m.ability[method] = callback
end
@@ -38,6 +53,7 @@ function m.response(id, res)
data.result = res == nil and json.null or res
local buf = jsonrpc.encode(data)
--log.debug('Response', id, #buf)
+ logSend(buf)
io.write(buf)
end
@@ -56,6 +72,7 @@ function m.responseErr(id, code, message)
}
}
--log.debug('ResponseErr', id, #buf)
+ logSend(buf)
io.write(buf)
end
@@ -65,9 +82,11 @@ function m.notify(name, params)
params = params,
}
--log.debug('Notify', name, #buf)
+ logSend(buf)
io.write(buf)
end
+---@async
function m.awaitRequest(name, params)
local id = reqCounter()
local buf = jsonrpc.encode {
@@ -76,6 +95,7 @@ function m.awaitRequest(name, params)
params = params,
}
--log.debug('Request', name, #buf)
+ logSend(buf)
io.write(buf)
local result, error = await.wait(function (resume)
m.waiting[id] = resume
@@ -94,6 +114,7 @@ function m.request(name, params, callback)
params = params,
}
--log.debug('Request', name, #buf)
+ logSend(buf)
io.write(buf)
m.waiting[id] = function (result, error)
if error then
@@ -106,6 +127,7 @@ function m.request(name, params, callback)
end
function m.doMethod(proto)
+ logRecieve(proto)
local method, optional = m.getMethodName(proto)
local abil = m.ability[method]
if not abil then
@@ -120,7 +142,7 @@ function m.doMethod(proto)
if proto.id then
m.holdon[proto.id] = proto
end
- await.call(function ()
+ await.call(function () ---@async
--log.debug('Start method:', method)
if proto.id then
await.setID('proto:' .. proto.id)
@@ -146,6 +168,7 @@ function m.doMethod(proto)
end
end
ok, res = xpcall(abil, log.error, proto.params)
+ await.delay()
end)
end
@@ -159,6 +182,7 @@ function m.close(id, reason)
end
function m.doResponse(proto)
+ logRecieve(proto)
local id = proto.id
local resume = m.waiting[id]
if not resume then
diff --git a/script/provider/capability.lua b/script/provider/capability.lua
index 76cadc0d..b712defc 100644
--- a/script/provider/capability.lua
+++ b/script/provider/capability.lua
@@ -48,6 +48,7 @@ end
function m.getIniter()
local initer = {
+ offsetEncoding = client.getOffsetEncoding(),
-- 文本同步方式
textDocumentSync = {
-- 打开关闭文本时通知
diff --git a/script/provider/diagnostic.lua b/script/provider/diagnostic.lua
index 492b3048..ca4bcdb8 100644
--- a/script/provider/diagnostic.lua
+++ b/script/provider/diagnostic.lua
@@ -11,6 +11,7 @@ local progress = require "progress"
local client = require 'client'
local converter = require 'proto.converter'
+---@class diagnosticProvider
local m = {}
m._start = false
m.cache = {}
@@ -139,6 +140,10 @@ function m.clear(uri)
log.debug('clearDiagnostics', uri)
end
+function m.clearCache(uri)
+ m.cache[uri] = false
+end
+
function m.clearAll()
for luri in pairs(m.cache) do
m.clear(luri)
@@ -152,11 +157,13 @@ function m.syntaxErrors(uri, ast)
local results = {}
- for _, err in ipairs(ast.errs) do
- if not config.get 'Lua.diagnostics.disable'[err.type:lower():gsub('_', '-')] then
- results[#results+1] = buildSyntaxError(uri, err)
+ pcall(function ()
+ for _, err in ipairs(ast.errs) do
+ if not config.get 'Lua.diagnostics.disable'[err.type:lower():gsub('_', '-')] then
+ results[#results+1] = buildSyntaxError(uri, err)
+ end
end
- end
+ end)
return results
end
@@ -180,6 +187,7 @@ function m.diagnostics(uri, diags)
end)
end
+---@async
function m.doDiagnostic(uri)
if not config.get 'Lua.diagnostics.enable' then
return
@@ -213,6 +221,8 @@ function m.doDiagnostic(uri)
return
end
+ local version = files.getVersion(uri)
+
await.setID('diag:' .. uri)
local prog <close> = progress.create(lang.script.WINDOW_DIAGNOSING, 0.5)
@@ -236,6 +246,7 @@ function m.doDiagnostic(uri)
proto.notify('textDocument/publishDiagnostics', {
uri = uri,
+ version = version,
diagnostics = full,
})
if #full > 0 then
@@ -265,15 +276,17 @@ function m.refresh(uri)
return
end
await.close('diag:' .. uri)
- await.call(function ()
+ await.call(function () ---@async
await.delay()
if uri then
- m.doDiagnostic(uri)
+ m.clearCache(uri)
+ xpcall(m.doDiagnostic, log.error, uri)
end
m.diagnosticsAll()
end, 'files.version')
end
+---@async
local function askForDisable()
if m.dontAskedForDisable then
return
@@ -332,7 +345,7 @@ function m.diagnosticsAll(force)
return
end
await.close 'diagnosticsAll'
- await.call(function ()
+ await.call(function () ---@async
await.sleep(delay)
m.diagnosticsAllClock = os.clock()
local clock = os.clock()
@@ -347,7 +360,7 @@ function m.diagnosticsAll(force)
for i, uri in ipairs(uris) do
bar:setMessage(('%d/%d'):format(i, #uris))
bar:setPercentage(i / #uris * 100)
- m.doDiagnostic(uri)
+ xpcall(m.doDiagnostic, log.error, uri)
await.delay()
if cancelled then
log.debug('Break workspace diagnostics')
@@ -375,6 +388,7 @@ function m.checkStepResult()
end
end
+---@async
function m.checkWorkspaceDiag()
if not await.hasID 'diagnosticsAll' then
return
@@ -400,7 +414,7 @@ function m.checkWorkspaceDiag()
return false
end
-files.watch(function (ev, uri)
+files.watch(function (ev, uri) ---@async
if ev == 'remove' then
m.clear(uri)
m.refresh(uri)
@@ -410,7 +424,7 @@ files.watch(function (ev, uri)
end
elseif ev == 'open' then
if ws.isReady() then
- m.doDiagnostic(uri)
+ xpcall(m.doDiagnostic, log.error, uri)
end
elseif ev == 'close' then
if files.isLibrary(uri)
@@ -420,7 +434,7 @@ files.watch(function (ev, uri)
end
end)
-await.watch(function (ev, co)
+await.watch(function (ev, co) ---@async
if ev == 'delay' then
if m.checkStepResult then
m.checkStepResult()
diff --git a/script/provider/provider.lua b/script/provider/provider.lua
index 8932c373..d732f3c2 100644
--- a/script/provider/provider.lua
+++ b/script/provider/provider.lua
@@ -16,6 +16,7 @@ local cfgLoader = require 'config.loader'
local converter = require 'proto.converter'
local filewatch = require 'filewatch'
+---@async
local function updateConfig()
local new
if CONFIGPATH then
@@ -43,7 +44,19 @@ local function updateConfig()
log.debug('loaded config dump:', util.dump(new))
end
-filewatch.event(function (changes)
+---@class provider
+local m = {}
+
+m.attributes = {}
+
+function m.register(method)
+ return function (attrs)
+ m.attributes[method] = attrs
+ proto.on(method, attrs[1])
+ end
+end
+
+filewatch.event(function (changes) ---@async
local configPath = workspace.getAbsolutePath(CONFIGPATH or '.luarc.json')
if not configPath then
return
@@ -56,777 +69,886 @@ filewatch.event(function (changes)
end
end)
-proto.on('initialize', function (params)
- client.init(params)
- config.init()
- workspace.initPath(params.rootUri)
- return {
- capabilities = cap.getIniter(),
- serverInfo = {
- name = 'sumneko.lua',
- },
- }
-end)
-
-proto.on('initialized', function (params)
- files.init()
- local _ <close> = progress.create(lang.script.WINDOW_INITIALIZING, 0.5)
- updateConfig()
- local registrations = {}
-
- if client.getAbility 'workspace.didChangeConfiguration.dynamicRegistration' then
- -- 监视配置变化
- registrations[#registrations+1] = {
- id = 'workspace/didChangeConfiguration',
- method = 'workspace/didChangeConfiguration',
+m.register 'initialize' {
+ function (params)
+ client.init(params)
+ config.init()
+ workspace.initPath(params.rootUri)
+ return {
+ capabilities = cap.getIniter(),
+ serverInfo = {
+ name = 'sumneko.lua',
+ },
}
end
+}
- if #registrations ~= 0 then
- proto.awaitRequest('client/registerCapability', {
- registrations = registrations
- })
- end
- library.init()
- workspace.init()
- return true
-end)
+m.register 'initialized'{
+ ---@async
+ function (params)
+ files.init()
+ local _ <close> = progress.create(lang.script.WINDOW_INITIALIZING, 0.5)
+ updateConfig()
+ local registrations = {}
-proto.on('exit', function ()
- log.info('Server exited.')
- os.exit(true)
-end)
+ if client.getAbility 'workspace.didChangeConfiguration.dynamicRegistration' then
+ -- 监视配置变化
+ registrations[#registrations+1] = {
+ id = 'workspace/didChangeConfiguration',
+ method = 'workspace/didChangeConfiguration',
+ }
+ end
-proto.on('shutdown', function ()
- log.info('Server shutdown.')
- return true
-end)
+ if #registrations ~= 0 then
+ proto.awaitRequest('client/registerCapability', {
+ registrations = registrations
+ })
+ end
+ library.init()
+ workspace.init()
+ return true
+ end
+}
-proto.on('workspace/didChangeConfiguration', function ()
- if CONFIGPATH then
- return
+m.register 'exit' {
+ function ()
+ log.info('Server exited.')
+ os.exit(true)
end
- updateConfig()
-end)
+}
-proto.on('workspace/didCreateFiles', function (params)
- log.debug('workspace/didCreateFiles', util.dump(params))
- for _, file in ipairs(params.files) do
- if workspace.isValidLuaUri(file.uri) then
- files.setText(file.uri, pub.awaitTask('loadFile', file.uri), false)
- end
+m.register 'shutdown' {
+ function ()
+ log.info('Server shutdown.')
+ return true
end
-end)
+}
-proto.on('workspace/didDeleteFiles', function (params)
- log.debug('workspace/didDeleteFiles', util.dump(params))
- for _, file in ipairs(params.files) do
- files.remove(file.uri)
- local childs = files.getChildFiles(file.uri)
- for _, uri in ipairs(childs) do
- log.debug('workspace/didDeleteFiles#child', uri)
- files.remove(uri)
+m.register 'workspace/didChangeConfiguration' {
+ function () ---@async
+ if CONFIGPATH then
+ return
end
+ updateConfig()
end
-end)
+}
-proto.on('workspace/didRenameFiles', function (params)
- log.debug('workspace/didRenameFiles', util.dump(params))
- for _, file in ipairs(params.files) do
- local text = files.getOriginText(file.oldUri)
- if text then
- files.remove(file.oldUri)
- if workspace.isValidLuaUri(file.newUri) then
- files.setText(file.newUri, text, false)
+m.register 'workspace/didCreateFiles' {
+ ---@async
+ function (params)
+ log.debug('workspace/didCreateFiles', util.dump(params))
+ for _, file in ipairs(params.files) do
+ if workspace.isValidLuaUri(file.uri) then
+ files.setText(file.uri, pub.awaitTask('loadFile', file.uri), false)
end
end
- local childs = files.getChildFiles(file.oldUri)
- for _, uri in ipairs(childs) do
- local ctext = files.getOriginText(uri)
- if ctext then
- local ouri = uri
- local tail = ouri:sub(#file.oldUri)
- local nuri = file.newUri .. tail
- log.debug('workspace/didRenameFiles#child', ouri, nuri)
+ end
+}
+
+m.register 'workspace/didDeleteFiles' {
+ function (params)
+ log.debug('workspace/didDeleteFiles', util.dump(params))
+ for _, file in ipairs(params.files) do
+ files.remove(file.uri)
+ local childs = files.getChildFiles(file.uri)
+ for _, uri in ipairs(childs) do
+ log.debug('workspace/didDeleteFiles#child', uri)
files.remove(uri)
- if workspace.isValidLuaUri(nuri) then
- files.setText(nuri, text, false)
+ end
+ end
+ end
+}
+
+m.register 'workspace/didRenameFiles' {
+ ---@async
+ function (params)
+ log.debug('workspace/didRenameFiles', util.dump(params))
+ for _, file in ipairs(params.files) do
+ local text = files.getOriginText(file.oldUri)
+ if text then
+ files.remove(file.oldUri)
+ if workspace.isValidLuaUri(file.newUri) then
+ files.setText(file.newUri, text, false)
+ end
+ end
+ local childs = files.getChildFiles(file.oldUri)
+ for _, uri in ipairs(childs) do
+ local ctext = files.getOriginText(uri)
+ if ctext then
+ local ouri = uri
+ local tail = ouri:sub(#file.oldUri)
+ local nuri = file.newUri .. tail
+ log.debug('workspace/didRenameFiles#child', ouri, nuri)
+ files.remove(uri)
+ if workspace.isValidLuaUri(nuri) then
+ files.setText(nuri, text, false)
+ end
end
end
end
end
-end)
+}
-proto.on('textDocument/didOpen', function (params)
- workspace.awaitReady()
- local doc = params.textDocument
- local uri = doc.uri
- local text = doc.text
- log.debug('didOpen', uri)
- files.setText(uri, text, true)
- files.open(uri)
-end)
+m.register 'textDocument/didOpen' {
+ ---@async
+ function (params)
+ workspace.awaitReady()
+ local doc = params.textDocument
+ local uri = doc.uri
+ local text = doc.text
+ log.debug('didOpen', uri)
+ files.setText(uri, text, true)
+ files.open(uri)
+ end
+}
-proto.on('textDocument/didClose', function (params)
- local doc = params.textDocument
- local uri = doc.uri
- log.debug('didClose', uri)
- files.close(uri)
- if not files.isLua(uri) then
- files.remove(uri)
+m.register 'textDocument/didClose' {
+ function (params)
+ local doc = params.textDocument
+ local uri = doc.uri
+ log.debug('didClose', uri)
+ files.close(uri)
+ if not files.isLua(uri) then
+ files.remove(uri)
+ end
end
-end)
+}
-proto.on('textDocument/didChange', function (params)
- workspace.awaitReady()
- local doc = params.textDocument
- local changes = params.contentChanges
- local uri = doc.uri
- --log.debug('changes', util.dump(changes))
- local text = tm(uri, changes)
- files.setText(uri, text, true)
-end)
+m.register 'textDocument/didChange' {
+ ---@async
+ function (params)
+ workspace.awaitReady()
+ local doc = params.textDocument
+ local changes = params.contentChanges
+ local uri = doc.uri
+ --log.debug('changes', util.dump(changes))
+ local text = tm(uri, changes)
+ files.setText(uri, text, true, doc.version)
+ end
+}
-proto.on('textDocument/hover', function (params)
- local doc = params.textDocument
- local uri = doc.uri
- if not workspace.isReady() then
- local count, max = workspace.getLoadProcess()
+m.register 'textDocument/hover' {
+ abortByFileUpdate = true,
+ ---@async
+ function (params)
+ local doc = params.textDocument
+ local uri = doc.uri
+ if not workspace.isReady() then
+ local count, max = workspace.getLoadProcess()
+ return {
+ contents = {
+ value = lang.script('HOVER_WS_LOADING', count, max),
+ kind = 'markdown',
+ }
+ }
+ end
+ local _ <close> = progress.create(lang.script.WINDOW_PROCESSING_HOVER, 0.5)
+ local core = require 'core.hover'
+ if not files.exists(uri) then
+ return nil
+ end
+ local pos = converter.unpackPosition(uri, params.position)
+ local hover, source = core.byUri(uri, pos)
+ if not hover then
+ return nil
+ end
return {
contents = {
- value = lang.script('HOVER_WS_LOADING', count, max),
+ value = tostring(hover),
kind = 'markdown',
- }
+ },
+ range = converter.packRange(uri, source.start, source.finish),
}
end
- local _ <close> = progress.create(lang.script.WINDOW_PROCESSING_HOVER, 0.5)
- local core = require 'core.hover'
- if not files.exists(uri) then
- return nil
- end
- local pos = converter.unpackPosition(uri, params.position)
- local hover, source = core.byUri(uri, pos)
- if not hover then
- return nil
- end
- return {
- contents = {
- value = tostring(hover),
- kind = 'markdown',
- },
- range = converter.packRange(uri, source.start, source.finish),
- }
-end)
+}
-proto.on('textDocument/definition', function (params)
- workspace.awaitReady()
- local _ <close> = progress.create(lang.script.WINDOW_PROCESSING_DEFINITION, 0.5)
- local core = require 'core.definition'
- local uri = params.textDocument.uri
- if not files.exists(uri) then
- return nil
- end
- local pos = converter.unpackPosition(uri, params.position)
- local result = core(uri, pos)
- if not result then
- return nil
- end
- local response = {}
- for i, info in ipairs(result) do
- local targetUri = info.uri
- if targetUri then
- if files.exists(targetUri) then
- if client.getAbility 'textDocument.definition.linkSupport' then
- response[i] = converter.locationLink(targetUri
- , converter.packRange(targetUri, info.target.start, info.target.finish)
- , converter.packRange(targetUri, info.target.start, info.target.finish)
- , converter.packRange(uri, info.source.start, info.source.finish)
- )
- else
- response[i] = converter.location(targetUri
- , converter.packRange(targetUri, info.target.start, info.target.finish)
- )
+m.register 'textDocument/definition' {
+ abortByFileUpdate = true,
+ ---@async
+ function (params)
+ workspace.awaitReady()
+ local _ <close> = progress.create(lang.script.WINDOW_PROCESSING_DEFINITION, 0.5)
+ local core = require 'core.definition'
+ local uri = params.textDocument.uri
+ if not files.exists(uri) then
+ return nil
+ end
+ local pos = converter.unpackPosition(uri, params.position)
+ local result = core(uri, pos)
+ if not result then
+ return nil
+ end
+ local response = {}
+ for i, info in ipairs(result) do
+ local targetUri = info.uri
+ if targetUri then
+ if files.exists(targetUri) then
+ if client.getAbility 'textDocument.definition.linkSupport' then
+ response[i] = converter.locationLink(targetUri
+ , converter.packRange(targetUri, info.target.start, info.target.finish)
+ , converter.packRange(targetUri, info.target.start, info.target.finish)
+ , converter.packRange(uri, info.source.start, info.source.finish)
+ )
+ else
+ response[i] = converter.location(targetUri
+ , converter.packRange(targetUri, info.target.start, info.target.finish)
+ )
+ end
end
end
end
+ return response
end
- return response
-end)
+}
-proto.on('textDocument/typeDefinition', function (params)
- workspace.awaitReady()
- local _ <close> = progress.create(lang.script.WINDOW_PROCESSING_TYPE_DEFINITION, 0.5)
- local core = require 'core.type-definition'
- local uri = params.textDocument.uri
- if not files.exists(uri) then
- return nil
- end
- local pos = converter.unpackPosition(uri, params.position)
- local result = core(uri, pos)
- if not result then
- return nil
- end
- local response = {}
- for i, info in ipairs(result) do
- local targetUri = info.uri
- if targetUri then
- if files.exists(targetUri) then
- if client.getAbility 'textDocument.typeDefinition.linkSupport' then
- response[i] = converter.locationLink(targetUri
- , converter.packRange(targetUri, info.target.start, info.target.finish)
- , converter.packRange(targetUri, info.target.start, info.target.finish)
- , converter.packRange(uri, info.source.start, info.source.finish)
- )
- else
- response[i] = converter.location(targetUri
- , converter.packRange(targetUri, info.target.start, info.target.finish)
- )
+m.register 'textDocument/typeDefinition' {
+ abortByFileUpdate = true,
+ ---@async
+ function (params)
+ workspace.awaitReady()
+ local _ <close> = progress.create(lang.script.WINDOW_PROCESSING_TYPE_DEFINITION, 0.5)
+ local core = require 'core.type-definition'
+ local uri = params.textDocument.uri
+ if not files.exists(uri) then
+ return nil
+ end
+ local pos = converter.unpackPosition(uri, params.position)
+ local result = core(uri, pos)
+ if not result then
+ return nil
+ end
+ local response = {}
+ for i, info in ipairs(result) do
+ local targetUri = info.uri
+ if targetUri then
+ if files.exists(targetUri) then
+ if client.getAbility 'textDocument.typeDefinition.linkSupport' then
+ response[i] = converter.locationLink(targetUri
+ , converter.packRange(targetUri, info.target.start, info.target.finish)
+ , converter.packRange(targetUri, info.target.start, info.target.finish)
+ , converter.packRange(uri, info.source.start, info.source.finish)
+ )
+ else
+ response[i] = converter.location(targetUri
+ , converter.packRange(targetUri, info.target.start, info.target.finish)
+ )
+ end
end
end
end
+ return response
end
- return response
-end)
+}
-proto.on('textDocument/references', function (params)
- workspace.awaitReady()
- local _ <close> = progress.create(lang.script.WINDOW_PROCESSING_REFERENCE, 0.5)
- local core = require 'core.reference'
- local uri = params.textDocument.uri
- if not files.exists(uri) then
- return nil
- end
- local pos = converter.unpackPosition(uri, params.position)
- local result = core(uri, pos)
- if not result then
- return nil
- end
- local response = {}
- for i, info in ipairs(result) do
- local targetUri = info.uri
- response[i] = converter.location(targetUri
- , converter.packRange(targetUri, info.target.start, info.target.finish)
- )
- end
- return response
-end)
-
-proto.on('textDocument/documentHighlight', function (params)
- local core = require 'core.highlight'
- local uri = params.textDocument.uri
- if not files.exists(uri) then
- return nil
- end
- local pos = converter.unpackPosition(uri, params.position)
- local result = core(uri, pos)
- if not result then
- return nil
- end
- local response = {}
- for _, info in ipairs(result) do
- response[#response+1] = {
- range = converter.packRange(uri, info.start, info.finish),
- kind = info.kind,
- }
+m.register 'textDocument/references' {
+ abortByFileUpdate = true,
+ ---@async
+ function (params)
+ workspace.awaitReady()
+ local _ <close> = progress.create(lang.script.WINDOW_PROCESSING_REFERENCE, 0.5)
+ local core = require 'core.reference'
+ local uri = params.textDocument.uri
+ if not files.exists(uri) then
+ return nil
+ end
+ local pos = converter.unpackPosition(uri, params.position)
+ local result = core(uri, pos)
+ if not result then
+ return nil
+ end
+ local response = {}
+ for i, info in ipairs(result) do
+ local targetUri = info.uri
+ response[i] = converter.location(targetUri
+ , converter.packRange(targetUri, info.target.start, info.target.finish)
+ )
+ end
+ return response
end
- return response
-end)
+}
-proto.on('textDocument/rename', function (params)
- workspace.awaitReady()
- local _ <close> = progress.create(lang.script.WINDOW_PROCESSING_RENAME, 0.5)
- local core = require 'core.rename'
- local uri = params.textDocument.uri
- if not files.exists(uri) then
- return nil
- end
- local pos = converter.unpackPosition(uri, params.position)
- local result = core.rename(uri, pos, params.newName)
- if not result then
- return nil
- end
- local workspaceEdit = {
- changes = {},
- }
- for _, info in ipairs(result) do
- local ruri = info.uri
- if not workspaceEdit.changes[ruri] then
- workspaceEdit.changes[ruri] = {}
- end
- local textEdit = converter.textEdit(converter.packRange(ruri, info.start, info.finish), info.text)
- workspaceEdit.changes[ruri][#workspaceEdit.changes[ruri]+1] = textEdit
- end
- return workspaceEdit
-end)
+m.register 'textDocument/documentHighlight' {
+ abortByFileUpdate = true,
+ function (params)
+ local core = require 'core.highlight'
+ local uri = params.textDocument.uri
+ if not files.exists(uri) then
+ return nil
+ end
+ local pos = converter.unpackPosition(uri, params.position)
+ local result = core(uri, pos)
+ if not result then
+ return nil
+ end
+ local response = {}
+ for _, info in ipairs(result) do
+ response[#response+1] = {
+ range = converter.packRange(uri, info.start, info.finish),
+ kind = info.kind,
+ }
+ end
+ return response
+ end
+}
-proto.on('textDocument/prepareRename', function (params)
- local core = require 'core.rename'
- local uri = params.textDocument.uri
- if not files.exists(uri) then
- return nil
- end
- local pos = converter.unpackPosition(uri, params.position)
- local result = core.prepareRename(uri, pos)
- if not result then
- return nil
- end
- return {
- range = converter.packRange(uri, result.start, result.finish),
- placeholder = result.text,
- }
-end)
+m.register 'textDocument/rename' {
+ abortByFileUpdate = true,
+ ---@async
+ function (params)
+ workspace.awaitReady()
+ local _ <close> = progress.create(lang.script.WINDOW_PROCESSING_RENAME, 0.5)
+ local core = require 'core.rename'
+ local uri = params.textDocument.uri
+ if not files.exists(uri) then
+ return nil
+ end
+ local pos = converter.unpackPosition(uri, params.position)
+ local result = core.rename(uri, pos, params.newName)
+ if not result then
+ return nil
+ end
+ local workspaceEdit = {
+ changes = {},
+ }
+ for _, info in ipairs(result) do
+ local ruri = info.uri
+ if not workspaceEdit.changes[ruri] then
+ workspaceEdit.changes[ruri] = {}
+ end
+ local textEdit = converter.textEdit(converter.packRange(ruri, info.start, info.finish), info.text)
+ workspaceEdit.changes[ruri][#workspaceEdit.changes[ruri]+1] = textEdit
+ end
+ return workspaceEdit
+ end
+}
-proto.on('textDocument/completion', function (params)
- local uri = params.textDocument.uri
- if not workspace.isReady() then
- local count, max = workspace.getLoadProcess()
+m.register 'textDocument/prepareRename' {
+ abortByFileUpdate = true,
+ function (params)
+ local core = require 'core.rename'
+ local uri = params.textDocument.uri
+ if not files.exists(uri) then
+ return nil
+ end
+ local pos = converter.unpackPosition(uri, params.position)
+ local result = core.prepareRename(uri, pos)
+ if not result then
+ return nil
+ end
return {
- {
- label = lang.script('HOVER_WS_LOADING', count, max),textEdit = {
- range = {
- start = params.position,
- ['end'] = params.position,
- },
- newText = '',
- },
- }
+ range = converter.packRange(uri, result.start, result.finish),
+ placeholder = result.text,
}
end
- local _ <close> = progress.create(lang.script.WINDOW_PROCESSING_COMPLETION, 0.5)
- --log.info(util.dump(params))
- local core = require 'core.completion'
- --log.debug('textDocument/completion')
- --log.debug('completion:', params.context and params.context.triggerKind, params.context and params.context.triggerCharacter)
- if not files.exists(uri) then
- return nil
- end
- local triggerCharacter = params.context and params.context.triggerCharacter
- if config.get 'editor.acceptSuggestionOnEnter' ~= 'off' then
- if triggerCharacter == '\n'
- or triggerCharacter == '{'
- or triggerCharacter == ',' then
- return
+}
+
+m.register 'textDocument/completion' {
+ ---@async
+ function (params)
+ local uri = params.textDocument.uri
+ if not workspace.isReady() then
+ local count, max = workspace.getLoadProcess()
+ return {
+ {
+ label = lang.script('HOVER_WS_LOADING', count, max),textEdit = {
+ range = {
+ start = params.position,
+ ['end'] = params.position,
+ },
+ newText = '',
+ },
+ }
+ }
end
- end
- await.setPriority(1000)
- local clock = os.clock()
- local pos = converter.unpackPosition(uri, params.position)
- local result = core.completion(uri, pos, triggerCharacter)
- local passed = os.clock() - clock
- if passed > 0.1 then
- log.warn(('Completion takes %.3f sec.'):format(passed))
- end
- if not result then
- return nil
- end
- tracy.ZoneBeginN 'completion make'
- local _ <close> = tracy.ZoneEnd
- local easy = false
- local items = {}
- for i, res in ipairs(result) do
- local item = {
- label = res.label,
- kind = res.kind,
- detail = res.detail,
- deprecated = res.deprecated,
- sortText = ('%04d'):format(i),
- filterText = res.filterText,
- insertText = res.insertText,
- insertTextFormat = 2,
- commitCharacters = res.commitCharacters,
- command = res.command,
- textEdit = res.textEdit and {
- range = converter.packRange(
- uri,
- res.textEdit.start,
- res.textEdit.finish
- ),
- newText = res.textEdit.newText,
- },
- additionalTextEdits = res.additionalTextEdits and (function ()
- local t = {}
- for j, edit in ipairs(res.additionalTextEdits) do
- t[j] = {
- range = converter.packRange(
- uri,
- edit.start,
- edit.finish
- ),
- newText = edit.newText,
- }
- end
- return t
- end)(),
- documentation = res.description and {
- value = tostring(res.description),
- kind = 'markdown',
- },
- }
- if res.id then
- if easy and os.clock() - clock < 0.05 then
- local resolved = core.resolve(res.id)
- if resolved then
- item.detail = resolved.detail
- item.documentation = resolved.description and {
- value = tostring(resolved.description),
- kind = 'markdown',
+ local _ <close> = progress.create(lang.script.WINDOW_PROCESSING_COMPLETION, 0.5)
+ --log.info(util.dump(params))
+ local core = require 'core.completion'
+ --log.debug('textDocument/completion')
+ --log.debug('completion:', params.context and params.context.triggerKind, params.context and params.context.triggerCharacter)
+ if not files.exists(uri) then
+ return nil
+ end
+ local triggerCharacter = params.context and params.context.triggerCharacter
+ if config.get 'editor.acceptSuggestionOnEnter' ~= 'off' then
+ if triggerCharacter == '\n'
+ or triggerCharacter == '{'
+ or triggerCharacter == ',' then
+ return
+ end
+ end
+ --await.setPriority(1000)
+ local clock = os.clock()
+ local pos = converter.unpackPosition(uri, params.position)
+ local result = core.completion(uri, pos, triggerCharacter)
+ local passed = os.clock() - clock
+ if passed > 0.1 then
+ log.warn(('Completion takes %.3f sec.'):format(passed))
+ end
+ if not result then
+ return nil
+ end
+ tracy.ZoneBeginN 'completion make'
+ local _ <close> = tracy.ZoneEnd
+ local easy = false
+ local items = {}
+ for i, res in ipairs(result) do
+ local item = {
+ label = res.label,
+ kind = res.kind,
+ detail = res.detail,
+ deprecated = res.deprecated,
+ sortText = ('%04d'):format(i),
+ filterText = res.filterText,
+ insertText = res.insertText,
+ insertTextFormat = 2,
+ commitCharacters = res.commitCharacters,
+ command = res.command,
+ textEdit = res.textEdit and {
+ range = converter.packRange(
+ uri,
+ res.textEdit.start,
+ res.textEdit.finish
+ ),
+ newText = res.textEdit.newText,
+ },
+ additionalTextEdits = res.additionalTextEdits and (function ()
+ local t = {}
+ for j, edit in ipairs(res.additionalTextEdits) do
+ t[j] = {
+ range = converter.packRange(
+ uri,
+ edit.start,
+ edit.finish
+ ),
+ newText = edit.newText,
+ }
+ end
+ return t
+ end)(),
+ documentation = res.description and {
+ value = tostring(res.description),
+ kind = 'markdown',
+ },
+ }
+ if res.id then
+ if easy and os.clock() - clock < 0.05 then
+ local resolved = core.resolve(res.id)
+ if resolved then
+ item.detail = resolved.detail
+ item.documentation = resolved.description and {
+ value = tostring(resolved.description),
+ kind = 'markdown',
+ }
+ end
+ else
+ easy = false
+ item.data = {
+ uri = uri,
+ id = res.id,
}
end
- else
- easy = false
- item.data = {
- uri = uri,
- id = res.id,
- }
end
+ items[i] = item
end
- items[i] = item
+ return {
+ isIncomplete = not result.complete,
+ items = items,
+ }
end
- return {
- isIncomplete = not result.complete,
- items = items,
- }
-end)
+}
-proto.on('completionItem/resolve', function (item)
- local core = require 'core.completion'
- if not item.data then
+m.register 'completionItem/resolve' {
+ ---@async
+ function (item)
+ local core = require 'core.completion'
+ if not item.data then
+ return item
+ end
+ local id = item.data.id
+ local uri = item.data.uri
+ --await.setPriority(1000)
+ local resolved = core.resolve(id)
+ if not resolved then
+ return nil
+ end
+ item.detail = resolved.detail or item.detail
+ item.documentation = resolved.description and {
+ value = tostring(resolved.description),
+ kind = 'markdown',
+ } or item.documentation
+ item.additionalTextEdits = resolved.additionalTextEdits and (function ()
+ local t = {}
+ for j, edit in ipairs(resolved.additionalTextEdits) do
+ t[j] = {
+ range = converter.packRange(
+ uri,
+ edit.start,
+ edit.finish
+ ),
+ newText = edit.newText,
+ }
+ end
+ return t
+ end)() or item.additionalTextEdits
return item
end
- local id = item.data.id
- local uri = item.data.uri
- --await.setPriority(1000)
- local resolved = core.resolve(id)
- if not resolved then
- return nil
- end
- item.detail = resolved.detail or item.detail
- item.documentation = resolved.description and {
- value = tostring(resolved.description),
- kind = 'markdown',
- } or item.documentation
- item.additionalTextEdits = resolved.additionalTextEdits and (function ()
- local t = {}
- for j, edit in ipairs(resolved.additionalTextEdits) do
- t[j] = {
- range = converter.packRange(
- uri,
- edit.start,
- edit.finish
- ),
- newText = edit.newText,
- }
- end
- return t
- end)() or item.additionalTextEdits
- return item
-end)
+}
-proto.on('textDocument/signatureHelp', function (params)
- if not config.get 'Lua.signatureHelp.enable' then
- return nil
- end
- workspace.awaitReady()
- local _ <close> = progress.create(lang.script.WINDOW_PROCESSING_SIGNATURE, 0.5)
- local uri = params.textDocument.uri
- if not files.exists(uri) then
- return nil
- end
- local pos = converter.unpackPosition(uri, params.position)
- local core = require 'core.signature'
- local results = core(uri, pos)
- if not results then
- return nil
- end
- local infos = {}
- for i, result in ipairs(results) do
- local parameters = {}
- for j, param in ipairs(result.params) do
- parameters[j] = {
- label = {
- param.label[1],
- param.label[2],
+m.register 'textDocument/signatureHelp' {
+ abortByFileUpdate = true,
+ ---@async
+ function (params)
+ if not config.get 'Lua.signatureHelp.enable' then
+ return nil
+ end
+ workspace.awaitReady()
+ local _ <close> = progress.create(lang.script.WINDOW_PROCESSING_SIGNATURE, 0.5)
+ local uri = params.textDocument.uri
+ if not files.exists(uri) then
+ return nil
+ end
+ local pos = converter.unpackPosition(uri, params.position)
+ local core = require 'core.signature'
+ local results = core(uri, pos)
+ if not results then
+ return nil
+ end
+ local infos = {}
+ for i, result in ipairs(results) do
+ local parameters = {}
+ for j, param in ipairs(result.params) do
+ parameters[j] = {
+ label = {
+ param.label[1],
+ param.label[2],
+ }
}
+ end
+ infos[i] = {
+ label = result.label,
+ parameters = parameters,
+ activeParameter = result.index - 1,
+ documentation = result.description and {
+ value = tostring(result.description),
+ kind = 'markdown',
+ },
}
end
- infos[i] = {
- label = result.label,
- parameters = parameters,
- activeParameter = result.index - 1,
- documentation = result.description and {
- value = tostring(result.description),
- kind = 'markdown',
- },
+ return {
+ signatures = infos,
}
end
- return {
- signatures = infos,
- }
-end)
+}
-proto.on('textDocument/documentSymbol', function (params)
- workspace.awaitReady()
- local _ <close> = progress.create(lang.script.WINDOW_PROCESSING_SYMBOL, 0.5)
- local core = require 'core.document-symbol'
- local uri = params.textDocument.uri
+m.register 'textDocument/documentSymbol' {
+ abortByFileUpdate = true,
+ ---@async
+ function (params)
+ workspace.awaitReady()
+ local _ <close> = progress.create(lang.script.WINDOW_PROCESSING_SYMBOL, 0.5)
+ local core = require 'core.document-symbol'
+ local uri = params.textDocument.uri
- local symbols = core(uri)
- if not symbols then
- return nil
- end
+ local symbols = core(uri)
+ if not symbols then
+ return nil
+ end
- local function convert(symbol)
- await.delay()
- symbol.range = converter.packRange(
- uri,
- symbol.range[1],
- symbol.range[2]
- )
- symbol.selectionRange = converter.packRange(
- uri,
- symbol.selectionRange[1],
- symbol.selectionRange[2]
- )
- if symbol.name == '' then
- symbol.name = lang.script.SYMBOL_ANONYMOUS
- end
- symbol.valueRange = nil
- if symbol.children then
- for _, child in ipairs(symbol.children) do
- convert(child)
+ ---@async
+ local function convert(symbol)
+ await.delay()
+ symbol.range = converter.packRange(
+ uri,
+ symbol.range[1],
+ symbol.range[2]
+ )
+ symbol.selectionRange = converter.packRange(
+ uri,
+ symbol.selectionRange[1],
+ symbol.selectionRange[2]
+ )
+ if symbol.name == '' then
+ symbol.name = lang.script.SYMBOL_ANONYMOUS
+ end
+ symbol.valueRange = nil
+ if symbol.children then
+ for _, child in ipairs(symbol.children) do
+ convert(child)
+ end
end
end
- end
-
- for _, symbol in ipairs(symbols) do
- convert(symbol)
- end
- return symbols
-end)
+ for _, symbol in ipairs(symbols) do
+ convert(symbol)
+ end
-proto.on('textDocument/codeAction', function (params)
- local core = require 'core.code-action'
- local uri = params.textDocument.uri
- local range = params.range
- local diagnostics = params.context.diagnostics
- if not files.exists(uri) then
- return nil
+ return symbols
end
+}
- local start, finish = converter.unpackRange(uri, range)
- local results = core(uri, start, finish, diagnostics)
+m.register 'textDocument/codeAction' {
+ abortByFileUpdate = true,
+ function (params)
+ local core = require 'core.code-action'
+ local uri = params.textDocument.uri
+ local range = params.range
+ local diagnostics = params.context.diagnostics
+ if not files.exists(uri) then
+ return nil
+ end
- if not results or #results == 0 then
- return nil
- end
+ local start, finish = converter.unpackRange(uri, range)
+ local results = core(uri, start, finish, diagnostics)
+
+ if not results or #results == 0 then
+ return nil
+ end
- for _, res in ipairs(results) do
- if res.edit then
- for turi, changes in pairs(res.edit.changes) do
- for _, change in ipairs(changes) do
- change.range = converter.packRange(turi, change.start, change.finish)
- change.start = nil
- change.finish = nil
+ for _, res in ipairs(results) do
+ if res.edit then
+ for turi, changes in pairs(res.edit.changes) do
+ for _, change in ipairs(changes) do
+ change.range = converter.packRange(turi, change.start, change.finish)
+ change.start = nil
+ change.finish = nil
+ end
end
end
end
- end
- return results
-end)
+ return results
+ end
+}
-proto.on('workspace/executeCommand', function (params)
- local command = params.command:gsub(':.+', '')
- if command == 'lua.removeSpace' then
- local core = require 'core.command.removeSpace'
- return core(params.arguments[1])
- elseif command == 'lua.solve' then
- local core = require 'core.command.solve'
- return core(params.arguments[1])
- elseif command == 'lua.jsonToLua' then
- local core = require 'core.command.jsonToLua'
- return core(params.arguments[1])
- elseif command == 'lua.setConfig' then
- local core = require 'core.command.setConfig'
- return core(params.arguments[1])
- elseif command == 'lua.autoRequire' then
- local core = require 'core.command.autoRequire'
- return core(params.arguments[1])
+m.register 'workspace/executeCommand' {
+ ---@async
+ function (params)
+ local command = params.command:gsub(':.+', '')
+ if command == 'lua.removeSpace' then
+ local core = require 'core.command.removeSpace'
+ return core(params.arguments[1])
+ elseif command == 'lua.solve' then
+ local core = require 'core.command.solve'
+ return core(params.arguments[1])
+ elseif command == 'lua.jsonToLua' then
+ local core = require 'core.command.jsonToLua'
+ return core(params.arguments[1])
+ elseif command == 'lua.setConfig' then
+ local core = require 'core.command.setConfig'
+ return core(params.arguments[1])
+ elseif command == 'lua.autoRequire' then
+ local core = require 'core.command.autoRequire'
+ return core(params.arguments[1])
+ end
end
-end)
+}
-proto.on('workspace/symbol', function (params)
- workspace.awaitReady()
- local _ <close> = progress.create(lang.script.WINDOW_PROCESSING_WS_SYMBOL, 0.5)
- local core = require 'core.workspace-symbol'
+m.register 'workspace/symbol' {
+ abortByFileUpdate = true,
+ ---@async
+ function (params)
+ workspace.awaitReady()
+ local _ <close> = progress.create(lang.script.WINDOW_PROCESSING_WS_SYMBOL, 0.5)
+ local core = require 'core.workspace-symbol'
- local symbols = core(params.query)
- if not symbols or #symbols == 0 then
- return nil
- end
+ local symbols = core(params.query)
+ if not symbols or #symbols == 0 then
+ return nil
+ end
- local function convert(symbol)
- symbol.location = converter.location(
- symbol.uri,
- converter.packRange(
+ local function convert(symbol)
+ symbol.location = converter.location(
symbol.uri,
- symbol.range[1],
- symbol.range[2]
+ converter.packRange(
+ symbol.uri,
+ symbol.range[1],
+ symbol.range[2]
+ )
)
- )
- symbol.uri = nil
- end
-
- for _, symbol in ipairs(symbols) do
- convert(symbol)
- end
+ symbol.uri = nil
+ end
- return symbols
-end)
+ for _, symbol in ipairs(symbols) do
+ convert(symbol)
+ end
-proto.on('textDocument/semanticTokens/full', function (params)
- local uri = params.textDocument.uri
- workspace.awaitReady()
- local _ <close> = progress.create(lang.script.WINDOW_PROCESSING_SEMANTIC_FULL, 0.5)
- local core = require 'core.semantic-tokens'
- local results = core(uri, 0, math.huge)
- return {
- data = results
- }
-end)
+ return symbols
+ end
+}
-proto.on('textDocument/semanticTokens/range', function (params)
- local uri = params.textDocument.uri
- workspace.awaitReady()
- local _ <close> = progress.create(lang.script.WINDOW_PROCESSING_SEMANTIC_RANGE, 0.5)
- local core = require 'core.semantic-tokens'
- local cache = files.getOpenedCache(uri)
- local start, finish
- if cache and not cache['firstSemantic'] then
- cache['firstSemantic'] = true
- start = 0
- finish = math.huge
- else
- start, finish = converter.unpackRange(uri, params.range)
+m.register 'textDocument/semanticTokens/full' {
+ abortByFileUpdate = true,
+ ---@async
+ function (params)
+ local uri = params.textDocument.uri
+ workspace.awaitReady()
+ local _ <close> = progress.create(lang.script.WINDOW_PROCESSING_SEMANTIC_FULL, 0.5)
+ local core = require 'core.semantic-tokens'
+ local results = core(uri, 0, math.huge)
+ return {
+ data = results
+ }
end
- local results = core(uri, start, finish)
- return {
- data = results
- }
-end)
+}
-proto.on('textDocument/foldingRange', function (params)
- local core = require 'core.folding'
- local uri = params.textDocument.uri
- if not files.exists(uri) then
- return nil
- end
- local regions = core(uri)
- if not regions then
- return nil
- end
-
- local results = {}
- for _, region in ipairs(regions) do
- local startLine = converter.packPosition(uri, region.start).line
- local endLine = converter.packPosition(uri, region.finish).line
- if not region.hideLastLine then
- endLine = endLine - 1
- end
- if startLine < endLine then
- results[#results+1] = {
- startLine = startLine,
- endLine = endLine,
- kind = region.kind,
- }
+m.register 'textDocument/semanticTokens/range' {
+ abortByFileUpdate = true,
+ ---@async
+ function (params)
+ local uri = params.textDocument.uri
+ workspace.awaitReady()
+ local _ <close> = progress.create(lang.script.WINDOW_PROCESSING_SEMANTIC_RANGE, 0.5)
+ local core = require 'core.semantic-tokens'
+ local cache = files.getOpenedCache(uri)
+ local start, finish
+ if cache and not cache['firstSemantic'] then
+ cache['firstSemantic'] = true
+ start = 0
+ finish = math.huge
+ else
+ start, finish = converter.unpackRange(uri, params.range)
end
+ local results = core(uri, start, finish)
+ return {
+ data = results
+ }
end
+}
- return results
-end)
+m.register 'textDocument/foldingRange' {
+ abortByFileUpdate = true,
+ ---@async
+ function (params)
+ local core = require 'core.folding'
+ local uri = params.textDocument.uri
+ if not files.exists(uri) then
+ return nil
+ end
+ local regions = core(uri)
+ if not regions then
+ return nil
+ end
-proto.on('window/workDoneProgress/cancel', function (params)
- progress.cancel(params.token)
-end)
+ local results = {}
+ for _, region in ipairs(regions) do
+ local startLine = converter.packPosition(uri, region.start).line
+ local endLine = converter.packPosition(uri, region.finish).line
+ if not region.hideLastLine then
+ endLine = endLine - 1
+ end
+ if startLine < endLine then
+ results[#results+1] = {
+ startLine = startLine,
+ endLine = endLine,
+ kind = region.kind,
+ }
+ end
+ end
-proto.on('$/didChangeVisibleRanges', function (params)
- local uri = params.uri
- await.close('visible:' .. uri)
- await.setID('visible:' .. uri)
- await.delay()
- files.setVisibles(uri, params.ranges)
-end)
+ return results
+ end
+}
-proto.on('$/status/click', function ()
- -- TODO: translate
- local titleDiagnostic = '进行工作区诊断'
- local result = client.awaitRequestMessage('Info', 'xxx', {
- titleDiagnostic,
- })
- if not result then
- return
+m.register 'window/workDoneProgress/cancel' {
+ function (params)
+ log.debug('close proto(cancel):', params.token)
+ progress.cancel(params.token)
end
- if result == titleDiagnostic then
- local diagnostic = require 'provider.diagnostic'
- diagnostic.diagnosticsAll(true)
+}
+
+m.register '$/didChangeVisibleRanges' {
+ ---@async
+ function (params)
+ local uri = params.uri
+ await.close('visible:' .. uri)
+ await.setID('visible:' .. uri)
+ await.delay()
+ files.setVisibles(uri, params.ranges)
end
-end)
+}
-proto.on('textDocument/onTypeFormatting', function (params)
- workspace.awaitReady()
- local _ <close> = progress.create(lang.script.WINDOW_PROCESSING_TYPE_FORMATTING, 0.5)
- local ch = params.ch
- local uri = params.textDocument.uri
- if not files.exists(uri) then
- return nil
- end
- local core = require 'core.type-formatting'
- local pos = converter.unpackPosition(uri, params.position)
- local edits = core(uri, pos, ch)
- if not edits or #edits == 0 then
- return nil
- end
- local tab = '\t'
- if params.options.insertSpaces then
- tab = (' '):rep(params.options.tabSize)
- end
- local results = {}
- for i, edit in ipairs(edits) do
- results[i] = {
- range = converter.packRange(uri, edit.start, edit.finish),
- newText = edit.text:gsub('\t', tab),
- }
+m.register '$/status/click' {
+ ---@async
+ function ()
+ -- TODO: translate
+ local titleDiagnostic = '进行工作区诊断'
+ local result = client.awaitRequestMessage('Info', 'xxx', {
+ titleDiagnostic,
+ })
+ if not result then
+ return
+ end
+ if result == titleDiagnostic then
+ local diagnostic = require 'provider.diagnostic'
+ diagnostic.diagnosticsAll(true)
+ end
end
- return results
-end)
+}
-proto.on('$/cancelRequest', function (params)
- proto.close(params.id, define.ErrorCodes.RequestCancelled)
-end)
+m.register 'textDocument/onTypeFormatting' {
+ abortByFileUpdate = true,
+ ---@async
+ function (params)
+ workspace.awaitReady()
+ local _ <close> = progress.create(lang.script.WINDOW_PROCESSING_TYPE_FORMATTING, 0.5)
+ local ch = params.ch
+ local uri = params.textDocument.uri
+ if not files.exists(uri) then
+ return nil
+ end
+ local core = require 'core.type-formatting'
+ local pos = converter.unpackPosition(uri, params.position)
+ local edits = core(uri, pos, ch)
+ if not edits or #edits == 0 then
+ return nil
+ end
+ local tab = '\t'
+ if params.options.insertSpaces then
+ tab = (' '):rep(params.options.tabSize)
+ end
+ local results = {}
+ for i, edit in ipairs(edits) do
+ results[i] = {
+ range = converter.packRange(uri, edit.start, edit.finish),
+ newText = edit.text:gsub('\t', tab),
+ }
+ end
+ return results
+ end
+}
-proto.on('$/requestHint', function (params)
- local core = require 'core.hint'
- if not config.get 'Lua.hint.enable' then
- return
+m.register '$/cancelRequest' {
+ function (params)
+ proto.close(params.id, define.ErrorCodes.RequestCancelled)
end
- workspace.awaitReady()
- local uri = params.textDocument.uri
- local start, finish = converter.unpackRange(uri, params.range)
- local results = core(uri, start, finish)
- local hintResults = {}
- for i, res in ipairs(results) do
- hintResults[i] = {
- text = res.text,
- pos = converter.packPosition(uri, res.offset),
- kind = res.kind,
- }
+}
+
+m.register '$/requestHint' {
+ ---@async
+ function (params)
+ local core = require 'core.hint'
+ if not config.get 'Lua.hint.enable' then
+ return
+ end
+ workspace.awaitReady()
+ local uri = params.textDocument.uri
+ local start, finish = converter.unpackRange(uri, params.range)
+ local results = core(uri, start, finish)
+ local hintResults = {}
+ for i, res in ipairs(results) do
+ hintResults[i] = {
+ text = res.text,
+ pos = converter.packPosition(uri, res.offset),
+ kind = res.kind,
+ }
+ end
+ return hintResults
end
- return hintResults
-end)
+}
-- Hint
do
+ ---@async
local function updateHint(uri)
if not config.get 'Lua.hint.enable' then
return
@@ -838,6 +960,10 @@ do
if not visibles then
return
end
+ await.close 'updateHint'
+ await.setID 'updateHint'
+ await.delay()
+ workspace.awaitReady()
local edits = {}
local hint = require 'core.hint'
local _ <close> = progress.create(lang.script.WINDOW_PROCESSING_HINT, 0.5)
@@ -862,7 +988,7 @@ do
files.watch(function (ev, uri)
if ev == 'update'
or ev == 'updateVisible' then
- await.call(function ()
+ await.call(function () ---@async
updateHint(uri)
end)
end
@@ -884,7 +1010,7 @@ config.watch(function (key, value)
end
end)
-proto.on('$/status/refresh', refreshStatusBar)
+m.register '$/status/refresh' { refreshStatusBar }
files.watch(function (ev, uri)
if not workspace.isReady() then
@@ -893,7 +1019,8 @@ files.watch(function (ev, uri)
if ev == 'update'
or ev == 'remove' then
for id, p in pairs(proto.holdon) do
- if p.params.textDocument and p.params.textDocument.uri == uri then
+ if m.attributes[p.method].abortByFileUpdate then
+ log.debug('close proto(ContentModified):', id, p.method)
proto.close(id, define.ErrorCodes.ContentModified)
end
end
diff --git a/script/pub/pub.lua b/script/pub/pub.lua
index ba57e5cb..fd780477 100644
--- a/script/pub/pub.lua
+++ b/script/pub/pub.lua
@@ -104,6 +104,7 @@ end
---@parma name string
---@param params any
---@return any
+---@async
function m.awaitTask(name, params)
local info = {
id = counter(),
diff --git a/script/service/telemetry.lua b/script/service/telemetry.lua
index 1ab3fdbe..dac72f3f 100644
--- a/script/service/telemetry.lua
+++ b/script/service/telemetry.lua
@@ -111,7 +111,7 @@ function m.updateConfig()
end
m.hasShowedMessage = true
- await.call(function ()
+ await.call(function () ---@async
local enableTitle = lang.script.WINDOW_TELEMETRY_ENABLE
local disableTitle = lang.script.WINDOW_TELEMETRY_DISABLE
local item = proto.awaitRequest('window/showMessageRequest', {
diff --git a/script/utility.lua b/script/utility.lua
index b5eb4095..85c98cb1 100644
--- a/script/utility.lua
+++ b/script/utility.lua
@@ -691,6 +691,7 @@ function m.switch()
return obj
end
+---@param f async fun()
function m.getUpvalue(f, name)
for i = 1, 999 do
local uname, value = getupvalue(f, i)
diff --git a/script/vm/eachDef.lua b/script/vm/eachDef.lua
index 2bfad4bf..ea14ed9f 100644
--- a/script/vm/eachDef.lua
+++ b/script/vm/eachDef.lua
@@ -1,4 +1,4 @@
----@type vm
+---@class vm
local vm = require 'vm.vm'
local searcher = require 'core.searcher'
diff --git a/script/vm/eachRef.lua b/script/vm/eachRef.lua
index 35425818..899c04c6 100644
--- a/script/vm/eachRef.lua
+++ b/script/vm/eachRef.lua
@@ -1,4 +1,4 @@
----@type vm
+---@class vm
local vm = require 'vm.vm'
local searcher = require 'core.searcher'
diff --git a/script/vm/getDocs.lua b/script/vm/getDocs.lua
index 2fb2bda9..3a0765bf 100644
--- a/script/vm/getDocs.lua
+++ b/script/vm/getDocs.lua
@@ -1,6 +1,6 @@
local files = require 'files'
local guide = require 'parser.guide'
----@type vm
+---@class vm
local vm = require 'vm.vm'
local config = require 'config'
local collector = require 'core.collector'
@@ -180,6 +180,140 @@ function vm.isDeprecated(value, deep)
end
end
+local function isAsync(value)
+ if value.type == 'function' then
+ if not value.bindDocs then
+ return false
+ end
+ if value._async ~= nil then
+ return value._async
+ end
+ for _, doc in ipairs(value.bindDocs) do
+ if doc.type == 'doc.async' then
+ value._async = true
+ return true
+ end
+ end
+ value._async = false
+ return false
+ end
+ return value.async == true
+end
+
+function vm.isAsync(value, deep)
+ if isAsync(value) then
+ return true
+ end
+ if deep then
+ local defs = vm.getDefs(value)
+ if #defs == 0 then
+ return false
+ end
+ for _, def in ipairs(defs) do
+ if isAsync(def) then
+ return true
+ end
+ end
+ end
+ return false
+end
+
+local function isNoDiscard(value)
+ if value.type == 'function' then
+ if not value.bindDocs then
+ return false
+ end
+ if value._nodiscard ~= nil then
+ return value._nodiscard
+ end
+ for _, doc in ipairs(value.bindDocs) do
+ if doc.type == 'doc.nodiscard' then
+ value._nodiscard = true
+ return true
+ end
+ end
+ value._nodiscard = false
+ return false
+ end
+ return false
+end
+
+function vm.isNoDiscard(value, deep)
+ if isNoDiscard(value) then
+ return true
+ end
+ if deep then
+ local defs = vm.getDefs(value)
+ if #defs == 0 then
+ return false
+ end
+ for _, def in ipairs(defs) do
+ if isNoDiscard(def) then
+ return true
+ end
+ end
+ end
+ return false
+end
+
+local function isCalledInFunction(param)
+ if not param.ref then
+ return false
+ end
+ local func = guide.getParentFunction(param)
+ for _, ref in ipairs(param.ref) do
+ if ref.type == 'getlocal' then
+ if ref.parent.type == 'call'
+ and guide.getParentFunction(ref) == func then
+ return true
+ end
+ if ref.parent.type == 'callargs'
+ and ref.parent[1] == ref
+ and guide.getParentFunction(ref) == func then
+ if ref.parent.parent.node.special == 'pcall'
+ or ref.parent.parent.node.special == 'xpcall' then
+ return true
+ end
+ end
+ end
+ end
+ return false
+end
+
+local function isLinkedCall(node, index)
+ for _, def in ipairs(vm.getDefs(node)) do
+ if def.type == 'function' then
+ local param = def.args and def.args[index]
+ if param then
+ if isCalledInFunction(param) then
+ return true
+ end
+ end
+ end
+ end
+ return false
+end
+
+function vm.isLinkedCall(node, index)
+ return isLinkedCall(node, index)
+end
+
+function vm.isAsyncCall(call)
+ if vm.isAsync(call.node, true) then
+ return true
+ end
+ if not call.args then
+ return
+ end
+ for i, arg in ipairs(call.args) do
+ if vm.isAsync(arg, true)
+ and isLinkedCall(call.node, i) then
+ return true
+ end
+ end
+ return false
+end
+
local function makeDiagRange(uri, doc, results)
local names
if doc.names then
diff --git a/script/vm/getGlobals.lua b/script/vm/getGlobals.lua
index 6dacda43..92fd1c8e 100644
--- a/script/vm/getGlobals.lua
+++ b/script/vm/getGlobals.lua
@@ -1,6 +1,6 @@
local collector = require 'core.collector'
local guide = require 'parser.guide'
----@type vm
+---@class vm
local vm = require 'vm.vm'
local noder = require 'core.noder'
diff --git a/script/vm/getLinks.lua b/script/vm/getLinks.lua
index d2332504..b245bdaa 100644
--- a/script/vm/getLinks.lua
+++ b/script/vm/getLinks.lua
@@ -1,5 +1,5 @@
local guide = require 'parser.guide'
----@type vm
+---@class vm
local vm = require 'vm.vm'
local files = require 'files'
diff --git a/script/vm/vm.lua b/script/vm/vm.lua
index 6abaaa0e..aa18ea73 100644
--- a/script/vm/vm.lua
+++ b/script/vm/vm.lua
@@ -14,7 +14,7 @@ local weakMT = { __mode = 'kv' }
_ENV = nil
----@type vm
+---@class vm
local m = {}
function m.getArgInfo(source)
diff --git a/script/workspace/require-path.lua b/script/workspace/require-path.lua
index 2ec2918c..e2149bac 100644
--- a/script/workspace/require-path.lua
+++ b/script/workspace/require-path.lua
@@ -27,7 +27,9 @@ local function getOnePath(path, searcher)
return nil
end
-function m.getVisiblePath(path, searchers, strict)
+function m.getVisiblePath(path)
+ local searchers = config.get 'Lua.runtime.path'
+ local strict = config.get 'Lua.runtime.pathStrict'
path = path:gsub('^[/\\]+', '')
local uri = furi.encode(path)
local libraryPath = files.getLibraryPath(uri)
@@ -91,7 +93,9 @@ files.watch(function (ev)
end)
config.watch(function (key, value, oldValue)
- if key == 'Lua.completion.requireSeparator' then
+ if key == 'Lua.completion.requireSeparator'
+ or key == 'Lua.runtime.path'
+ or key == 'Lua.runtime.pathStrict' then
m.flush()
end
end)
diff --git a/script/workspace/workspace.lua b/script/workspace/workspace.lua
index 240596a4..099196ce 100644
--- a/script/workspace/workspace.lua
+++ b/script/workspace/workspace.lua
@@ -74,6 +74,7 @@ local globInteferFace = {
}
--- 创建排除文件匹配器
+---@async
function m.getNativeMatcher()
if not m.path then
return nil
@@ -177,6 +178,7 @@ function m.getLibraryMatchers()
end
--- 文件是否被忽略
+---@async
function m.isIgnored(uri)
local path = m.getRelativePath(uri)
local ignore = m.getNativeMatcher()
@@ -186,6 +188,7 @@ function m.isIgnored(uri)
return ignore(path)
end
+---@async
function m.isValidLuaUri(uri)
if not files.isLua(uri) then
return false
@@ -198,7 +201,7 @@ function m.isValidLuaUri(uri)
end
local function loadFileFactory(root, progressData, isLibrary)
- return function (path)
+ return function (path) ---@async
local uri = furi.encode(path)
if files.isLua(uri) then
if not isLibrary and progressData.preload >= config.get 'Lua.workspace.maxPreload' then
@@ -246,7 +249,7 @@ local function loadFileFactory(root, progressData, isLibrary)
log.info('++++As library of:', root)
files.setLibraryPath(uri, root)
end
- files.setText(uri, text, false, true)
+ files.setText(uri, text, false)
else
files.remove(uri)
end
@@ -279,6 +282,7 @@ local function loadFileFactory(root, progressData, isLibrary)
end
end
+---@async
function m.awaitLoadFile(uri)
local progressBar <close> = progress.create(lang.script.WORKSPACE_LOADING)
local progressData = {
@@ -299,6 +303,7 @@ function m.awaitLoadFile(uri)
end
--- 预读工作区内所有文件
+---@async
function m.awaitPreload()
local diagnostic = require 'provider.diagnostic'
await.close 'preload'
@@ -347,7 +352,7 @@ function m.awaitPreload()
if isLoadingFiles then
return
end
- await.call(function ()
+ await.call(function () ---@async
isLoadingFiles = true
while true do
local loader = table.remove(progressData.loaders)
@@ -391,17 +396,22 @@ function m.findUrisByFilePath(path)
return resultCache[path].results, resultCache[path].posts
end
tracy.ZoneBeginN('findUrisByFilePath #1')
+ local strict = config.get 'Lua.runtime.pathStrict'
local results = {}
local posts = {}
for uri in files.eachFile() do
if not uri:find(lpath, 1, true) then
goto CONTINUE
end
+ local relat = m.getRelativePath(uri)
local pathLen = #path
- local curPath = furi.decode(uri)
+ local curPath = relat
local curLen = #curPath
local seg = curPath:sub(curLen - pathLen, curLen - pathLen)
if seg == '/' or seg == '\\' or seg == '' then
+ if strict and seg ~= '' then
+ goto CONTINUE
+ end
local see = curPath:sub(curLen - pathLen + 1, curLen)
if see == path then
results[#results+1] = uri
@@ -558,6 +568,7 @@ function m.init()
m.reload()
end
+---@async
function m.awaitReload()
m.ready = false
m.hasHitMaxPreload = false
@@ -575,6 +586,7 @@ function m.awaitReload()
end
---等待工作目录加载完成
+---@async
function m.awaitReady()
if m.isReady() then
return
@@ -592,7 +604,7 @@ function m.getLoadProcess()
return m.fileLoaded, m.fileFound
end
-files.watch(function (ev, uri)
+files.watch(function (ev, uri) ---@async
if ev == 'close'
and m.isIgnored(uri)
and not files.isLibrary(uri) then
@@ -610,7 +622,7 @@ config.watch(function (key, value, oldValue)
end
end)
-fw.event(function (changes)
+fw.event(function (changes) ---@async
m.awaitReady()
for _, change in ipairs(changes) do
local path = change.path
diff --git a/test/completion/common.lua b/test/completion/common.lua
index 73c6d7e6..15e2cc2a 100644
--- a/test/completion/common.lua
+++ b/test/completion/common.lua
@@ -1334,12 +1334,13 @@ end
]]
{
{
- label = 'a, b, c',
+ label = 'a, b, c, ...',
kind = define.CompletionItemKind.Snippet,
insertText = [[
a ${1:any}
---@param b ${2:any}
----@param c ${3:any}]],
+---@param c ${3:any}
+---@param ... ${4:any}]],
},
{
label = 'self',
@@ -1357,6 +1358,10 @@ a ${1:any}
label = 'c',
kind = define.CompletionItemKind.Interface,
},
+ {
+ label = '...',
+ kind = define.CompletionItemKind.Interface,
+ },
}
TEST [[
diff --git a/test/completion/init.lua b/test/completion/init.lua
index 58885149..11d39252 100644
--- a/test/completion/init.lua
+++ b/test/completion/init.lua
@@ -64,6 +64,7 @@ ContinueTyping = false
function TEST(script)
return function (expect)
+ ---@diagnostic disable: await-in-sync
files.removeAll()
local newScript, catched = catch(script, '?')
diff --git a/test/crossfile/completion.lua b/test/crossfile/completion.lua
index 172f9d6f..50ebad45 100644
--- a/test/crossfile/completion.lua
+++ b/test/crossfile/completion.lua
@@ -80,6 +80,7 @@ local function removeMetas(results)
util.tableMultiRemove(results, removes)
end
+---@diagnostic disable: await-in-sync
function TEST(data)
files.removeAll()
@@ -87,7 +88,7 @@ function TEST(data)
local pos
for _, info in ipairs(data) do
local uri = furi.encode(info.path)
- local script = info.content
+ local script = info.content or ''
if info.main then
local newScript, catched = catch(script, '?')
pos = catched['?'][1][1]
@@ -565,9 +566,115 @@ TEST {
]],
main = true,
},
+ completion = nil,
}
TEST {
+ { path = 'f/a.lua' },
+ { path = 'f/b.lua' },
+ {
+ path = 'c.lua',
+ content = [[
+ require '<??>'
+ ]],
+ main = true,
+ },
+ completion = {
+ {
+ label = 'a',
+ kind = CompletionItemKind.Reference,
+ textEdit = EXISTS,
+ },
+ {
+ label = 'b',
+ kind = CompletionItemKind.Reference,
+ textEdit = EXISTS,
+ },
+ {
+ label = 'f.a',
+ kind = CompletionItemKind.Reference,
+ textEdit = EXISTS,
+ },
+ {
+ label = 'f.b',
+ kind = CompletionItemKind.Reference,
+ textEdit = EXISTS,
+ },
+ }
+}
+
+TEST {
+ { path = 'f/a.lua' },
+ { path = 'f/b.lua' },
+ {
+ path = 'c.lua',
+ content = [[
+ require 'a<??>'
+ ]],
+ main = true,
+ },
+ completion = {
+ {
+ label = 'a',
+ kind = CompletionItemKind.Reference,
+ textEdit = EXISTS,
+ },
+ {
+ label = 'f.a',
+ kind = CompletionItemKind.Reference,
+ textEdit = EXISTS,
+ },
+ }
+}
+
+config.set('Lua.runtime.pathStrict', true)
+
+TEST {
+ { path = 'f/a.lua' },
+ { path = 'f/b.lua' },
+ {
+ path = 'c.lua',
+ content = [[
+ require '<??>'
+ ]],
+ main = true,
+ },
+ completion = {
+ {
+ label = 'f.a',
+ kind = CompletionItemKind.Reference,
+ textEdit = EXISTS,
+ },
+ {
+ label = 'f.b',
+ kind = CompletionItemKind.Reference,
+ textEdit = EXISTS,
+ },
+ }
+}
+
+TEST {
+ { path = 'f/a.lua' },
+ { path = 'f/b.lua' },
+ {
+ path = 'c.lua',
+ content = [[
+ require 'a<??>'
+ ]],
+ main = true,
+ },
+ completion = {
+ {
+ label = 'f.a',
+ kind = CompletionItemKind.Reference,
+ textEdit = EXISTS,
+ },
+ }
+}
+
+config.set('Lua.runtime.pathStrict', false)
+
+TEST {
{
path = 'xxx.lua',
content = ''
diff --git a/test/crossfile/definition.lua b/test/crossfile/definition.lua
index b233141c..058f5d18 100644
--- a/test/crossfile/definition.lua
+++ b/test/crossfile/definition.lua
@@ -117,6 +117,31 @@ TEST {
},
}
+config.set('Lua.runtime.pathStrict', true)
+TEST {
+ {
+ path = 'aaa/bbb.lua',
+ content = '',
+ },
+ {
+ path = 'b.lua',
+ content = 'require "<?bbb?>"',
+ },
+}
+
+TEST {
+ {
+ path = 'aaa/bbb.lua',
+ content = '<!!>',
+ },
+ {
+ path = 'b.lua',
+ content = 'require "<?aaa.bbb?>"',
+ },
+}
+
+config.set('Lua.runtime.pathStrict', false)
+
TEST {
{
path = 'a.lua',
diff --git a/test/crossfile/diagnostic.lua b/test/crossfile/diagnostic.lua
index 7735f4c5..c2d043f4 100644
--- a/test/crossfile/diagnostic.lua
+++ b/test/crossfile/diagnostic.lua
@@ -29,6 +29,7 @@ local function founded(targets, results)
return true
end
+---@diagnostic disable: await-in-sync
function TEST(datas)
files.removeAll()
diff --git a/test/crossfile/hover.lua b/test/crossfile/hover.lua
index 35528446..f23850a5 100644
--- a/test/crossfile/hover.lua
+++ b/test/crossfile/hover.lua
@@ -37,6 +37,7 @@ local function eq(a, b)
return a == b
end
+---@diagnostic disable: await-in-sync
function TEST(expect)
files.removeAll()
@@ -592,7 +593,7 @@ function f(arg1: integer, arg2: integer)
---
```lua
-function f()
+function f(arg3: any)
```]]}
diff --git a/test/definition/luadoc.lua b/test/definition/luadoc.lua
index 5f8c11ee..58c7c8fe 100644
--- a/test/definition/luadoc.lua
+++ b/test/definition/luadoc.lua
@@ -100,6 +100,11 @@ function f(<?...?>) end
]]
TEST [[
+---@param ... <!fun():void!>
+function f(<?...?>) end
+]]
+
+TEST [[
---@overload <!fun(y: boolean)!>
---@param x number
---@param y boolean
diff --git a/test/diagnostics/init.lua b/test/diagnostics/init.lua
index ab55cd92..558ffc26 100644
--- a/test/diagnostics/init.lua
+++ b/test/diagnostics/init.lua
@@ -4,8 +4,9 @@ local config = require 'config'
local util = require 'utility'
local catch = require 'catch'
-config.get 'Lua.diagnostics.neededFileStatus'['deprecated'] = 'Any'
-config.get 'Lua.diagnostics.neededFileStatus'['type-check'] = 'Any'
+config.get 'Lua.diagnostics.neededFileStatus'['deprecated'] = 'Any'
+config.get 'Lua.diagnostics.neededFileStatus'['type-check'] = 'Any'
+config.get 'Lua.diagnostics.neededFileStatus'['await-in-sync'] = 'Any'
rawset(_G, 'TEST', true)
@@ -25,6 +26,7 @@ local function founded(targets, results)
return true
end
+---@diagnostic disable: await-in-sync
function TEST(script, ...)
files.removeAll()
local newScript, catched = catch(script, '!')
@@ -304,7 +306,7 @@ Instance = _G[InstanceName]
]]
TEST [[
-(''):sub(1, 2)
+local _ = (''):sub(1, 2)
]]
TEST [=[
@@ -429,7 +431,7 @@ f(1, 2, 3, 4)
]]
TEST [[
-next({}, 1, <!2!>)
+local _ = next({}, 1, <!2!>)
print(1, 2, 3, 4, 5)
]]
@@ -461,7 +463,7 @@ f(1, 2, 3)
]]
TEST [[
-<!unpack!>()
+local _ = <!unpack!>()
]]
TEST [[
@@ -674,10 +676,10 @@ T = {}
T['x'], <!T['y']!>, <!T['z']!> = 1
]]
-TEST [[
----@class <!Class!>
----@class <!Class!>
-]]
+--TEST [[
+-----@class <!Class!>
+-----@class <!Class!>
+--]]
TEST [[
---@class A : <!B!>
@@ -718,7 +720,7 @@ TEST [[
]]
TEST [[
----@class <!A!>
+---@class A
---@class B
---@alias <!A B!>
]]
@@ -1348,12 +1350,159 @@ end
f()
]]
----TODO(arthur)
-do return end
-
TEST [[
---@type file*
local f
-f:read '*a'
-f:read('*a')
+local _ = f:read '*a'
+local _ = f:read('*a')
+]]
+
+TEST [[
+function F()
+ <!coroutine.yield!>()
+end
+]]
+
+TEST [[
+---@async
+function F()
+ coroutine.yield()
+end
+]]
+
+TEST [[
+---@type async fun()
+local f
+
+function F()
+ <!f!>()
+end
+]]
+
+TEST [[
+---@type async fun()
+local f
+
+---@async
+function F()
+ f()
+end
+]]
+
+TEST [[
+local function f(cb)
+ cb()
+end
+
+<!f!>(function () ---@async
+ return nil
+end)
+]]
+
+TEST [[
+local function f(cb)
+ pcall(cb)
+end
+
+<!f!>(function () ---@async
+ return nil
+end)
+]]
+
+TEST [[
+---@nodiscard
+local function f()
+ return 1
+end
+
+<!f()!>
+]]
+
+TEST [[
+---@nodiscard
+local function f()
+ return 1
+end
+
+X = f()
+]]
+
+config.get 'Lua.diagnostics.neededFileStatus'['not-yieldable'] = 'Any'
+TEST [[
+local function f(cb)
+ return cb
+end
+
+---@async
+local function af()
+ return nil
+end
+
+f(<!af!>)
+]]
+
+TEST [[
+---@param cb async fun()
+local function f(cb)
+ return cb
+end
+
+---@async
+local function af()
+ return nil
+end
+
+f(af)
+]]
+
+TEST [[
+local function f(cb)
+ cb()
+end
+
+local function af()
+ <!f!>(function () ---@async
+ return nil
+ end)
+end
+
+return af
+]]
+
+TEST [[
+local function f(cb)
+ cb()
+end
+
+---@async
+local function af()
+ f(function () ---@async
+ return nil
+ end)
+end
+
+return af
+]]
+
+TEST [[
+local _ = type(function () ---@async
+ return nil
+end)
+]]
+
+TEST [[
+---@param ... number
+local function f(...)
+ return ...
+end
+
+return f
+]]
+
+TEST [[
+---@type fun(...: string)
+]]
+
+TEST [[
+---@type fun(xxx, yyy, ...): boolean
]]
diff --git a/test/document_symbol/init.lua b/test/document_symbol/init.lua
index d3168197..1324f29c 100644
--- a/test/document_symbol/init.lua
+++ b/test/document_symbol/init.lua
@@ -45,6 +45,7 @@ local function checkArcoss(symbols)
end
end
+---@diagnostic disable: await-in-sync
function TEST(script)
return function (expect)
files.removeAll()
diff --git a/test/full/example.lua b/test/full/example.lua
index 20de5528..0505f1a5 100644
--- a/test/full/example.lua
+++ b/test/full/example.lua
@@ -8,6 +8,7 @@ local luadoc = require "parser.luadoc"
local noder = require 'core.noder'
-- 临时
+---@diagnostic disable: await-in-sync
local function testIfExit(path)
config.set('Lua.workspace.preloadFileSize', 1000000000)
local buf = util.loadFile(path:string())
diff --git a/test/full/projects.lua b/test/full/projects.lua
index b5523fed..a095f316 100644
--- a/test/full/projects.lua
+++ b/test/full/projects.lua
@@ -12,6 +12,7 @@ config.set('Lua.diagnostics.neededFileStatus', {
['not-yieldable'] = 'Any',
})
+---@diagnostic disable: await-in-sync
local function doProjects(pathname)
files.removeAll()
diff --git a/test/full/self.lua b/test/full/self.lua
index eae53b72..b2c74271 100644
--- a/test/full/self.lua
+++ b/test/full/self.lua
@@ -25,6 +25,7 @@ diag.start()
local clock = os.clock()
+---@diagnostic disable: await-in-sync
for uri in files.eachFile() do
local fileClock = os.clock()
diag.doDiagnostic(uri)
diff --git a/test/hover/init.lua b/test/hover/init.lua
index b3d675bb..15bf60d4 100644
--- a/test/hover/init.lua
+++ b/test/hover/init.lua
@@ -20,6 +20,7 @@ local accept = {
['function'] = true,
}
+---@diagnostic disable: await-in-sync
function TEST(script)
return function (expect)
files.removeAll()
@@ -245,7 +246,7 @@ TEST [[
<?print?>()
]]
[[
-function print(...)
+function print(...: any)
]]
TEST [[
@@ -299,7 +300,7 @@ end
<?x?>(1, 2, 3, 4, 5, 6, 7)
]]
[[
-function x(a: any, ...)
+function x(a: any, ...: any)
]]
TEST [[
@@ -1120,6 +1121,45 @@ local t: Class[]
]]
TEST [[
+---@class Class
+
+---@param ... Class
+local function f(...)
+ local _, <?x?> = ...
+end
+f(1, 2, 3)
+]]
+[[
+local x: Class
+]]
+
+TEST [[
+---@class Class
+
+---@param ... Class
+local function f(...)
+ local t = {...}
+ local <?v?> = t[1]
+end
+]]
+[[
+local v: Class
+]]
+
+TEST [[
+---@class Class
+
+---@param ... Class
+local function f(...)
+ local <?t?> = {...}
+end
+f(1, 2, 3)
+]]
+[[
+local t: Class[]
+]]
+
+TEST [[
---@type string[]
local <?x?>
]]
@@ -1456,7 +1496,7 @@ TEST [[
local function f(<?callback?>) end
]]
[[
-local callback: fun(x: integer, ...: nil)
+local callback: fun(x: integer, ...: any)
]]
TEST [[
@@ -1728,3 +1768,36 @@ local function <?f?>() end
function f()
-> nil
]]
+
+TEST [[
+---@async
+local function <?f?>() end
+]]
+[[
+async function f()
+]]
+
+TEST [[
+---@type function
+local <?f?>
+]]
+[[
+local f: function
+]]
+
+TEST [[
+---@type async fun()
+local <?f?>
+]]
+[[
+local f: async fun()
+]]
+
+config.set('Lua.runtime.nonstandardSymbol', { '//' })
+TEST [[
+local <?x?> = 1 // 2
+]]
+[[
+local x: integer = 1
+]]
+config.set('runtime.nonstandardSymbol', {})
diff --git a/test/signature/init.lua b/test/signature/init.lua
index 1dbe61e8..aa9d9094 100644
--- a/test/signature/init.lua
+++ b/test/signature/init.lua
@@ -4,6 +4,7 @@ local catch = require 'catch'
rawset(_G, 'TEST', true)
+---@diagnostic disable: await-in-sync
function TEST(script)
return function (expect)
local newScript, catched1 = catch(script, '?')
@@ -82,7 +83,7 @@ end
x(1, 2, 3, <??>
]]
-'function x(a: any, <!...!>)'
+'function x(a: any, <!...: any!>)'
TEST [[
(''):sub(<??>
diff --git a/test/type_inference/init.lua b/test/type_inference/init.lua
index 6d5a57dd..c76e372c 100644
--- a/test/type_inference/init.lua
+++ b/test/type_inference/init.lua
@@ -930,6 +930,11 @@ emit:on("died", function (<?i?>)
end)
]]
+TEST '👍' [[
+---@class 👍
+local <?x?>
+]]
+
TEST 'boolean' [[
---@type boolean
local x
diff --git a/tools/build-3rd-meta.lua b/tools/build-3rd-meta.lua
new file mode 100644
index 00000000..ab6b683e
--- /dev/null
+++ b/tools/build-3rd-meta.lua
@@ -0,0 +1,4 @@
+package.path = package.path .. ';script/?.lua;tools/?.lua'
+
+dofile 'tools/love-api.lua'
+dofile 'tools/lovr-api.lua'
diff --git a/tools/love-api.lua b/tools/love-api.lua
index 32ded033..90f43876 100644
--- a/tools/love-api.lua
+++ b/tools/love-api.lua
@@ -1,5 +1,4 @@
-
-package.path = package.path .. ';script/?.lua;tools/?.lua;3rd/love-api/?.lua'
+package.path = package.path .. ';3rd/love-api/?.lua'
local lua51 = require 'Lua51'
local api = lua51.require 'love_api'
diff --git a/tools/lovr-api.lua b/tools/lovr-api.lua
new file mode 100644
index 00000000..6bbc52b4
--- /dev/null
+++ b/tools/lovr-api.lua
@@ -0,0 +1,234 @@
+local fs = require 'bee.filesystem'
+local fsu = require 'fs-utility'
+
+local api = dofile('3rd/lovr-api/api/init.lua')
+
+local metaPath = fs.path 'meta/3rd/lovr'
+local libraryPath = metaPath / 'library'
+fs.create_directories(libraryPath)
+
+local knownTypes = {
+ ['nil'] = 'nil',
+ ['any'] = 'any',
+ ['boolean'] = 'boolean',
+ ['number'] = 'number',
+ ['integer'] = 'integer',
+ ['string'] = 'string',
+ ['table'] = 'table',
+ ['function'] = 'function',
+ ['userdata'] = 'userdata',
+ ['lightuserdata'] = 'lightuserdata',
+ ['thread'] = 'thread',
+ ['cdata'] = 'ffi.cdata*',
+ ['light userdata'] = 'lightuserdata',
+ ['Variant'] = 'any',
+}
+
+local function trim(name)
+ name = name:gsub('^%s+', '')
+ name = name:gsub('%s+$', '')
+ return name
+end
+
+---@param names string
+local function getTypeName(names)
+ if names == '*' then
+ return 'any'
+ end
+ local types = {}
+ names = names:gsub('%sor%s', '|')
+ for name in names:gmatch '[^|]+' do
+ name = trim(name)
+ types[#types+1] = knownTypes[name] or ('lovr.' .. name)
+ end
+ return table.concat(types, '|')
+end
+
+local function formatIndex(key)
+ if key:match '^[%a_][%w_]*$' then
+ return key
+ end
+ return ('[%q]'):format(key)
+end
+
+local buildType
+
+local function buildDocTable(tbl)
+ local fields = {}
+ for _, field in ipairs(tbl) do
+ if field.name ~= '...' then
+ fields[#fields+1] = ('%s: %s'):format(formatIndex(field.name), buildType(field))
+ end
+ end
+ return ('{%s}'):format(table.concat(fields, ', '))
+end
+
+function buildType(param)
+ if param.table then
+ return buildDocTable(param.table)
+ end
+ if param.type then
+ return getTypeName(param.type)
+ end
+ return 'any'
+end
+
+local function buildSuper(tp)
+ if not tp.supertypes then
+ return ''
+ end
+ local parents = {}
+ for _, parent in ipairs(tp.supertypes) do
+ parents[#parents+1] = getTypeName(parent)
+ end
+ return (': %s'):format(table.concat(parents, ', '))
+end
+
+local function buildDescription(desc)
+ if desc then
+ return ('---\n---%s\n---'):format(desc:gsub('([\r\n])', '%1---'))
+ else
+ return nil
+ end
+end
+
+local function buildDocFunc(variant)
+ local params = {}
+ local returns = {}
+ for _, param in ipairs(variant.arguments or {}) do
+ if param.name == '...' then
+ params[#params+1] = '...'
+ else
+ if param.name:find '^[\'"]' then
+ params[#params+1] = ('%s: %s|%q'):format(param.name:sub(2, -2), getTypeName(param.type), param.name)
+ else
+ params[#params+1] = ('%s: %s'):format(param.name, getTypeName(param.type))
+ end
+ end
+ end
+ for _, rtn in ipairs(variant.returns or {}) do
+ returns[#returns+1] = ('%s'):format(getTypeName(rtn.type))
+ end
+ return ('fun(%s)%s'):format(
+ table.concat(params, ', '),
+ #returns > 0 and (':' .. table.concat(returns, ', ')) or ''
+ )
+end
+
+local function buildMultiDocFunc(tp)
+ local cbs = {}
+ for _, variant in ipairs(tp.variants) do
+ cbs[#cbs+1] = buildDocFunc(variant)
+ end
+ return table.concat(cbs, '|')
+end
+
+local function buildFunction(func)
+ local text = {}
+ text[#text+1] = buildDescription(func.description)
+ for i = 2, #func.variants do
+ local variant = func.variants[i]
+ text[#text+1] = ('---@overload %s'):format(buildDocFunc(variant))
+ end
+ local params = {}
+ for _, param in ipairs(func.variants[1].arguments or {}) do
+ for paramName in param.name:gmatch '[%a_][%w_]*' do
+ params[#params+1] = paramName
+ text[#text+1] = ('---@param %s%s %s # %s'):format(
+ paramName,
+ param.default == nil and '' or '?',
+ buildType(param),
+ param.description
+ )
+ end
+ end
+ for _, rtn in ipairs(func.variants[1].returns or {}) do
+ for returnName in rtn.name:gmatch '[%a_][%w_]*' do
+ text[#text+1] = ('---@return %s %s # %s'):format(
+ buildType(rtn),
+ returnName,
+ rtn.description
+ )
+ end
+ end
+ text[#text+1] = ('function %s(%s) end'):format(
+ func.key,
+ table.concat(params, ', ')
+ )
+ return table.concat(text, '\n')
+end
+
+local function buildFile(defs)
+ local class = defs.key
+ local filePath = libraryPath / (class .. '.lua')
+ local text = {}
+
+ text[#text+1] = '---@meta'
+ text[#text+1] = ''
+ text[#text+1] = buildDescription(defs.description)
+ text[#text+1] = ('---@class %s'):format(class)
+ text[#text+1] = ('%s = {}'):format(class)
+
+ for _, func in ipairs(defs.functions or {}) do
+ text[#text+1] = ''
+ text[#text+1] = buildFunction(func)
+ end
+
+ for _, obj in ipairs(defs.objects or {}) do
+ local mark = {}
+ text[#text+1] = ''
+ text[#text+1] = buildDescription(obj.description)
+ text[#text+1] = ('---@class %s%s'):format(getTypeName(obj.name), buildSuper(obj))
+ text[#text+1] = ('local %s = {}'):format(obj.name)
+ for _, func in ipairs(obj.methods or {}) do
+ if not mark[func.name] then
+ mark[func.name] = true
+ text[#text+1] = ''
+ text[#text+1] = buildFunction(func)
+ end
+ end
+ end
+
+ for _, enum in ipairs(defs.enums or {}) do
+ text[#text+1] = ''
+ text[#text+1] = buildDescription(enum.description)
+ text[#text+1] = ('---@class %s'):format(getTypeName(enum.name))
+ for _, constant in ipairs(enum.values) do
+ text[#text+1] = buildDescription(constant.description)
+ text[#text+1] = ('---@field %s integer'):format(formatIndex(constant.name))
+ end
+ end
+
+ if defs.version then
+ text[#text+1] = ''
+ text[#text+1] = ('return %s'):format(class)
+ end
+
+ text[#text+1] = ''
+
+ fsu.saveFile(filePath, table.concat(text, '\n'))
+end
+
+local function buildCallback(defs)
+ local filePath = libraryPath / ('callback.lua')
+ local text = {}
+
+ text[#text+1] = '---@meta'
+
+ for _, cb in ipairs(defs.callbacks or {}) do
+ text[#text+1] = ''
+ text[#text+1] = buildDescription(cb.description)
+ text[#text+1] = ('---@type %s'):format(buildMultiDocFunc(cb))
+ text[#text+1] = ('%s = nil'):format(cb.key)
+ end
+
+ text[#text+1] = ''
+
+ fsu.saveFile(filePath, table.concat(text, '\n'))
+end
+
+buildCallback(api)
+
+for _, module in ipairs(api.modules) do
+ buildFile(module)
+end