Skip to content

lopi-py/luau-lsp.nvim

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

luau-lsp.nvim

A luau-lsp extension to improve your experience in neovim.

demo.mp4

Requirements

Installation

Use your favorite plugin manager to install luau-lsp.nvim

lazy.nvim
{
  "lopi-py/luau-lsp.nvim",
  opts = {
    ...
  },
  dependencies = {
    "nvim-lua/plenary.nvim",
  },
}
packer.nvim
use {
  "lopi-py/luau-lsp.nvim",
  config = function()
    require("luau-lsp").setup {
      ...
    }
  end,
  requires = {
    "nvim-lua/plenary.nvim",
  },
}

Quick start

Caution

lspconfig.luau_lsp.setup should NOT be called, it may cause conflicts with the plugin

require("luau-lsp").setup {
  ...
}

Using mason-lspconfig.nvim

require("mason-lspconfig").setup_handlers {
  luau_lsp = function()
    require("luau-lsp").setup {
      ...
    }
  end,
}

Roblox

Roblox types are downloaded from the luau-lsp repository and passed to the language server.

require("luau-lsp").setup {
  platform = {
    type = "roblox",
  },
  types = {
    roblox_security_level = "PluginSecurity",
  },
}

Rojo sourcemap

Sourcemap generation is done by running rojo sourcemap --watch default.project.json --output sourcemap.json.

require("luau-lsp").setup {
  sourcemap = {
    enabled = true,
    autogenerate = true, -- automatic generation when the server is attached
    rojo_project_file = "default.project.json",
  },
}

:LuauLsp regenerate_sourcemap {file} is provided to start sourcemap generation with the project file passed as argument (optional).

Companion plugin

You can install the companion plugin here.

require("luau-lsp").setup {
  plugin = {
    enabled = true,
    port = 3667,
  },
}

Definition files

require("luau-lsp").setup {
  types = {
    definition_files = { "path/to/definitions/file" },
    documentation_files = { "path/to/documentation/file" },
  },
}

Luau FFLags

require("luau-lsp").setup {
  fflags = {
    sync = true, -- sync currently enabled fflags with roblox's published fflags
    override = {
      LuauSolverV2 = "True", -- enable the new solver
    },
  },
}

Bytecode generation

:LuauLsp bytecode and :LuauLsp compiler_remarks open a new window and show the current Luau file bytecode and compiler remarks. It will automatically update if you change the file or edit it. Close with q.

bytecode.mp4

.luaurc aliases

The server is not able to read .luaurc aliases yet, but require("luau-lsp").aliases() can read .luaurc if it exists and returns a table containing the aliases with @.

.luaurc lookup order:

  1. .luaurc
  2. src/.luaurc
  3. lib/.luaurc
require("luau-lsp").setup {
  server = {
    settings = {
      ["luau-lsp"] = {
        require = {
          mode = "relativeToFile",
          directoryAliases = require("luau-lsp").aliases(),
        },
      },
    },
  },
}

Server configuration

require("luau-lsp").setup {
  server = {
    settings = {
      -- https://github.com/folke/neoconf.nvim/blob/main/schemas/luau_lsp.json
      ["luau-lsp"] = {
        completion = {
          imports = {
            enabled = true, -- enable auto imports
          },
        },
      },
    },
  },
}

Project configuration

Add the following to your .nvim.lua

require("luau-lsp").config {
  ...
}

For more info about .nvim.lua, check :help 'exrc'

Configuration

Defaults
---@alias luau-lsp.PlatformType "standard" | "roblox"
---@alias luau-lsp.RobloxSecurityLevel "None" | "LocalUserSecurity" | "PluginSecurity" | "RobloxScriptSecurity"

---@class luau-lsp.Config
local defaults = {
  platform = {
    ---@type luau-lsp.PlatformType
    type = "roblox",
  },
  sourcemap = {
    enabled = true,
    autogenerate = true,
    rojo_path = "rojo",
    rojo_project_file = "default.project.json",
    include_non_scripts = true,
  },
  types = {
    ---@type string[]
    definition_files = {},
    ---@type string[]
    documentation_files = {},
    ---@type luau-lsp.RobloxSecurityLevel
    roblox_security_level = "PluginSecurity",
  },
  fflags = {
    enable_by_default = false,
    sync = true,
    ---@type table<string, string>
    override = {},
  },
  plugin = {
    enabled = false,
    port = 3667,
  },
  ---@class luau-lsp.ClientConfig: vim.lsp.ClientConfig
  server = {
    ---@type string[]
    cmd = { "luau-lsp", "lsp" },
    ---@type fun(path: string): string?
    root_dir = function(path)
      return vim.fs.root(path, function(name)
        return name:match ".+%.project%.json$"
      end) or vim.fs.root(path, {
        ".git",
        ".luaurc",
        "stylua.toml",
        "selene.toml",
        "selene.yml",
      })
    end,
  },
}

Troubleshooting

Health checks

To verify the setup, run :checkhealth luau-lsp

Log file

To open the luau-lsp.nvim log file, run :LuauLsp log

FAQ

Why doesn't the server detect changes in the sourcemap?

Make sure to enable the file watcher capability and pass it in the server options

-- there are couple ways to get the default capabilities, it depends on your distribution or the completion plugin you are using
local capabilities = vim.lsp.protocol.make_client_capabilities()

-- example using nvim-cmp
capabilities = vim.tbl_deep_extend("force", capabilities, require("nvim_cmp_lsp").default_capabilities())

-- manually enable the file watcher capability so luau-lsp will know when the sourcemap changes
-- only needed if you are on Linux
capabilities.workspace.didChangeWatchedFiles.dynamicRegistration = true

require("luau-lsp").setup {
  server = {
    capabilities = capabilities,
  },
}

How to set the platform automatically?

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",
  },
}

How to use luau-lsp in a Roblox codebase using the .lua extension?

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,
    },
  }
end