Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for registering definition files #41

Merged
merged 1 commit into from
Jun 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

- Added predicate logic to `EnumItem:IsA("Type")` so it will now narrow the type of an EnumItem when used as a predicate
- Added setting to configure whether all Luau FFlags are enabled by default. This can be configured using `luau-lsp.fflags.enableByDefault` or `--no-flags-enabled` command line option. Currently, all FFlags are enabled by default, but you can manually sync/override them.
- Added support for adding extra definition files to load using `luau-lsp.types.definitionFiles`
- Roblox definitions can now be disabled using `luau-lsp.types.roblox`

### Changed

Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ Install the extension from the marketplace: https://marketplace.visualstudio.com
The langauge server should be immediately usable for general Luau code after installation.
String require support is provided for relative module paths, using `require("../module")`.

Type definitions can be provided by configuring `luau-lsp.types.definitionFiles`.

If there are specific features you require in the language server for your use case, feel free to open an issue.

### For Rojo Users

Rojo instance tree and requiring support is provided by default, and the language server should be able to directly emulate Studio.
The extension will automatically populate the latest API types and documentation.
The extension will automatically populate the latest API types and documentation (which can be disabled by configuring `luau-lsp.types.roblox`).

To resolve your instance tree and provide module resolution, the language server uses Rojo sourcemaps.
The language server will automatically create a `sourcemap.json` in your workspace root on startup and whenever files are added/created/renamed.
Expand Down
17 changes: 14 additions & 3 deletions editors/code/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 16 additions & 2 deletions editors/code/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,19 @@
"markdownDescription": "Compute diagnostics for the whole workspace",
"type": "boolean",
"default": false
},
"luau-lsp.types.definitionFiles": {
"markdownDescription": "A list of paths to definition files to load in to the type checker. Note that definition file syntax is currently unstable and may change at any time",
"type": "array",
"default": [],
"items": {
"type": "string"
}
},
"luau-lsp.types.roblox": {
"markdownDescription": "Load in and automatically update Roblox type definitions for the type checker",
"type": "boolean",
"default": true
}
}
}
Expand Down Expand Up @@ -157,6 +170,7 @@
},
"dependencies": {
"node-fetch": "^3.2.4",
"vscode-languageclient": "^7.0.0"
"vscode-languageclient": "^7.0.0",
"vscode-uri": "^3.0.3"
}
}
}
50 changes: 44 additions & 6 deletions editors/code/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
LanguageClientOptions,
} from "vscode-languageclient/node";
import { spawn } from "child_process";
import { Utils as UriUtils } from "vscode-uri";

const CURRENT_VERSION_TXT =
"https://raw.githubusercontent.com/CloneTrooper1019/Roblox-Client-Tracker/roblox/version.txt";
Expand Down Expand Up @@ -118,12 +119,38 @@ const getFFlags = async () => {
export async function activate(context: vscode.ExtensionContext) {
console.log("Luau LSP activated");

await updateApiInfo(context);
const args = [
`lsp`,
`--definitions=${globalTypesUri(context).fsPath}`,
`--docs=${apiDocsUri(context).fsPath}`,
];
const args = ["lsp"];

// Load roblox type definitions
const typesConfig = vscode.workspace.getConfiguration("luau-lsp.types");
if (typesConfig.get<boolean>("roblox")) {
await updateApiInfo(context);
args.push(`--definitions=${globalTypesUri(context).fsPath}`);
args.push(`--docs=${apiDocsUri(context).fsPath}`);
}

// Load extra type definitions
const definitionFiles = typesConfig.get<string[]>("definitionFiles");
if (definitionFiles) {
for (const definitionPath of definitionFiles) {
let uri;
if (vscode.workspace.workspaceFolders) {
uri = UriUtils.resolvePath(
vscode.workspace.workspaceFolders[0].uri,
definitionPath
);
} else {
uri = vscode.Uri.file(definitionPath);
}
if (await exists(uri)) {
args.push(`--definitions=${uri.fsPath}`);
} else {
vscode.window.showWarningMessage(
`Definitions file at ${definitionPath} does not exist, types will not be provided from this file`
);
}
}
}

// Handle FFlags
const fflags: FFlags = {};
Expand Down Expand Up @@ -314,6 +341,17 @@ export async function activate(context: vscode.ExtensionContext) {
vscode.commands.executeCommand("workbench.action.reloadWindow");
}
});
} else if (e.affectsConfiguration("luau-lsp.types")) {
vscode.window
.showInformationMessage(
"Luau type definitions have been changed, reload your workspace for this to take effect.",
"Reload Workspace"
)
.then((command) => {
if (command === "Reload Workspace") {
vscode.commands.executeCommand("workbench.action.reloadWindow");
}
});
}
})
);
Expand Down
23 changes: 13 additions & 10 deletions src/Workspace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1037,26 +1037,29 @@ void WorkspaceFolder::setup()
Luau::registerBuiltinTypes(frontend.typeChecker);
Luau::registerBuiltinTypes(frontend.typeCheckerForAutocomplete);

if (client->definitionsFile)
if (client->definitionsFiles.empty())
{
client->sendLogMessage(lsp::MessageType::Info, "Loading definitions file: " + client->definitionsFile->generic_string());
auto result = types::registerDefinitions(frontend.typeChecker, *client->definitionsFile);
types::registerDefinitions(frontend.typeCheckerForAutocomplete, *client->definitionsFile);
// TODO: should we disable this warning - maybe its sometimes not necessary if its vanilla Luau?
client->sendLogMessage(lsp::MessageType::Error, "Definitions file was not provided by the client. Extended types will not be provided");
client->sendWindowMessage(lsp::MessageType::Error, "Definitions file was not provided by the client. Extended types will not be provided");
}

for (auto definitionsFile : client->definitionsFiles)
{
client->sendLogMessage(lsp::MessageType::Info, "Loading definitions file: " + definitionsFile.generic_string());
auto result = types::registerDefinitions(frontend.typeChecker, definitionsFile);
types::registerDefinitions(frontend.typeCheckerForAutocomplete, definitionsFile);

if (!result.success)
{
client->sendWindowMessage(lsp::MessageType::Error, "Failed to read definitions file. Extended types will not be provided");
// TODO: Display diagnostics?
// TODO: Display diagnostics? We can't right now since this is currently called during initialisation, need to move
}
}
else
{
client->sendLogMessage(lsp::MessageType::Error, "Definitions file was not provided by the client. Extended types will not be provided");
client->sendWindowMessage(lsp::MessageType::Error, "Definitions file was not provided by the client. Extended types will not be provided");
}
Luau::freeze(frontend.typeChecker.globalTypes);
Luau::freeze(frontend.typeCheckerForAutocomplete.globalTypes);

// TODO: disable sourcemap lookup if not Roblox related
if (!isNullWorkspace() && !updateSourceMap())
{
client->sendWindowMessage(
Expand Down
2 changes: 1 addition & 1 deletion src/include/LSP/Client.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class Client
lsp::ClientCapabilities capabilities;
lsp::TraceValue traceMode = lsp::TraceValue::Off;
/// A registered definitions file passed by the client
std::optional<std::filesystem::path> definitionsFile = std::nullopt;
std::vector<std::filesystem::path> definitionsFiles;
/// A registered documentation file passed by the client
std::optional<std::filesystem::path> documentationFile = std::nullopt;
/// Parsed documentation database
Expand Down
4 changes: 2 additions & 2 deletions src/include/LSP/LanguageServer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ class LanguageServer
std::vector<WorkspaceFolderPtr> workspaceFolders;
ClientPtr client;

LanguageServer(std::optional<std::filesystem::path> definitionsFile, std::optional<std::filesystem::path> documentationFile)
LanguageServer(std::vector<std::filesystem::path> definitionsFiles, std::optional<std::filesystem::path> documentationFile)
: client(std::make_shared<Client>())
{
client->definitionsFile = definitionsFile;
client->definitionsFiles = definitionsFiles;
client->documentationFile = documentationFile;
parseDocumentation(documentationFile, client->documentation, client);
nullWorkspace = std::make_shared<WorkspaceFolder>(client, "$NULL_WORKSPACE", Uri());
Expand Down
6 changes: 3 additions & 3 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,21 +120,21 @@ int startLanguageServer(int argc, char** argv)
_setmode(_fileno(stdout), _O_BINARY);
#endif

std::optional<std::filesystem::path> definitionsFile;
std::vector<std::filesystem::path> definitionsFiles;
std::optional<std::filesystem::path> documentationFile;
for (int i = 1; i < argc; i++)
{
if (strncmp(argv[i], "--definitions=", 14) == 0)
{
definitionsFile = std::filesystem::path(argv[i] + 14);
definitionsFiles.emplace_back(argv[i] + 14);
}
else if (strncmp(argv[i], "--docs=", 7) == 0)
{
documentationFile = std::filesystem::path(argv[i] + 7);
}
}

LanguageServer server(definitionsFile, documentationFile);
LanguageServer server(definitionsFiles, documentationFile);

// Begin input loop
server.processInputLoop();
Expand Down