-
Notifications
You must be signed in to change notification settings - Fork 48
Plugin
Plugins are a powerful feature that can be used to modify how the language server works.
- Create a .lua file for the plugin, you can create it anywhere.
- Set
robloxLsp.runtime.plugin
to the path of that file, you can use an absolute or relative path. - For better debugging, set
robloxLsp.develop.enable
totrue
, only use it while developing the plugin. - Define a global function in the plugin file with the name of an event, it will be called when the event triggers.
- Windows:
%homepath%\.vscode\extensions\nightrains.robloxlsp-X.X.X\
- WSL:
\\wsl$\Ubuntu-20.04\home\USERNAME\.vscode-server\extensions\nightrains.robloxlsp-X.X.X\
- Linux/MacOS:
~/.vscode/extensions/nightrains.robloxlsp-X.X.X/server/
Do not use print
, os.execute
or the io
library, check Useful API
below for alternative methods.
You can append ---@module path.to.file
above a variable to get IntelliSense from a module.
Changes the text that the language server reads from a file, called before parsing the text of a file into an Ast, must return a list of replacements or a string as a full replacement of the text.
Roblox LSP calculates the differences for offsetting the Ast to accommodate it to the original source text.
-- uri - The URI of the source file
-- text - The source text
function OnSetText(uri: string, text: string) -> string | {
{
-- The number of bytes at the beginning of the replacement
start: number,
-- The number of bytes at the end of the replacement
finish: number,
-- Text replacement
text: string
}
}
If robloxLsp.develop.enable
is enabled, the result or errors will the outputted to extension\server\log\diffed.lua
function OnSetText(uri, text)
local diffs = {}
for start, path, finish in text:gmatch("()import%(\"(.-)\"%)()") do
table.insert(diffs, {
start = start,
finish = finish - 1,
text = ("require(game.ReplicatedStorage.Libraries[\"%s\"])"):format(path),
})
end
return diffs
end
Called when triggering a completion suggestion, must return a list of completion items. Completion suggestions are cached and thus are not triggered every key stroke.
-- uri - The URI of the source file
-- text - The source text
-- offset - The position in bytes of the cursor
function OnCompletion(uri: string, text: string, offset: number) -> {CompletionItem}
CompletionItem
is a table following this format https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#completionItem
NOTE: The text
and offset
passed may be transformed by OnSetText
before OnCompletion
is called.
If robloxLsp.develop.enable
is enabled, errors will the outputted to extension\server\log\diffed.lua
function OnCompletion(uri, text, offset)
local items = {}
if text:sub(0, offset):match("createElement%(\"$") then
table.insert(items, {
kind = 13,
label = "Frame",
detail = "Insert Frame"
})
table.insert(items, {
kind = 13,
label = "TextButton",
detail = "Insert TextButton"
})
end
return items
end
Some useful functions when making a plugin, the full language server can be accessed via plugins.
Use local module = require("name")
Appends text to the log file for your workspace located at extension\server\log\
.
function log.debug(...: string) -> void
Sends a notification to the client, for specifications check: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/
You can use "window/logMessage"
to log directly to the output, check the specification here.
function proto.notify(method: string, params: table) -> void
Enums for CompletionItemKind
define.CompletionItemKind: {[string]: number}
Enums for MessageType
define.MessageType: {[string]: number}
Returns the text of a file, or nil if the file has not been loaded.
function files.getText(uri: string) -> string?
Same as files.getText
, but without the changes made by OnSetText
.
function files.getOriginText(uri: string) -> string?
Returns the AST of the file, or nil if the file has not been loaded.
function files.getAst(uri: string) -> Ast?
Returns a list of all lines in a string. Call it with a colon.
function parser:lines(text: string) -> {string}
Returns the row and column of a byte position in a string.
function parser.calcline.rowcol(text: string, position: number) -> (number, number)
Similar to Instance:IsA()
function rbxlibs.isA(className: string, otherClass: string) -> boolean
A set of all Roblox Instance class names.
rbxlibs.ClassNames: {[string]: true}
A set of all Roblox Services names
rbxlibs.Services: {[string]: true}
A set of all creatable instances class names.
rbxlibs.CreatableInstances: {[string]: true}
The full Roblox API Dump with DataTypes included.
rbxlibs.Api: table
Converts a table into a readable string.
function utility.dump(table: table) -> string
Returns the content of a file, or nil if the file doesn't exists.
function utility.loadFile(path: string | path) -> string?
Converts a path string into an URI
function uri.encode(path: string) -> string
Converts an URI into a path string.
function uri.decode(uri: string) -> string
Converts a JSON string into a table.
function json.decode(content: string) -> table
Converts a table into a JSON string.
function json.encode(table: table) -> string
A map of all scripts found in the rojo project, the format is the full name of the instance as the key, i.e. "ServerScriptService.Script", and the absolute path string of the source file as the value.
rojo.SourceMap: {[string]: string}
Returns the path to the rojo executable.
function rojo:getRojoPath() -> path | string
Returns the root path of the current workspace.
function fs.current_path() -> path
Creates a path object from a string.
function fs.path(path: string) -> path
Checks if a file/directory exists.
function fs.exists(path: path) -> boolean
Checks if a path points to a directory.
function fs.is_directory(path: path) -> boolean
Returns an iterator for the files inside a directory, similar to pairs
.
function fs.pairs(path: path) -> function
Gets the absolute path.
function fs.absolute(path: path) -> path
Gets the relative path to another path.
function fs.relative(path: path, base: path) -> path
Returns the name of the file/directory with the extension.
function path:filename() -> path
Returns the stem of the file (The name without the extension).
function path:stem() -> path
Returns the extension of the file.
function path:extension() -> path
Returns the path of the file/directory's parent.
function path:parent_path() -> path
Converts the path object into a string.
function path:__string() -> string
Returns the path with another path appended. Usage: local new = path / name
function path:__div(other: path | string) -> path
Opens a program in a separate process and returns a handle for reading/writing to the process's stdout/stdin/stderr. If fails returns nil and an error message.
It may not recognize the PATH env variable, in that case, you would have to manually find the executable using os.getenv("PATH")
and the bee.filesystem
library.
-- args - A table with the path of the executable followed by the arguments and optional fields.
function sp.spawn(
args: {
...string,
cwd: path?,
stdin: boolean?,
stdout: boolean?,
stderr: boolean?
}
) -> (process?, string)
Wait for the process, may yield indefinitely.
function process:wait() -> void
Kills the process.
function process:kill() -> void
A file handle to the stdout.
process.stdout: file
A file handle to the stdin.
process.stdin: file
A file handle to the stderr.
process.stderr: file
The file
object is the same as the one used by the standard io
library.
Most people won't need to use the AST or type inference, but if you want to make more complex or precise plugins, you have to look into core.guide to traverse the AST and vm for looking into the type inference. You may also use find-source.
The arguments for vm
are nodes of the AST. The most important functions are:
Returns a list of inferred types of an AstNode with the Luau type as a string and its source, including Luau types.
-- deep parameter must be 0
function vm.getInfers(source: AstNode, deep: number) -> {
{
type: string,
level: number,
source: AstNode | TypeDef
}
}
Returns a list of definitions in the AST or type definitions of an AstNode.
-- deep parameter must be 0
function vm.getDefs(source: AstNode, deep: number) -> {AstNode | TypeDef}
Returns a list of inferred fields AST definitions or type definitions of an AstNode.
-- deep parameter must be 0
function vm.getFields(source: AstNode, deep: number) -> {AstNode | TypeDef}
For checking the type of function returns, search the returns in the AstNode or the TypeDef of the function and use the functions above.
TypeDef
are Luau types in an AST-like structure.