Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
10c2a63
Split Roblox-specific functionality into dedicated interface
voidedWarranties Nov 30, 2023
76e7aff
Merge branch 'main' of https://github.com/JohnnyMorganz/luau-lsp into…
JohnnyMorganz Dec 26, 2023
d3e5402
Fix frontend reference
JohnnyMorganz Dec 31, 2023
de6591f
Merge branch 'main' of https://github.com/JohnnyMorganz/luau-lsp into…
voidedWarranties Dec 31, 2023
901d216
Address initial review items
voidedWarranties Jan 1, 2024
a5319d2
Split RobloxPlatform into multiple files
voidedWarranties Jan 2, 2024
fbce308
Move some WorkspaceFileResolver functions into LSPPlatform
voidedWarranties Jan 6, 2024
9d762b7
Merge branch 'main' of https://github.com/JohnnyMorganz/luau-lsp into…
voidedWarranties Jan 6, 2024
77526ed
Fix MSVC build
voidedWarranties Jan 14, 2024
aff460b
Address review items
voidedWarranties Jan 20, 2024
9e72f06
Merge branch 'main' of https://github.com/JohnnyMorganz/luau-lsp into…
voidedWarranties Feb 23, 2024
63fdaf9
Initial extension split
voidedWarranties Feb 23, 2024
2a58485
Update extension config and config usage
voidedWarranties Feb 23, 2024
cfb8ba6
Merge branch 'main' of https://github.com/JohnnyMorganz/luau-lsp into…
voidedWarranties Apr 9, 2024
02ecb58
Resolve some issues
voidedWarranties Apr 9, 2024
7e16b8d
Merge branch 'main' of https://github.com/JohnnyMorganz/luau-lsp into…
JohnnyMorganz May 18, 2024
a60b248
Remove unused client config changes
JohnnyMorganz May 18, 2024
6b63e9a
Simplify readSourceCode
JohnnyMorganz May 18, 2024
de52f22
Merge branch 'main' into platform-specific-split
JohnnyMorganz May 19, 2024
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
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## [Unreleased]

### Deprecated

- Deprecated `luau-lsp.types.roblox` setting in favour of `luau-lsp.platform.platform`
- Deprecated `luau-lsp.completion.imports.suggestServices` setting in favour of `luau-lsp.platform.roblox.suggestServices`

### Added

- Added `luau-lsp.platform.platform` to separate platform-specific functionality from the main LSP

## [1.27.0] - 2023-12-25

### Added
Expand Down
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ target_sources(Luau.LanguageServer PRIVATE
src/LuauExt.cpp
src/IostreamHelpers.cpp
src/Utils.cpp
src/StudioPlugin.cpp
src/CliConfigurationParser.cpp
src/platform/LSPPlatform.cpp
src/platform/RobloxPlatform.cpp
src/operations/Diagnostics.cpp
src/operations/Completion.cpp
src/operations/DocumentSymbol.cpp
Expand Down
24 changes: 22 additions & 2 deletions editors/code/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,22 @@
],
"scope": "resource"
},
"luau-lsp.platform.platform": {
"markdownDescription": "Platform-specific support features",
"type": "string",
"enum": [
"vanilla",
"roblox"
],
"scope": "window",
"default": "roblox"
},
"luau-lsp.platform.roblox.suggestServices": {
"markdownDescription": "Whether `GetService` completions are suggested in autocomplete when `#luau-lsp.completion.imports.enabled#` is `true`",
"type": "boolean",
"default": true,
"scope": "resource"
},
"luau-lsp.sourcemap.enabled": {
"markdownDescription": "Whether Rojo sourcemap parsing is enabled",
"type": "boolean",
Expand Down Expand Up @@ -235,7 +251,9 @@
"scope": "window",
"tags": [
"usesOnlineServices"
]
],
"markdownDeprecationMessage": "**Deprecated**: Please use `#luau-lsp.platform.platform#` instead.",
"deprecationMessage": "Deprecated: Please use luau-lsp.platform.platform instead."
},
"luau-lsp.types.robloxSecurityLevel": {
"markdownDescription": "Security Level to use in the Roblox API definitions",
Expand Down Expand Up @@ -371,7 +389,9 @@
"markdownDescription": "Whether GetService completions are suggested in autocomplete",
"type": "boolean",
"default": true,
"scope": "resource"
"scope": "resource",
"markdownDeprecationMessage": "**Deprecated**: Please use `#luau-lsp.platform.roblox.suggestServices#` instead.",
"deprecationMessage": "Deprecated: Please use luau-lsp.platform.roblox.suggestServices instead."
},
"luau-lsp.completion.imports.suggestRequires": {
"markdownDescription": "Whether module requires are suggested in autocomplete",
Expand Down
12 changes: 8 additions & 4 deletions src/AnalyzeCli.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "Analyze/CliConfigurationParser.hpp"
#include "Analyze/CliClient.hpp"

#include "Platform/LSPPlatform.hpp"
#include "Luau/ModuleResolver.h"
#include "Luau/BuiltinDefinitions.h"
#include "Luau/Frontend.h"
Expand All @@ -14,6 +15,7 @@
#include "glob/glob.hpp"
#include <iostream>
#include <filesystem>
#include <memory>
#include <vector>

LUAU_FASTFLAG(DebugLuauTimeTracing)
Expand Down Expand Up @@ -256,6 +258,7 @@ int startAnalyze(const argparse::ArgumentParser& program)
}
}

std::unique_ptr<LSPPlatform> platform = LSPPlatform::getPlatform(client.configuration);

WorkspaceFileResolver fileResolver;
if (baseLuaurc)
Expand Down Expand Up @@ -308,8 +311,7 @@ int startAnalyze(const argparse::ArgumentParser& program)
return 1;
}

auto loadResult = types::registerDefinitions(frontend, frontend.globals, *definitionsContents, /* typeCheckForAutocomplete = */ false,
types::parseDefinitionsFileMetadata(*definitionsContents));
auto loadResult = types::registerDefinitions(frontend, frontend.globals, *definitionsContents, /* typeCheckForAutocomplete = */ false);
if (!loadResult.success)
{
fprintf(stderr, "Failed to load definitions\n");
Expand All @@ -329,10 +331,12 @@ int startAnalyze(const argparse::ArgumentParser& program)
}
return 1;
}

platform->handleRegisterDefinitions(frontend.globals, types::parseDefinitionsFileMetadata(*definitionsContents));
}

types::registerInstanceTypes(frontend, frontend.globals, frontend.globals.globalTypes, fileResolver,
!program.is_used("--no-strict-dm-types") && client.configuration.diagnostics.strictDatamodelTypes);
platform->handleSourcemapUpdate(
frontend, frontend.globals, fileResolver, !program.is_used("--no-strict-dm-types") && client.configuration.diagnostics.strictDatamodelTypes);

Luau::freeze(frontend.globals.globalTypes);
Luau::freeze(frontend.globalsForAutocomplete.globalTypes);
Expand Down
69 changes: 32 additions & 37 deletions src/LanguageServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@
if (!params) \
throw json_rpc::JsonRpcException(lsp::ErrorCode::InvalidParams, "params not provided for " method);

#define REQUIRED_PARAMS(params, method) \
(!(params) ? throw json_rpc::JsonRpcException(lsp::ErrorCode::InvalidParams, "params not provided for " method) : (params).value())

/// Finds the workspace which the file belongs to.
/// If no workspace is found, the file is attached to the null workspace
WorkspaceFolderPtr LanguageServer::findWorkspace(const lsp::DocumentUri& file)
Expand Down Expand Up @@ -123,71 +120,71 @@ void LanguageServer::onRequest(const id_type& id, const std::string& method, std

if (method == "initialize")
{
response = onInitialize(REQUIRED_PARAMS(baseParams, "initialize"));
response = onInitialize(JSON_REQUIRED_PARAMS(baseParams, "initialize"));
}
else if (method == "shutdown")
{
response = onShutdown(id);
}
else if (method == "textDocument/completion")
{
response = completion(REQUIRED_PARAMS(baseParams, "textDocument/completion"));
response = completion(JSON_REQUIRED_PARAMS(baseParams, "textDocument/completion"));
}
else if (method == "textDocument/documentLink")
{
response = documentLink(REQUIRED_PARAMS(baseParams, "textDocument/documentLink"));
response = documentLink(JSON_REQUIRED_PARAMS(baseParams, "textDocument/documentLink"));
}
else if (method == "textDocument/hover")
{
response = hover(REQUIRED_PARAMS(baseParams, "textDocument/hover"));
response = hover(JSON_REQUIRED_PARAMS(baseParams, "textDocument/hover"));
}
else if (method == "textDocument/signatureHelp")
{
response = signatureHelp(REQUIRED_PARAMS(baseParams, "textDocument/signatureHelp"));
response = signatureHelp(JSON_REQUIRED_PARAMS(baseParams, "textDocument/signatureHelp"));
}
else if (method == "textDocument/definition")
{
response = gotoDefinition(REQUIRED_PARAMS(baseParams, "textDocument/definition"));
response = gotoDefinition(JSON_REQUIRED_PARAMS(baseParams, "textDocument/definition"));
}
else if (method == "textDocument/typeDefinition")
{
response = gotoTypeDefinition(REQUIRED_PARAMS(baseParams, "textDocument/typeDefinition"));
response = gotoTypeDefinition(JSON_REQUIRED_PARAMS(baseParams, "textDocument/typeDefinition"));
}
else if (method == "textDocument/references")
{
response = references(REQUIRED_PARAMS(baseParams, "textDocument/references"));
response = references(JSON_REQUIRED_PARAMS(baseParams, "textDocument/references"));
}
else if (method == "textDocument/rename")
{
response = rename(REQUIRED_PARAMS(baseParams, "textDocument/rename"));
response = rename(JSON_REQUIRED_PARAMS(baseParams, "textDocument/rename"));
}
else if (method == "textDocument/documentSymbol")
{
response = documentSymbol(REQUIRED_PARAMS(baseParams, "textDocument/documentSymbol"));
response = documentSymbol(JSON_REQUIRED_PARAMS(baseParams, "textDocument/documentSymbol"));
}
else if (method == "textDocument/codeAction")
{
response = codeAction(REQUIRED_PARAMS(baseParams, "textDocument/codeAction"));
response = codeAction(JSON_REQUIRED_PARAMS(baseParams, "textDocument/codeAction"));
}
// else if (method == "codeAction/resolve")
// {
// response = codeActionResolve(REQUIRED_PARAMS(params, "codeAction/resolve"));
// response = codeActionResolve(JSON_REQUIRED_PARAMS(params, "codeAction/resolve"));
// }
else if (method == "textDocument/semanticTokens/full")
{
response = semanticTokens(REQUIRED_PARAMS(baseParams, "textDocument/semanticTokens/full"));
response = semanticTokens(JSON_REQUIRED_PARAMS(baseParams, "textDocument/semanticTokens/full"));
}
else if (method == "textDocument/inlayHint")
{
response = inlayHint(REQUIRED_PARAMS(baseParams, "textDocument/inlayHint"));
response = inlayHint(JSON_REQUIRED_PARAMS(baseParams, "textDocument/inlayHint"));
}
else if (method == "textDocument/documentColor")
{
response = documentColor(REQUIRED_PARAMS(baseParams, "textDocument/documentColor"));
response = documentColor(JSON_REQUIRED_PARAMS(baseParams, "textDocument/documentColor"));
}
else if (method == "textDocument/colorPresentation")
{
response = colorPresentation(REQUIRED_PARAMS(baseParams, "textDocument/colorPresentation"));
response = colorPresentation(JSON_REQUIRED_PARAMS(baseParams, "textDocument/colorPresentation"));
}
else if (method == "textDocument/prepareCallHierarchy")
{
Expand Down Expand Up @@ -219,13 +216,13 @@ void LanguageServer::onRequest(const id_type& id, const std::string& method, std
}
else if (method == "textDocument/diagnostic")
{
response = documentDiagnostic(REQUIRED_PARAMS(baseParams, "textDocument/diagnostic"));
response = documentDiagnostic(JSON_REQUIRED_PARAMS(baseParams, "textDocument/diagnostic"));
}
else if (method == "workspace/diagnostic")
{
// This request has partial request support.
// If workspaceDiagnostic returns nothing, then we don't signal a response (as data will be sent as progress notifications)
if (auto report = workspaceDiagnostic(REQUIRED_PARAMS(baseParams, "workspace/diagnostic")))
if (auto report = workspaceDiagnostic(JSON_REQUIRED_PARAMS(baseParams, "workspace/diagnostic")))
{
response = report;
}
Expand Down Expand Up @@ -287,11 +284,11 @@ void LanguageServer::onNotification(const std::string& method, std::optional<jso
}
else if (method == "initialized")
{
onInitialized(REQUIRED_PARAMS(params, "initialized"));
onInitialized(JSON_REQUIRED_PARAMS(params, "initialized"));
}
else if (method == "$/setTrace")
{
client->setTrace(REQUIRED_PARAMS(params, "$/setTrace"));
client->setTrace(JSON_REQUIRED_PARAMS(params, "$/setTrace"));
}
else if (method == "$/cancelRequest")
{
Expand All @@ -300,42 +297,40 @@ void LanguageServer::onNotification(const std::string& method, std::optional<jso
}
else if (method == "textDocument/didOpen")
{
onDidOpenTextDocument(REQUIRED_PARAMS(params, "textDocument/didOpen"));
onDidOpenTextDocument(JSON_REQUIRED_PARAMS(params, "textDocument/didOpen"));
}
else if (method == "textDocument/didChange")
{
onDidChangeTextDocument(REQUIRED_PARAMS(params, "textDocument/didChange"));
onDidChangeTextDocument(JSON_REQUIRED_PARAMS(params, "textDocument/didChange"));
}
else if (method == "textDocument/didSave")
{
// NO-OP
}
else if (method == "textDocument/didClose")
{
onDidCloseTextDocument(REQUIRED_PARAMS(params, "textDocument/didClose"));
onDidCloseTextDocument(JSON_REQUIRED_PARAMS(params, "textDocument/didClose"));
}
else if (method == "workspace/didChangeConfiguration")
{
onDidChangeConfiguration(REQUIRED_PARAMS(params, "workspace/didChangeConfiguration"));
onDidChangeConfiguration(JSON_REQUIRED_PARAMS(params, "workspace/didChangeConfiguration"));
}
else if (method == "workspace/didChangeWorkspaceFolders")
{
onDidChangeWorkspaceFolders(REQUIRED_PARAMS(params, "workspace/didChangeWorkspaceFolders"));
onDidChangeWorkspaceFolders(JSON_REQUIRED_PARAMS(params, "workspace/didChangeWorkspaceFolders"));
}
else if (method == "workspace/didChangeWatchedFiles")
{
onDidChangeWatchedFiles(REQUIRED_PARAMS(params, "workspace/didChangeWatchedFiles"));
}
else if (method == "$/plugin/full")
{
onStudioPluginFullChange(REQUIRED_PARAMS(params, "$/plugin/full"));
}
else if (method == "$/plugin/clear")
{
onStudioPluginClear();
onDidChangeWatchedFiles(JSON_REQUIRED_PARAMS(params, "workspace/didChangeWatchedFiles"));
}
else
{
for (auto& workspace : workspaceFolders)
{
if (workspace->platform && workspace->platform->handleNotification(method, params))
return;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if returning for the first workspace that matches is fine or if we should be sending the notification to all registered workspaces.

More of a note to self, I can check this.

}

client->sendLogMessage(lsp::MessageType::Warning, "unknown notification method: " + method);
}
}
Expand Down
Loading