A luau-lsp extension to improve your experience in Neovim.
demo.mp4
- Neovim 0.12+
- luau-lsp 1.60.0+ available on
$PATH, or configured withserver.path - Rojo 7.3.0+ for default sourcemap generation
Use your favorite plugin manager to install luau-lsp.nvim
lazy.nvim
{
"lopi-py/luau-lsp.nvim",
opts = {
...
},
}packer.nvim
use {
"lopi-py/luau-lsp.nvim",
config = function()
require("luau-lsp").setup {
...
}
end,
}Caution
lspconfig.luau_lsp.setup and vim.lsp.enable("luau_lsp") should NOT be called, as it might cause conflicts with this plugin
require("luau-lsp").setup {
...
}mason-lspconfig.nvim will try to automatically enable luau_lsp. To prevent this, make sure to exclude it:
require("mason-lspconfig").setup {
automatic_enable = {
exclude = { "luau_lsp" },
},
}Built-in Luau API documentation is downloaded automatically for standard projects.
require("luau-lsp").setup {
platform = {
type = "standard",
},
}Roblox types are downloaded from the luau-lsp page and passed to the language server.
require("luau-lsp").setup {
platform = {
type = "roblox",
},
types = {
roblox_security_level = "PluginSecurity",
},
}Sourcemap generation is done by running rojo sourcemap --watch --output sourcemap.json default.project.json --include-non-scripts by default.
require("luau-lsp").setup {
sourcemap = {
enabled = true,
autogenerate = true, -- automatic generation when the server is initialized
rojo_path = "rojo",
rojo_project_file = "default.project.json",
include_non_scripts = true,
sourcemap_file = "sourcemap.json",
},
}You can specify a custom generator command using sourcemap.generator_cmd. The command is run exactly as provided, so the Rojo-specific options do not affect it. The generator must write the file configured by sourcemap.sourcemap_file, which the language server watches for changes. This option is recommended for per-project configuration.
require("luau-lsp").setup {
sourcemap = {
-- based on https://argon.wiki/docs/commands/cli#sourcemap
generator_cmd = { "argon", "sourcemap", "--watch", "--non-scripts" },
},
}:LuauLsp regenerate_sourcemap is provided to restart sourcemap generation.
You can install the companion plugin here.
Native Script Sync file discovery requires fd or ripgrep (rg) to be available on $PATH.
require("luau-lsp").setup {
plugin = {
enabled = true,
port = 3667,
},
}require("luau-lsp").setup {
types = {
definition_files = {
["@foo"] = "path/to/definitions/file",
bar = "https://some.url/file.d.luau", -- @ will be added internally
},
documentation_files = { "path/to/documentation/file" },
},
}Remote definition and documentation files are cached for one day to avoid re-downloading them on every start. Run :LuauLsp refresh_types to ignore the cache and fetch fresh copies on demand.
require("luau-lsp").setup {
fflags = {
enable_by_default = false, -- start luau-lsp with --no-flags-enabled
enable_new_solver = true, -- enables the fflags required for luau's new type solver
sync = true, -- sync currently enabled fflags with roblox's published fflags
override = { -- override fflags passed to luau
LuauTableTypeMaximumStringifierLength = 100,
},
},
}:LuauLsp bytecode, :LuauLsp compiler_remarks, and :LuauLsp codegen open a new window and show compiler output for the current Luau file. CodeGen prompts for an assembly target after selecting the optimization level. The view automatically updates when you change or edit the file. Close it with q.
bytecode.mp4
:LuauLsp internal_source opens the source produced by Luau source-transform plugins in a nofile Luau buffer. The view updates when you edit the source or switch to another Luau file. Close it with q.
See :help vim.lsp.config
vim.lsp.config("luau-lsp", {
settings = {
["luau-lsp"] = {
completion = {
fillCallArguments = false, -- disable arguments snippets when completing a function call
},
},
},
})For full server options check the luau-lsp schema
require("luau-lsp").setup {
server = {
path = "path/to/luau-lsp", -- path to the luau-lsp server binary
base_luaurc = "path/to/.luaurc", -- path to a `.luaurc` file which acts as the default baseline luau config
},
}Add the following to your .nvim.lua
require("luau-lsp").config {
...
}For more info about .nvim.lua, check :help 'exrc'
Defaults
See lua/luau-lsp/config.lua for option types and validation.
local defaults = {
platform = {
type = "roblox",
},
sourcemap = {
enabled = true,
autogenerate = true,
rojo_path = "rojo",
rojo_project_file = "default.project.json",
include_non_scripts = true,
sourcemap_file = "sourcemap.json",
generator_cmd = nil,
},
types = {
definition_files = {},
documentation_files = {},
roblox_security_level = "PluginSecurity",
},
fflags = {
enable_by_default = false,
enable_new_solver = false,
sync = true,
override = {},
},
plugin = {
enabled = false,
port = 3667,
},
server = {
path = "luau-lsp",
base_luaurc = nil,
},
}To verify the setup, run :checkhealth luau-lsp
To open the luau-lsp.nvim log file, run :LuauLsp log
Make sure to enable the file watcher capability
vim.lsp.config("*", {
capabilities = {
workspace = {
didChangeWatchedFiles = {
dynamicRegistration = true,
},
},
},
})local function rojo_project()
return vim.fs.root(0, function(name)
return name:match ".+%.project%.json$"
end)
end
require("luau-lsp").setup {
platform = {
type = rojo_project() and "roblox" or "standard",
},
}local function rojo_project()
return vim.fs.root(0, function(name)
return name:match ".+%.project%.json$"
end)
end
if rojo_project() then
vim.filetype.add {
extension = {
lua = function(path)
return path:match "%.nvim%.lua$" and "lua" or "luau"
end,
},
}
endlocal schemas = {
{
name = "default.project.json",
description = "JSON schema for Rojo project files",
fileMatch = { "*.project.json" },
url = "https://raw.githubusercontent.com/rojo-rbx/vscode-rojo/master/schemas/project.template.schema.json",
},
}
vim.lsp.config("jsonls", {
settings = {
json = {
-- without SchemaStore.nvim
schemas = schemas,
-- or if using SchemaStore.nvim
-- schemas = require("schemastore").json.schemas { extra = schemas },
validate = {
enabled = true,
},
},
},
})