summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2024-10-27 14:27:52 -0700
committerGitHub <noreply@github.com>2024-10-27 14:27:52 -0700
commit1dd6ec26776081274604a94a96a1d87818830e82 (patch)
tree25b3a7d2df98cc152986b04725f61e69e1492b3a /source
parentfaa7d6ba4d73d8e3d89f083deea103afda456a21 (diff)
Export language server to wasm. (#5419)
Diffstat (limited to 'source')
-rw-r--r--source/compiler-core/slang-language-server-protocol.h30
-rw-r--r--source/slang-wasm/CMakeLists.txt11
-rw-r--r--source/slang-wasm/slang-wasm-bindings.cpp146
-rw-r--r--source/slang-wasm/slang-wasm.cpp310
-rw-r--r--source/slang-wasm/slang-wasm.h123
-rw-r--r--source/slang/slang-language-server-completion.cpp43
-rw-r--r--source/slang/slang-language-server-completion.h41
-rw-r--r--source/slang/slang-language-server.cpp422
-rw-r--r--source/slang/slang-language-server.h111
9 files changed, 1003 insertions, 234 deletions
diff --git a/source/compiler-core/slang-language-server-protocol.h b/source/compiler-core/slang-language-server-protocol.h
index ff5cd394e..506969dcc 100644
--- a/source/compiler-core/slang-language-server-protocol.h
+++ b/source/compiler-core/slang-language-server-protocol.h
@@ -6,6 +6,7 @@
#include "../../source/core/slang-rtti-info.h"
#include "../../source/compiler-core/slang-json-value.h"
+#include <optional>
namespace Slang
{
@@ -1124,3 +1125,32 @@ struct DocumentFormattingParams
} // namespace LanguageServerProtocol
} // namespace Slang
+
+namespace Slang
+{
+ template<typename T>
+ struct LanguageServerResult
+ {
+ SlangResult returnCode;
+ bool isNull = true;
+ T result;
+ LanguageServerResult()
+ {
+ returnCode = SLANG_OK;
+ }
+ LanguageServerResult(std::nullopt_t)
+ {
+ returnCode = SLANG_OK;
+ }
+ LanguageServerResult(const T& value)
+ {
+ result = value;
+ isNull = false;
+ returnCode = SLANG_OK;
+ }
+ LanguageServerResult(SlangResult code)
+ {
+ returnCode = code;
+ }
+ };
+}
diff --git a/source/slang-wasm/CMakeLists.txt b/source/slang-wasm/CMakeLists.txt
index d821415e7..75bbe3b69 100644
--- a/source/slang-wasm/CMakeLists.txt
+++ b/source/slang-wasm/CMakeLists.txt
@@ -9,7 +9,16 @@ if (EMSCRIPTEN)
EXECUTABLE
EXCLUDE_FROM_ALL
USE_FEWER_WARNINGS
- LINK_WITH_PRIVATE miniz lz4_static slang core compiler-core
+ LINK_WITH_PRIVATE
+ miniz
+ lz4_static
+ slang
+ core
+ compiler-core
+ slang-capability-defs
+ slang-capability-lookup
+ slang-reflect-headers
+ slang-lookup-tables
INCLUDE_DIRECTORIES_PUBLIC ${slang_SOURCE_DIR}/include .
)
# To generate binding code
diff --git a/source/slang-wasm/slang-wasm-bindings.cpp b/source/slang-wasm/slang-wasm-bindings.cpp
index d033f3846..360dec6eb 100644
--- a/source/slang-wasm/slang-wasm-bindings.cpp
+++ b/source/slang-wasm/slang-wasm-bindings.cpp
@@ -74,4 +74,150 @@ EMSCRIPTEN_BINDINGS(slang)
return_value_policy::take_ownership());
register_vector<slang::wgsl::ComponentType*>("ComponentTypeList");
+
+ register_vector<std::string>("StringList");
+ register_optional<std::vector<std::string>>();
+
+ value_object<slang::wgsl::lsp::Position>("Position")
+ .field("line", &slang::wgsl::lsp::Position::line)
+ .field("character", &slang::wgsl::lsp::Position::character);
+
+ value_object<slang::wgsl::lsp::Range>("Range")
+ .field("start", &slang::wgsl::lsp::Range::start)
+ .field("end", &slang::wgsl::lsp::Range::end);
+
+ value_object<slang::wgsl::lsp::Location>("Location")
+ .field("uri", &slang::wgsl::lsp::Location::uri)
+ .field("range", &slang::wgsl::lsp::Location::range);
+ register_vector<slang::wgsl::lsp::Location>("LocationList");
+ register_optional<std::vector<slang::wgsl::lsp::Location>>();
+
+ value_object<slang::wgsl::lsp::TextEdit>("TextEdit")
+ .field("range", &slang::wgsl::lsp::TextEdit::range)
+ .field("text", &slang::wgsl::lsp::TextEdit::text);
+ register_optional<slang::wgsl::lsp::TextEdit>();
+ register_vector<slang::wgsl::lsp::TextEdit>("TextEditList");
+ register_optional<std::vector<slang::wgsl::lsp::TextEdit>>();
+
+ value_object<slang::wgsl::lsp::MarkupContent>("MarkupContent")
+ .field("kind", &slang::wgsl::lsp::MarkupContent::kind)
+ .field("value", &slang::wgsl::lsp::MarkupContent::value);
+ register_optional<slang::wgsl::lsp::MarkupContent>();
+
+ value_object<slang::wgsl::lsp::Hover>("Hover")
+ .field("contents", &slang::wgsl::lsp::Hover::contents)
+ .field("range", &slang::wgsl::lsp::Hover::range);
+ register_optional<slang::wgsl::lsp::Hover>();
+
+ value_object<slang::wgsl::lsp::CompletionItem>("CompletionItem")
+ .field("label", &slang::wgsl::lsp::CompletionItem::label)
+ .field("kind", &slang::wgsl::lsp::CompletionItem::kind)
+ .field("detail", &slang::wgsl::lsp::CompletionItem::detail)
+ .field("documentation", &slang::wgsl::lsp::CompletionItem::documentation)
+ .field("textEdit", &slang::wgsl::lsp::CompletionItem::textEdit)
+ .field("data", &slang::wgsl::lsp::CompletionItem::data)
+ .field("commitCharacters", &slang::wgsl::lsp::CompletionItem::commitCharacters);
+ register_optional<slang::wgsl::lsp::CompletionItem>();
+ register_vector<slang::wgsl::lsp::CompletionItem>("CompletionItemList");
+ register_optional<std::vector<slang::wgsl::lsp::CompletionItem>>();
+
+ value_object<slang::wgsl::lsp::CompletionContext>("CompletionContext")
+ .field("triggerKind", &slang::wgsl::lsp::CompletionContext::triggerKind)
+ .field("triggerCharacter", &slang::wgsl::lsp::CompletionContext::triggerCharacter);
+
+ value_array<std::array<uint32_t, 2>>("array_uint_2")
+ .element(emscripten::index<0>())
+ .element(emscripten::index<1>());
+
+ value_object<slang::wgsl::lsp::ParameterInformation>("ParameterInformation")
+ .field("label", &slang::wgsl::lsp::ParameterInformation::label)
+ .field("documentation", &slang::wgsl::lsp::ParameterInformation::documentation);
+
+ register_vector<slang::wgsl::lsp::ParameterInformation>("ParameterInformationList");
+
+ value_object<slang::wgsl::lsp::SignatureInformation>("SignatureInformation")
+ .field("label", &slang::wgsl::lsp::SignatureInformation::label)
+ .field("documentation", &slang::wgsl::lsp::SignatureInformation::documentation)
+ .field("parameters", &slang::wgsl::lsp::SignatureInformation::parameters);
+
+ register_vector<slang::wgsl::lsp::SignatureInformation>("SignatureInformationList");
+
+ value_object<slang::wgsl::lsp::SignatureHelp>("SignatureHelp")
+ .field("signatures", &slang::wgsl::lsp::SignatureHelp::signatures)
+ .field("activeSignature", &slang::wgsl::lsp::SignatureHelp::activeSignature)
+ .field("activeParameter", &slang::wgsl::lsp::SignatureHelp::activeParameter);
+ register_optional<slang::wgsl::lsp::SignatureHelp>();
+
+ value_object<slang::wgsl::lsp::DocumentSymbol>("DocumentSymbol")
+ .field("name", &slang::wgsl::lsp::DocumentSymbol::name)
+ .field("detail", &slang::wgsl::lsp::DocumentSymbol::detail)
+ .field("kind", &slang::wgsl::lsp::DocumentSymbol::kind)
+ .field("range", &slang::wgsl::lsp::DocumentSymbol::range)
+ .field("selectionRange", &slang::wgsl::lsp::DocumentSymbol::selectionRange)
+ .field("children", &slang::wgsl::lsp::DocumentSymbol::children);
+
+ register_vector<slang::wgsl::lsp::DocumentSymbol>("DocumentSymbolList");
+ register_optional<std::vector<slang::wgsl::lsp::DocumentSymbol>>();
+
+ value_object<slang::wgsl::lsp::Diagnostics>("Diagnostics")
+ .field("code", &slang::wgsl::lsp::Diagnostics::code)
+ .field("range", &slang::wgsl::lsp::Diagnostics::range)
+ .field("severity", &slang::wgsl::lsp::Diagnostics::severity)
+ .field("message", &slang::wgsl::lsp::Diagnostics::message);
+ register_vector<slang::wgsl::lsp::Diagnostics>("DiagnosticsList");
+ register_optional<std::vector<slang::wgsl::lsp::Diagnostics>>();
+
+ register_vector<uint32_t>("Uint32List");
+ register_optional<std::vector<uint32_t>>();
+
+ class_<slang::wgsl::lsp::LanguageServer>("LanguageServer")
+ .function(
+ "didOpenTextDocument",
+ &slang::wgsl::lsp::LanguageServer::didOpenTextDocument,
+ allow_raw_pointers())
+ .function(
+ "didCloseTextDocument",
+ &slang::wgsl::lsp::LanguageServer::didCloseTextDocument,
+ allow_raw_pointers())
+ .function(
+ "didChangeTextDocument",
+ &slang::wgsl::lsp::LanguageServer::didChangeTextDocument,
+ allow_raw_pointers())
+ .function(
+ "hover",
+ &slang::wgsl::lsp::LanguageServer::hover,
+ allow_raw_pointers())
+ .function(
+ "gotoDefinition",
+ &slang::wgsl::lsp::LanguageServer::gotoDefinition,
+ allow_raw_pointers())
+ .function(
+ "completion",
+ &slang::wgsl::lsp::LanguageServer::completion,
+ allow_raw_pointers())
+ .function(
+ "completionResolve",
+ &slang::wgsl::lsp::LanguageServer::completionResolve,
+ allow_raw_pointers())
+ .function(
+ "semanticTokens",
+ &slang::wgsl::lsp::LanguageServer::semanticTokens,
+ allow_raw_pointers())
+ .function(
+ "signatureHelp",
+ &slang::wgsl::lsp::LanguageServer::signatureHelp,
+ allow_raw_pointers())
+ .function(
+ "documentSymbol",
+ &slang::wgsl::lsp::LanguageServer::documentSymbol,
+ allow_raw_pointers())
+ .function(
+ "getDiagnostics",
+ &slang::wgsl::lsp::LanguageServer::getDiagnostics,
+ allow_raw_pointers());
+
+ function(
+ "createLanguageServer",
+ &slang::wgsl::lsp::createLanguageServer,
+ return_value_policy::take_ownership());
}
diff --git a/source/slang-wasm/slang-wasm.cpp b/source/slang-wasm/slang-wasm.cpp
index 6fbe2dc6c..886efc5f7 100644
--- a/source/slang-wasm/slang-wasm.cpp
+++ b/source/slang-wasm/slang-wasm.cpp
@@ -5,6 +5,7 @@
#include "slang-wasm.h"
#include "../core/slang-blob.h"
#include "../core/slang-exception.h"
+#include "../slang/slang-language-server.h"
using namespace slang;
@@ -261,5 +262,314 @@ emscripten::val ComponentType::getEntryPointCodeSpirv(int entryPointIndex, int t
ptr));
}
+namespace lsp
+{
+ Position translate(Slang::LanguageServerProtocol::Position p)
+ {
+ Position result;
+ result.line = p.line;
+ result.character = p.character;
+ return result;
+ }
+ Range translate(Slang::LanguageServerProtocol::Range r)
+ {
+ Range result;
+ result.start = translate(r.start);
+ result.end = translate(r.end);
+ return result;
+ }
+ Location translate(Slang::LanguageServerProtocol::Location l)
+ {
+ Location result;
+ result.uri = l.uri.getBuffer();
+ result.range = translate(l.range);
+ return result;
+ }
+ Slang::LanguageServerProtocol::Position translate(Position p)
+ {
+ Slang::LanguageServerProtocol::Position result;
+ result.line = p.line;
+ result.character = p.character;
+ return result;
+ }
+ Slang::LanguageServerProtocol::Range translate(Range r)
+ {
+ Slang::LanguageServerProtocol::Range result;
+ result.start = translate(r.start);
+ result.end = translate(r.end);
+ return result;
+ }
+ Slang::LanguageServerProtocol::Location translate(Location l)
+ {
+ Slang::LanguageServerProtocol::Location result;
+ result.uri = l.uri.c_str();
+ result.range = translate(l.range);
+ return result;
+ }
+
+ LanguageServer::LanguageServer()
+ {
+ Slang::LanguageServerStartupOptions options = {};
+ m_core = new Slang::LanguageServerCore(options);
+ init();
+ }
+
+ LanguageServer::~LanguageServer()
+ {
+ delete m_core;
+ }
+
+ void LanguageServer::init()
+ {
+ Slang::LanguageServerProtocol::InitializeParams args = {};
+ Slang::LanguageServerProtocol::WorkspaceFolder folder = {};
+ folder.uri = "file:///";
+ folder.name = "/";
+ args.workspaceFolders.add(folder);
+ m_core->init(args);
+ }
+
+ void LanguageServer::didOpenTextDocument(std::string uri, std::string text)
+ {
+ Slang::LanguageServerProtocol::DidOpenTextDocumentParams args = {};
+ args.textDocument.uri = uri.c_str();
+ args.textDocument.languageId = "slang";
+ args.textDocument.text = text.c_str();
+ m_core->didOpenTextDocument(args);
+ }
+
+ void LanguageServer::didCloseTextDocument(std::string uri)
+ {
+ Slang::LanguageServerProtocol::DidCloseTextDocumentParams args = {};
+ args.textDocument.uri = uri.c_str();
+ m_core->didCloseTextDocument(args);
+ }
+
+ void LanguageServer::didChangeTextDocument(std::string uri, const std::vector<lsp::TextEdit>& changes)
+ {
+ Slang::LanguageServerProtocol::DidChangeTextDocumentParams args = {};
+ args.textDocument.uri = uri.c_str();
+ for (auto change : changes)
+ {
+ Slang::LanguageServerProtocol::TextDocumentContentChangeEvent lspChange;
+ lspChange.text = change.text.c_str();
+ lspChange.range = translate(change.range);
+ args.contentChanges.add(lspChange);
+ }
+ m_core->didChangeTextDocument(args);
+ }
+
+ std::optional<lsp::Hover> LanguageServer::hover(std::string uri, lsp::Position position)
+ {
+ Slang::LanguageServerProtocol::HoverParams args = {};
+ args.textDocument.uri = uri.c_str();
+ args.position = translate(position);
+ auto coreResult = m_core->hover(args);
+ if (coreResult.isNull)
+ return std::nullopt;
+ lsp::Hover result;
+ result.contents.kind = coreResult.result.contents.kind.getBuffer();
+ result.contents.value = coreResult.result.contents.value.getBuffer();
+ result.range = translate(coreResult.result.range);
+ return result;
+ }
+
+ std::optional<std::vector<lsp::Location>> LanguageServer::gotoDefinition(std::string uri, lsp::Position position)
+ {
+ Slang::LanguageServerProtocol::DefinitionParams args = {};
+ args.textDocument.uri = uri.c_str();
+ args.position = translate(position);
+ auto coreResult = m_core->gotoDefinition(args);
+ if (coreResult.isNull)
+ return std::nullopt;
+ std::vector<lsp::Location> result;
+ for (auto location : coreResult.result)
+ result.push_back(translate(location));
+ return result;
+ }
+
+ std::optional<std::vector<lsp::CompletionItem>> LanguageServer::completion(
+ std::string uri, lsp::Position position, CompletionContext context)
+ {
+ Slang::LanguageServerProtocol::CompletionParams args = {};
+ args.textDocument.uri = uri.c_str();
+ args.position = translate(position);
+ args.context.triggerKind = context.triggerKind;
+ args.context.triggerCharacter = context.triggerCharacter.c_str();
+ auto coreResult = m_core->completion(args);
+ if (coreResult.isNull)
+ return std::nullopt;
+ std::vector<lsp::CompletionItem> result;
+ for (auto item : coreResult.result.items)
+ {
+ lsp::CompletionItem completionItem;
+ completionItem.label = item.label.getBuffer();
+ completionItem.kind = item.kind;
+ completionItem.detail = item.detail.getBuffer();
+ MarkupContent documentation;
+ documentation.kind = item.documentation.kind.getBuffer();
+ documentation.value = item.documentation.value.getBuffer();
+ completionItem.documentation = documentation;
+ completionItem.textEdit = std::nullopt;
+ completionItem.data = item.data.getBuffer();
+ std::vector<std::string> commitCharacters;
+ for (auto character : item.commitCharacters)
+ commitCharacters.push_back(character.getBuffer());
+ completionItem.commitCharacters = commitCharacters;
+ result.push_back(completionItem);
+ }
+ return result;
+ }
+
+ std::optional<lsp::CompletionItem> LanguageServer::completionResolve(lsp::CompletionItem args)
+ {
+ Slang::LanguageServerProtocol::CompletionItem coreArgs = {};
+ coreArgs.label = args.label.c_str();
+ coreArgs.kind = args.kind;
+ coreArgs.detail = args.detail.c_str();
+ if (args.documentation.has_value())
+ {
+ coreArgs.documentation.kind = args.documentation.value().kind.c_str();
+ coreArgs.documentation.value = args.documentation.value().value.c_str();
+ }
+ coreArgs.data = args.data.c_str();
+ if (args.commitCharacters.has_value())
+ {
+ for (auto character : args.commitCharacters.value())
+ coreArgs.commitCharacters.add(character.c_str());
+ }
+ Slang::LanguageServerProtocol::TextEditCompletionItem editItem;
+ editItem.label = coreArgs.label;
+ editItem.kind = coreArgs.kind;
+ editItem.detail = coreArgs.detail;
+ editItem.documentation.kind = coreArgs.documentation.kind;
+ editItem.documentation.value = coreArgs.documentation.value;
+ editItem.data = coreArgs.data;
+ for (auto character : coreArgs.commitCharacters)
+ editItem.commitCharacters.add(character);
+ auto coreResult = m_core->completionResolve(coreArgs, editItem);
+ if (coreResult.isNull)
+ return std::nullopt;
+ lsp::CompletionItem result;
+ result.label = coreResult.result.label.getBuffer();
+ result.kind = coreResult.result.kind;
+ result.detail = coreResult.result.detail.getBuffer();
+ MarkupContent documentation;
+ documentation.kind = coreResult.result.documentation.kind.getBuffer();
+ documentation.value = coreResult.result.documentation.value.getBuffer();
+ result.documentation = documentation;
+ result.textEdit = std::nullopt;
+ result.data = coreResult.result.data.getBuffer();
+ std::vector<std::string> commitCharacters;
+ for (auto character : coreResult.result.commitCharacters)
+ commitCharacters.push_back(character.getBuffer());
+ result.commitCharacters = commitCharacters;
+ return result;
+ }
+
+ std::optional<std::vector<uint32_t>> LanguageServer::semanticTokens(std::string uri)
+ {
+ Slang::LanguageServerProtocol::SemanticTokensParams args = {};
+ args.textDocument.uri = uri.c_str();
+ auto coreResult = m_core->semanticTokens(args);
+ if (coreResult.isNull)
+ return std::nullopt;
+ std::vector<uint32_t> result;
+ result.reserve((size_t)coreResult.result.data.getCount());
+ for (auto token : coreResult.result.data)
+ result.push_back(token);
+ return result;
+ }
+
+ std::optional<lsp::SignatureHelp> LanguageServer::signatureHelp(std::string uri, lsp::Position position)
+ {
+ Slang::LanguageServerProtocol::SignatureHelpParams args = {};
+ args.textDocument.uri = uri.c_str();
+ args.position = translate(position);
+ auto coreResult = m_core->signatureHelp(args);
+ if (coreResult.isNull)
+ return std::nullopt;
+ lsp::SignatureHelp result;
+ for (auto signature : coreResult.result.signatures)
+ {
+ lsp::SignatureInformation signatureInfo;
+ signatureInfo.label = signature.label.getBuffer();
+ signatureInfo.documentation.kind = signature.documentation.kind.getBuffer();
+ signatureInfo.documentation.value = signature.documentation.value.getBuffer();
+ for (auto parameter : signature.parameters)
+ {
+ lsp::ParameterInformation parameterInfo;
+ parameterInfo.label[0] = parameter.label[0];
+ parameterInfo.label[1] = parameter.label[1];
+ parameterInfo.documentation.kind = parameter.documentation.kind.getBuffer();
+ parameterInfo.documentation.value = parameter.documentation.value.getBuffer();
+ signatureInfo.parameters.push_back(parameterInfo);
+ }
+ result.signatures.push_back(signatureInfo);
+ }
+ result.activeSignature = coreResult.result.activeSignature;
+ result.activeParameter = coreResult.result.activeParameter;
+ return result;
+ }
+
+ lsp::DocumentSymbol translate(Slang::LanguageServerProtocol::DocumentSymbol symbol)
+ {
+ lsp::DocumentSymbol result;
+ result.name = symbol.name.getBuffer();
+ result.detail = symbol.detail.getBuffer();
+ result.kind = symbol.kind;
+ result.range = translate(symbol.range);
+ result.selectionRange = translate(symbol.selectionRange);
+ for (auto child : symbol.children)
+ result.children.push_back(translate(child));
+ return result;
+ }
+
+ std::optional<std::vector<lsp::DocumentSymbol>> LanguageServer::documentSymbol(std::string uri)
+ {
+ Slang::LanguageServerProtocol::DocumentSymbolParams args = {};
+ args.textDocument.uri = uri.c_str();
+ auto coreResult = m_core->documentSymbol(args);
+ if (coreResult.isNull)
+ return std::nullopt;
+ std::vector<lsp::DocumentSymbol> result;
+ for (auto symbol : coreResult.result)
+ {
+ auto documentSymbol = translate(symbol);
+ result.push_back(documentSymbol);
+ }
+ return result;
+ }
+
+ std::optional<std::vector<lsp::Diagnostics>> LanguageServer::getDiagnostics(std::string uri)
+ {
+ std::vector<lsp::Diagnostics> result;
+ auto module = m_core->m_workspace->getCurrentVersion()->getOrLoadModule(
+ Slang::URI::fromString(Slang::UnownedStringSlice(uri.c_str())).getPath());
+ if (!module)
+ return std::nullopt;
+ for (auto& docDiag: m_core->m_workspace->getCurrentVersion()->diagnostics)
+ {
+ for (auto& message: docDiag.second.messages)
+ {
+ lsp::Diagnostics diag;
+ diag.code = Slang::String(message.code).getBuffer();
+ diag.range = translate(message.range);
+ diag.severity = (int)message.severity;
+ diag.message = message.message.getBuffer();
+ result.push_back(diag);
+ }
+ }
+ return result;
+ }
+
+
+ LanguageServer* createLanguageServer()
+ {
+ return new LanguageServer();
+ }
+
+}
+
} // namespace wgsl
} // namespace slang
diff --git a/source/slang-wasm/slang-wasm.h b/source/slang-wasm/slang-wasm.h
index a54cfe1ea..5a299453c 100644
--- a/source/slang-wasm/slang-wasm.h
+++ b/source/slang-wasm/slang-wasm.h
@@ -4,6 +4,11 @@
#include <unordered_map>
#include <emscripten/val.h>
+namespace Slang
+{
+ class LanguageServerCore;
+}
+
namespace slang
{
namespace wgsl
@@ -118,5 +123,123 @@ private:
GlobalSession* createGlobalSession();
+namespace lsp
+{
+ struct Position
+ {
+ int line = -1;
+ int character = -1;
+ };
+
+ struct Range
+ {
+ Position start;
+ Position end;
+ };
+
+ struct Location
+ {
+ std::string uri;
+ Range range;
+ };
+
+ struct TextEdit
+ {
+ Range range;
+ std::string text;
+ };
+
+ struct MarkupContent
+ {
+ std::string kind;
+ std::string value;
+ };
+
+ struct Hover
+ {
+ MarkupContent contents;
+ Range range;
+ };
+
+ struct CompletionItem
+ {
+ std::string label;
+ int kind;
+ std::string detail;
+ std::string data;
+ std::optional<MarkupContent> documentation;
+ std::optional<TextEdit> textEdit;
+ std::optional<std::vector<std::string>> commitCharacters;
+ };
+
+ struct CompletionContext
+ {
+ int triggerKind = 1;
+ std::string triggerCharacter;
+ };
+
+ struct ParameterInformation
+ {
+ uint32_t label[2] = { 0, 0 };
+ MarkupContent documentation;
+ };
+
+ struct SignatureInformation
+ {
+ std::string label;
+ MarkupContent documentation;
+ std::vector<ParameterInformation> parameters;
+ };
+
+ struct SignatureHelp
+ {
+ std::vector<SignatureInformation> signatures;
+ uint32_t activeSignature = 0;
+ uint32_t activeParameter = 0;
+ };
+
+ struct DocumentSymbol
+ {
+ std::string name;
+ std::string detail;
+ int kind = 0;
+ Range range;
+ Range selectionRange;
+ std::vector<DocumentSymbol> children;
+ };
+
+ struct Diagnostics
+ {
+ std::string code;
+ Range range;
+ std::string message;
+ int severity;
+ };
+
+ class LanguageServer
+ {
+ private:
+ Slang::LanguageServerCore* m_core = nullptr;
+ void init();
+ public:
+ LanguageServer();
+ ~LanguageServer();
+ void didOpenTextDocument(std::string uri, std::string text);
+ void didCloseTextDocument(std::string uri);
+ void didChangeTextDocument(std::string uri, const std::vector<lsp::TextEdit>& changes);
+ std::optional<lsp::Hover> hover(std::string uri, lsp::Position position);
+ std::optional<std::vector<lsp::Location>> gotoDefinition(std::string uri, lsp::Position position);
+ std::optional<std::vector<lsp::CompletionItem>> completion(
+ std::string uri, lsp::Position position, CompletionContext context);
+ std::optional<lsp::CompletionItem> completionResolve(lsp::CompletionItem args);
+ std::optional<std::vector<uint32_t>> semanticTokens(std::string uri);
+ std::optional<lsp::SignatureHelp> signatureHelp(std::string uri, lsp::Position position);
+ std::optional<std::vector<lsp::DocumentSymbol>> documentSymbol(std::string uri);
+ std::optional<std::vector<lsp::Diagnostics>> getDiagnostics(std::string uri);
+ };
+
+ LanguageServer* createLanguageServer();
+}
+
} // namespace wgsl
} // namespace slang
diff --git a/source/slang/slang-language-server-completion.cpp b/source/slang/slang-language-server-completion.cpp
index 14613d08b..074336ea6 100644
--- a/source/slang/slang-language-server-completion.cpp
+++ b/source/slang/slang-language-server-completion.cpp
@@ -84,7 +84,7 @@ bool isDeclKeyword(const UnownedStringSlice& slice)
return false;
}
-SlangResult CompletionContext::tryCompleteHLSLSemantic()
+LanguageServerResult<CompletionResult> CompletionContext::tryCompleteHLSLSemantic()
{
if (version->linkage->contentAssistInfo.completionSuggestions.scopeKind !=
CompletionSuggestions::ScopeKind::HLSLSemantics)
@@ -99,23 +99,20 @@ SlangResult CompletionContext::tryCompleteHLSLSemantic()
item.kind = LanguageServerProtocol::kCompletionItemKindKeyword;
items.add(item);
}
- server->m_connection->sendResult(&items, responseId);
- return SLANG_OK;
+ return CompletionResult(_Move(items));
}
-SlangResult CompletionContext::tryCompleteAttributes()
+LanguageServerResult<CompletionResult> CompletionContext::tryCompleteAttributes()
{
if (version->linkage->contentAssistInfo.completionSuggestions.scopeKind !=
CompletionSuggestions::ScopeKind::Attribute)
{
return SLANG_FAIL;
}
- List<LanguageServerProtocol::CompletionItem> items = collectAttributes();
- server->m_connection->sendResult(&items, responseId);
- return SLANG_OK;
+ return collectAttributes();
}
-List<LanguageServerProtocol::TextEditCompletionItem> CompletionContext::gatherFileAndModuleCompletionItems(
+CompletionResult CompletionContext::gatherFileAndModuleCompletionItems(
const String& prefixPath,
bool translateModuleName,
bool isImportString,
@@ -299,10 +296,10 @@ List<LanguageServerProtocol::TextEditCompletionItem> CompletionContext::gatherFi
}
}
}
- return context.items;
+ return CompletionResult(_Move(context.items));
}
-SlangResult CompletionContext::tryCompleteImport()
+LanguageServerResult<CompletionResult> CompletionContext::tryCompleteImport()
{
const char* prefixes[] = { "import ", "__include ", "implementing " };
UnownedStringSlice lineContent;
@@ -358,13 +355,11 @@ validLine:;
prefixSB.appendChar(ch);
}
auto prefix = prefixSB.produceString();
- auto items = gatherFileAndModuleCompletionItems(
+ return gatherFileAndModuleCompletionItems(
prefix, true, false, line - 1, fileNameEnd, lastPos + 1, sectionEnd, 0);
- server->m_connection->sendResult(&items, responseId);
- return SLANG_OK;
}
-SlangResult CompletionContext::tryCompleteRawFileName(UnownedStringSlice lineContent, Index pos, bool isImportString)
+LanguageServerResult<CompletionResult> CompletionContext::tryCompleteRawFileName(UnownedStringSlice lineContent, Index pos, bool isImportString)
{
while (pos < lineContent.getLength() && (lineContent[pos] != '\"' && lineContent[pos] != '<'))
pos++;
@@ -405,7 +400,7 @@ SlangResult CompletionContext::tryCompleteRawFileName(UnownedStringSlice lineCon
prefixSB.appendChar(ch);
}
auto prefix = prefixSB.produceString();
- auto items = gatherFileAndModuleCompletionItems(
+ return gatherFileAndModuleCompletionItems(
prefix,
false,
isImportString,
@@ -414,11 +409,9 @@ SlangResult CompletionContext::tryCompleteRawFileName(UnownedStringSlice lineCon
lastPos + 1,
sectionEnd,
closingChar);
- server->m_connection->sendResult(&items, responseId);
- return SLANG_OK;
}
-SlangResult CompletionContext::tryCompleteInclude()
+LanguageServerResult<CompletionResult> CompletionContext::tryCompleteInclude()
{
auto lineContent = doc->getLine(line);
if (!lineContent.startsWith("#"))
@@ -437,14 +430,12 @@ SlangResult CompletionContext::tryCompleteInclude()
return tryCompleteRawFileName(lineContent, pos, false);
}
-SlangResult CompletionContext::tryCompleteMemberAndSymbol()
+LanguageServerResult<CompletionResult> CompletionContext::tryCompleteMemberAndSymbol()
{
- List<LanguageServerProtocol::CompletionItem> items = collectMembersAndSymbols();
- server->m_connection->sendResult(&items, responseId);
- return SLANG_OK;
+ return collectMembersAndSymbols();
}
-List<LanguageServerProtocol::CompletionItem> CompletionContext::collectMembersAndSymbols()
+CompletionResult CompletionContext::collectMembersAndSymbols()
{
auto linkage = version->linkage;
if (linkage->contentAssistInfo.completionSuggestions.scopeKind ==
@@ -611,7 +602,7 @@ List<LanguageServerProtocol::CompletionItem> CompletionContext::collectMembersAn
return result;
}
-List<LanguageServerProtocol::CompletionItem> CompletionContext::createCapabilityCandidates()
+CompletionResult CompletionContext::createCapabilityCandidates()
{
List<LanguageServerProtocol::CompletionItem> result;
List<UnownedStringSlice> names;
@@ -629,7 +620,7 @@ List<LanguageServerProtocol::CompletionItem> CompletionContext::createCapability
return result;
}
-List<LanguageServerProtocol::CompletionItem> CompletionContext::createSwizzleCandidates(
+CompletionResult CompletionContext::createSwizzleCandidates(
Type* type, IntegerLiteralValue elementCount[2])
{
List<LanguageServerProtocol::CompletionItem> result;
@@ -738,7 +729,7 @@ LanguageServerProtocol::CompletionItem CompletionContext::generateGUIDCompletion
return resultItem;
}
-List<LanguageServerProtocol::CompletionItem> CompletionContext::collectAttributes()
+CompletionResult CompletionContext::collectAttributes()
{
List<LanguageServerProtocol::CompletionItem> result;
for (auto& item : version->linkage->contentAssistInfo.completionSuggestions.candidateItems)
diff --git a/source/slang/slang-language-server-completion.h b/source/slang/slang-language-server-completion.h
index d3910bcfd..0158a709f 100644
--- a/source/slang/slang-language-server-completion.h
+++ b/source/slang/slang-language-server-completion.h
@@ -3,10 +3,11 @@
#include "slang-workspace-version.h"
#include "slang-language-server-ast-lookup.h"
+#include "../compiler-core/slang-language-server-protocol.h"
namespace Slang
{
-class LanguageServer;
+class LanguageServerCore;
enum class CommitCharacterBehavior
{
@@ -15,34 +16,46 @@ enum class CommitCharacterBehavior
All
};
+struct CompletionResult
+{
+ List<LanguageServerProtocol::CompletionItem> items;
+ List<LanguageServerProtocol::TextEditCompletionItem> textEditItems;
+ CompletionResult() = default;
+ CompletionResult(List<LanguageServerProtocol::CompletionItem>&& other)
+ :items(_Move(other))
+ {}
+ CompletionResult(List<LanguageServerProtocol::TextEditCompletionItem>&& other)
+ :textEditItems(_Move(other))
+ {}
+};
+
struct CompletionContext
{
- LanguageServer* server;
+ LanguageServerCore* server;
Index cursorOffset;
WorkspaceVersion* version;
DocumentVersion* doc;
Module* parsedModule;
- JSONValue responseId;
UnownedStringSlice canonicalPath;
CommitCharacterBehavior commitCharacterBehavior;
Int line;
Int col;
- SlangResult tryCompleteMemberAndSymbol();
- SlangResult tryCompleteHLSLSemantic();
- SlangResult tryCompleteAttributes();
- SlangResult tryCompleteImport();
- SlangResult tryCompleteInclude();
- SlangResult tryCompleteRawFileName(UnownedStringSlice lineContent, Index fileNameStartPos, bool isImportString);
+ LanguageServerResult<CompletionResult> tryCompleteMemberAndSymbol();
+ LanguageServerResult<CompletionResult> tryCompleteHLSLSemantic();
+ LanguageServerResult<CompletionResult> tryCompleteAttributes();
+ LanguageServerResult<CompletionResult> tryCompleteImport();
+ LanguageServerResult<CompletionResult> tryCompleteInclude();
+ LanguageServerResult<CompletionResult> tryCompleteRawFileName(UnownedStringSlice lineContent, Index fileNameStartPos, bool isImportString);
- List<LanguageServerProtocol::CompletionItem> collectMembersAndSymbols();
- List<LanguageServerProtocol::CompletionItem> createSwizzleCandidates(
+ CompletionResult collectMembersAndSymbols();
+ CompletionResult createSwizzleCandidates(
Type* baseType, IntegerLiteralValue elementCount[2]);
- List<LanguageServerProtocol::CompletionItem> createCapabilityCandidates();
- List<LanguageServerProtocol::CompletionItem> collectAttributes();
+ CompletionResult createCapabilityCandidates();
+ CompletionResult collectAttributes();
LanguageServerProtocol::CompletionItem generateGUIDCompletionItem();
- List<LanguageServerProtocol::TextEditCompletionItem> gatherFileAndModuleCompletionItems(
+ CompletionResult gatherFileAndModuleCompletionItems(
const String& prefixPath,
bool translateModuleName,
bool isImportString,
diff --git a/source/slang/slang-language-server.cpp b/source/slang/slang-language-server.cpp
index 94debde40..80d9c2ef8 100644
--- a/source/slang/slang-language-server.cpp
+++ b/source/slang/slang-language-server.cpp
@@ -30,6 +30,9 @@
#include "slang-mangle.h"
#include "../../tools/platform/performance-counter.h"
+#define SLANG_LS_RETURN_ON_SUCCESS(x) { auto _res = (x); if (_res.returnCode == SLANG_OK) return _res; }
+#define SLANG_LS_RETURN_ON_FAIL(x) { auto _res = (x); if (SLANG_FAILED(_res.returnCode)) return _res; }
+
namespace Slang
{
using namespace LanguageServerProtocol;
@@ -42,12 +45,8 @@ ArrayView<const char*> getCommitChars()
return makeArrayView(_commitCharsArray, SLANG_COUNT_OF(_commitCharsArray));
}
-SlangResult LanguageServer::init(const InitializeParams& args)
+SlangResult LanguageServerCore::init(const InitializeParams& args)
{
- SLANG_RETURN_ON_FAIL(m_connection->initWithStdStreams(JSONRPCConnection::CallStyle::Object));
-
- m_typeMap = JSONNativeUtil::getTypeFuncsMap();
-
m_workspaceFolders = args.workspaceFolders;
m_workspace = new Workspace();
List<URI> rootUris;
@@ -59,7 +58,16 @@ SlangResult LanguageServer::init(const InitializeParams& args)
return SLANG_OK;
}
-slang::IGlobalSession* LanguageServer::getOrCreateGlobalSession()
+SlangResult LanguageServer::init(const InitializeParams& args)
+{
+ SLANG_RETURN_ON_FAIL(m_connection->initWithStdStreams(JSONRPCConnection::CallStyle::Object));
+
+ m_typeMap = JSONNativeUtil::getTypeFuncsMap();
+
+ return m_core.init(args);
+}
+
+slang::IGlobalSession* LanguageServerCore::getOrCreateGlobalSession()
{
if (!m_session)
{
@@ -146,7 +154,7 @@ SlangResult LanguageServer::parseNextMessage()
serverInfo.name = "SlangLanguageServer";
serverInfo.version = "1.8";
- if (m_options.isVisualStudio)
+ if (m_core.m_options.isVisualStudio)
{
VSInitializeResult vsResult;
vsResult.serverInfo = serverInfo;
@@ -220,13 +228,18 @@ SlangResult LanguageServer::parseNextMessage()
}
}
-SlangResult LanguageServer::didOpenTextDocument(const DidOpenTextDocumentParams& args)
+SlangResult LanguageServerCore::didOpenTextDocument(const DidOpenTextDocumentParams& args)
{
String canonicalPath = uriToCanonicalPath(args.textDocument.uri);
m_workspace->openDoc(canonicalPath, args.textDocument.text);
return SLANG_OK;
}
+SlangResult LanguageServer::didOpenTextDocument(const DidOpenTextDocumentParams& args)
+{
+ return m_core.didOpenTextDocument(args);
+}
+
static bool isBoolType(Type* t)
{
auto basicType = as<BasicExpressionType>(t);
@@ -515,12 +528,24 @@ HumaneSourceLoc getModuleLoc(SourceManager* manager, ContainerDecl* moduleDecl)
SlangResult LanguageServer::hover(
const LanguageServerProtocol::HoverParams& args, const JSONValue& responseId)
{
+ auto result = m_core.hover(args);
+ if (SLANG_FAILED(result.returnCode) || result.isNull)
+ {
+ m_connection->sendResult(NullResponse::get(), responseId);
+ return SLANG_OK;
+ }
+ m_connection->sendResult(&result.result, responseId);
+ return SLANG_OK;
+}
+
+LanguageServerResult<LanguageServerProtocol::Hover> LanguageServerCore::hover(
+ const LanguageServerProtocol::HoverParams& args)
+{
String canonicalPath = uriToCanonicalPath(args.textDocument.uri);
RefPtr<DocumentVersion> doc;
if (!m_workspace->openedDocuments.tryGetValue(canonicalPath, doc))
{
- m_connection->sendResult(NullResponse::get(), responseId);
- return SLANG_OK;
+ return std::nullopt;
}
Index line, col;
doc->zeroBasedUTF16LocToOneBasedUTF8Loc(args.position.line, args.position.character, line, col);
@@ -531,8 +556,7 @@ SlangResult LanguageServer::hover(
Module* parsedModule = version->getOrLoadModule(canonicalPath);
if (!parsedModule)
{
- m_connection->sendResult(NullResponse::get(), responseId);
- return SLANG_OK;
+ return LanguageServerResult<LanguageServerProtocol::Hover>();
}
auto findResult = findASTNodesAt(
doc.Ptr(),
@@ -544,10 +568,8 @@ SlangResult LanguageServer::hover(
col);
if (findResult.getCount() == 0 || findResult[0].path.getCount() == 0)
{
- if (SLANG_SUCCEEDED(tryGetMacroHoverInfo(version, doc, line, col, responseId)))
- return SLANG_OK;
- m_connection->sendResult(NullResponse::get(), responseId);
- return SLANG_OK;
+ SLANG_LS_RETURN_ON_SUCCESS(tryGetMacroHoverInfo(version, doc, line, col));
+ return std::nullopt;
}
StringBuilder sb;
@@ -836,27 +858,37 @@ SlangResult LanguageServer::hover(
}
if (sb.getLength() == 0)
{
- m_connection->sendResult(NullResponse::get(), responseId);
- return SLANG_OK;
+ return std::nullopt;
}
else
{
hover.contents.kind = "markdown";
hover.contents.value = sb.produceString();
- m_connection->sendResult(&hover, responseId);
- return SLANG_OK;
+ return hover;
}
}
SlangResult LanguageServer::gotoDefinition(
const LanguageServerProtocol::DefinitionParams& args, const JSONValue& responseId)
{
+ auto result = m_core.gotoDefinition(args);
+ if (SLANG_FAILED(result.returnCode) || result.isNull)
+ {
+ m_connection->sendResult(NullResponse::get(), responseId);
+ return SLANG_OK;
+ }
+ m_connection->sendResult(&result.result, responseId);
+ return SLANG_OK;
+}
+
+LanguageServerResult<List<LanguageServerProtocol::Location>> LanguageServerCore::gotoDefinition(
+ const LanguageServerProtocol::DefinitionParams& args)
+{
String canonicalPath = uriToCanonicalPath(args.textDocument.uri);
RefPtr<DocumentVersion> doc;
if (!m_workspace->openedDocuments.tryGetValue(canonicalPath, doc))
{
- m_connection->sendResult(NullResponse::get(), responseId);
- return SLANG_OK;
+ return std::nullopt;
}
Index line, col;
doc->zeroBasedUTF16LocToOneBasedUTF8Loc(args.position.line, args.position.character, line, col);
@@ -867,8 +899,7 @@ SlangResult LanguageServer::gotoDefinition(
Module* parsedModule = version->getOrLoadModule(canonicalPath);
if (!parsedModule)
{
- m_connection->sendResult(NullResponse::get(), responseId);
- return SLANG_OK;
+ return std::nullopt;
}
auto findResult = findASTNodesAt(
doc.Ptr(),
@@ -880,12 +911,9 @@ SlangResult LanguageServer::gotoDefinition(
col);
if (findResult.getCount() == 0 || findResult[0].path.getCount() == 0)
{
- if (SLANG_SUCCEEDED(tryGotoMacroDefinition(version, doc, line, col, responseId)))
- return SLANG_OK;
- if (SLANG_SUCCEEDED(tryGotoFileInclude(version, doc, line, responseId)))
- return SLANG_OK;
- m_connection->sendResult(NullResponse::get(), responseId);
- return SLANG_OK;
+ SLANG_LS_RETURN_ON_SUCCESS(tryGotoMacroDefinition(version, doc, line, col));
+ SLANG_LS_RETURN_ON_SUCCESS(tryGotoFileInclude(version, doc, line));
+ return std::nullopt;
}
struct LocationResult
{
@@ -948,8 +976,7 @@ SlangResult LanguageServer::gotoDefinition(
}
if (locations.getCount() == 0)
{
- m_connection->sendResult(NullResponse::get(), responseId);
- return SLANG_OK;
+ return std::nullopt;
}
else
{
@@ -971,8 +998,7 @@ SlangResult LanguageServer::gotoDefinition(
results.add(result);
}
}
- m_connection->sendResult(&results, responseId);
- return SLANG_OK;
+ return results;
}
}
@@ -989,13 +1015,25 @@ template <typename Func> Deferred<Func> makeDeferred(const Func& f) { return Def
SlangResult LanguageServer::completion(
const LanguageServerProtocol::CompletionParams& args, const JSONValue& responseId)
{
+ auto result = m_core.completion(args);
+ if (SLANG_FAILED(result.returnCode) || result.isNull)
+ m_connection->sendResult(NullResponse::get(), responseId);
+ else if (result.result.items.getCount())
+ m_connection->sendResult(&result.result.items, responseId);
+ else
+ m_connection->sendResult(&result.result.textEditItems, responseId);
+ return SLANG_OK;
+}
+
+LanguageServerResult<CompletionResult> LanguageServerCore::completion(
+ const LanguageServerProtocol::CompletionParams& args)
+{
String canonicalPath = uriToCanonicalPath(args.textDocument.uri);
RefPtr<DocumentVersion> doc;
if (!m_workspace->openedDocuments.tryGetValue(canonicalPath, doc))
{
- m_connection->sendResult(NullResponse::get(), responseId);
- return SLANG_OK;
+ return std::nullopt;
}
// Don't show completion at case label or after single '>' operator.
@@ -1014,8 +1052,7 @@ SlangResult LanguageServer::completion(
auto prevCharPos = args.position.character - 2;
if (prevCharPos >= 0 && prevCharPos < line.getLength() && line[prevCharPos] != requiredPrevChar)
{
- m_connection->sendResult(NullResponse::get(), responseId);
- return SLANG_OK;
+ return std::nullopt;
}
}
}
@@ -1026,8 +1063,7 @@ SlangResult LanguageServer::completion(
auto cursorOffset = doc->getOffset(utf8Line, utf8Col);
if (cursorOffset == -1 || doc->getText().getLength() == 0)
{
- m_connection->sendResult(NullResponse::get(), responseId);
- return SLANG_OK;
+ return std::nullopt;
}
// Ajust cursor position to the beginning of the current/last identifier.
@@ -1040,8 +1076,7 @@ SlangResult LanguageServer::completion(
// Never show suggestions when the user is typing a number.
if (cursorOffset + 1 >= 0 && cursorOffset + 1 < doc->getText().getLength() && CharUtil::isDigit(doc->getText()[cursorOffset + 1]))
{
- m_connection->sendResult(NullResponse::get(), responseId);
- return SLANG_OK;
+ return std::nullopt;
}
// Always create a new workspace version for the completion request since we
@@ -1057,7 +1092,6 @@ SlangResult LanguageServer::completion(
context.cursorOffset = cursorOffset;
context.version = version;
context.doc = doc.Ptr();
- context.responseId = responseId;
context.canonicalPath = canonicalPath.getUnownedSlice();
context.line = utf8Line;
context.col = utf8Col;
@@ -1069,22 +1103,15 @@ SlangResult LanguageServer::completion(
context.commitCharacterBehavior = CommitCharacterBehavior::Disabled;
}
- if (SLANG_SUCCEEDED(context.tryCompleteInclude()))
- {
- return SLANG_OK;
- }
- if (SLANG_SUCCEEDED(context.tryCompleteImport()))
- {
- return SLANG_OK;
- }
+ SLANG_LS_RETURN_ON_SUCCESS(context.tryCompleteInclude());
+ SLANG_LS_RETURN_ON_SUCCESS(context.tryCompleteImport());
if (args.context.triggerKind ==
LanguageServerProtocol::kCompletionTriggerKindTriggerCharacter &&
(args.context.triggerCharacter == "\"" || args.context.triggerCharacter == "/"))
{
// Trigger characters '"' and '/' are for include only.
- m_connection->sendResult(NullResponse::get(), responseId);
- return SLANG_OK;
+ return std::nullopt;
}
@@ -1099,49 +1126,48 @@ SlangResult LanguageServer::completion(
Module* parsedModule = version->getOrLoadModule(canonicalPath);
if (!parsedModule)
{
- m_connection->sendResult(NullResponse::get(), responseId);
- return SLANG_OK;
+ return std::nullopt;
}
context.parsedModule = parsedModule;
- if (SLANG_SUCCEEDED(context.tryCompleteAttributes()))
- {
- return SLANG_OK;
- }
+ SLANG_LS_RETURN_ON_SUCCESS(context.tryCompleteAttributes());
// Don't generate completion suggestions after typing '['.
if (args.context.triggerKind ==
LanguageServerProtocol::kCompletionTriggerKindTriggerCharacter &&
args.context.triggerCharacter == "[")
{
- m_connection->sendResult(NullResponse::get(), responseId);
- return SLANG_OK;
+ return std::nullopt;
}
- if (SLANG_SUCCEEDED(context.tryCompleteHLSLSemantic()))
- {
- return SLANG_OK;
- }
- if (SLANG_SUCCEEDED(context.tryCompleteMemberAndSymbol()))
+ SLANG_LS_RETURN_ON_SUCCESS(context.tryCompleteHLSLSemantic());
+ SLANG_LS_RETURN_ON_SUCCESS(context.tryCompleteMemberAndSymbol());
+ return std::nullopt;
+}
+
+SlangResult LanguageServer::completionResolve(
+ const LanguageServerProtocol::CompletionItem& args, const LanguageServerProtocol::TextEditCompletionItem& editItem, const JSONValue& responseId)
+{
+ auto result = m_core.completionResolve(args, editItem);
+ if (SLANG_FAILED(result.returnCode) || result.isNull)
{
+ m_connection->sendResult(NullResponse::get(), responseId);
return SLANG_OK;
}
- m_connection->sendResult(NullResponse::get(), responseId);
+ m_connection->sendResult(&result.result, responseId);
return SLANG_OK;
}
-SlangResult LanguageServer::completionResolve(
- const LanguageServerProtocol::CompletionItem& args, const LanguageServerProtocol::TextEditCompletionItem& editItem, const JSONValue& responseId)
+LanguageServerResult<LanguageServerProtocol::CompletionItem> LanguageServerCore::completionResolve(
+ const LanguageServerProtocol::CompletionItem& args, const LanguageServerProtocol::TextEditCompletionItem& editItem)
{
if (args.data.getLength() == 0)
{
if (editItem.textEdit.newText.getLength())
{
- m_connection->sendResult(&editItem, responseId);
- return SLANG_OK;
+ return std::nullopt;
}
- m_connection->sendResult(&args, responseId);
- return SLANG_OK;
+ return args;
}
LanguageServerProtocol::CompletionItem resolvedItem = args;
@@ -1149,8 +1175,7 @@ SlangResult LanguageServer::completionResolve(
auto version = m_workspace->getCurrentCompletionVersion();
if (!version || !version->linkage)
{
- m_connection->sendResult(&resolvedItem, responseId);
- return SLANG_OK;
+ return resolvedItem;
}
SLANG_AST_BUILDER_RAII(version->linkage->getASTBuilder());
auto& candidateItems = version->linkage->contentAssistInfo.completionSuggestions.candidateItems;
@@ -1163,20 +1188,31 @@ SlangResult LanguageServer::completionResolve(
resolvedItem.documentation.value = docSB.produceString();
resolvedItem.documentation.kind = "markdown";
}
- m_connection->sendResult(&resolvedItem, responseId);
- return SLANG_OK;
+ return resolvedItem;
}
SlangResult LanguageServer::semanticTokens(
const LanguageServerProtocol::SemanticTokensParams& args, const JSONValue& responseId)
{
+ auto result = m_core.semanticTokens(args);
+ if (SLANG_FAILED(result.returnCode) || result.isNull)
+ {
+ m_connection->sendResult(NullResponse::get(), responseId);
+ return SLANG_OK;
+ }
+ m_connection->sendResult(&result.result, responseId);
+ return SLANG_OK;
+}
+
+LanguageServerResult<LanguageServerProtocol::SemanticTokens> LanguageServerCore::semanticTokens(
+ const LanguageServerProtocol::SemanticTokensParams& args)
+{
String canonicalPath = uriToCanonicalPath(args.textDocument.uri);
RefPtr<DocumentVersion> doc;
if (!m_workspace->openedDocuments.tryGetValue(canonicalPath, doc))
{
- m_connection->sendResult(NullResponse::get(), responseId);
- return SLANG_OK;
+ return std::nullopt;
}
auto version = m_workspace->getCurrentVersion();
@@ -1185,8 +1221,7 @@ SlangResult LanguageServer::semanticTokens(
Module* parsedModule = version->getOrLoadModule(canonicalPath);
if (!parsedModule)
{
- m_connection->sendResult(NullResponse::get(), responseId);
- return SLANG_OK;
+ return std::nullopt;
}
auto tokens = getSemanticTokens(version->linkage, parsedModule, canonicalPath.getUnownedSlice(), doc.Ptr());
@@ -1204,11 +1239,10 @@ SlangResult LanguageServer::semanticTokens(
SemanticTokens response;
response.resultId = "";
response.data = getEncodedTokens(tokens);
- m_connection->sendResult(&response, responseId);
- return SLANG_OK;
+ return response;
}
-String LanguageServer::getExprDeclSignature(Expr* expr, String* outDocumentation, List<Slang::Range<Index>>* outParamRanges)
+String LanguageServerCore::getExprDeclSignature(Expr* expr, String* outDocumentation, List<Slang::Range<Index>>* outParamRanges)
{
if (auto declRefExpr = as<DeclRefExpr>(expr))
{
@@ -1285,7 +1319,7 @@ String LanguageServer::getExprDeclSignature(Expr* expr, String* outDocumentation
return printer.getString();
}
-String LanguageServer::getDeclRefSignature(DeclRef<Decl> declRef, String* outDocumentation, List<Slang::Range<Index>>* outParamRanges)
+String LanguageServerCore::getDeclRefSignature(DeclRef<Decl> declRef, String* outDocumentation, List<Slang::Range<Index>>* outParamRanges)
{
auto version = m_workspace->getCurrentVersion();
SLANG_AST_BUILDER_RAII(version->linkage->getASTBuilder());
@@ -1314,12 +1348,24 @@ String LanguageServer::getDeclRefSignature(DeclRef<Decl> declRef, String* outDoc
SlangResult LanguageServer::signatureHelp(
const LanguageServerProtocol::SignatureHelpParams& args, const JSONValue& responseId)
{
+ auto result = m_core.signatureHelp(args);
+ if (SLANG_FAILED(result.returnCode) || result.isNull)
+ {
+ m_connection->sendResult(NullResponse::get(), responseId);
+ return SLANG_OK;
+ }
+ m_connection->sendResult(&result.result, responseId);
+ return SLANG_OK;
+}
+
+LanguageServerResult<LanguageServerProtocol::SignatureHelp> LanguageServerCore::signatureHelp(
+ const LanguageServerProtocol::SignatureHelpParams& args)
+{
String canonicalPath = uriToCanonicalPath(args.textDocument.uri);
RefPtr<DocumentVersion> doc;
if (!m_workspace->openedDocuments.tryGetValue(canonicalPath, doc))
{
- m_connection->sendResult(NullResponse::get(), responseId);
- return SLANG_OK;
+ return std::nullopt;
}
Index line, col;
doc->zeroBasedUTF16LocToOneBasedUTF8Loc(args.position.line, args.position.character, line, col);
@@ -1330,8 +1376,7 @@ SlangResult LanguageServer::signatureHelp(
Module* parsedModule = version->getOrLoadModule(canonicalPath);
if (!parsedModule)
{
- m_connection->sendResult(NullResponse::get(), responseId);
- return SLANG_OK;
+ return std::nullopt;
}
auto findResult = findASTNodesAt(
@@ -1345,8 +1390,7 @@ SlangResult LanguageServer::signatureHelp(
if (findResult.getCount() == 0)
{
- m_connection->sendResult(NullResponse::get(), responseId);
- return SLANG_OK;
+ return std::nullopt;
}
AppExprBase* appExpr = nullptr;
@@ -1373,14 +1417,12 @@ SlangResult LanguageServer::signatureHelp(
}
if (!appExpr)
{
- m_connection->sendResult(NullResponse::get(), responseId);
- return SLANG_OK;
+ return std::nullopt;
}
if (appExpr->argumentDelimeterLocs.getCount() == 0)
{
- m_connection->sendResult(NullResponse::get(), responseId);
- return SLANG_OK;
+ return std::nullopt;
}
auto funcExpr = appExpr->functionExpr;
@@ -1399,8 +1441,7 @@ SlangResult LanguageServer::signatureHelp(
}
if (!funcExpr)
{
- m_connection->sendResult(NullResponse::get(), responseId);
- return SLANG_OK;
+ return std::nullopt;
}
SignatureHelp response;
@@ -1534,19 +1575,30 @@ SlangResult LanguageServer::signatureHelp(
}
}
- m_connection->sendResult(&response, responseId);
- return SLANG_OK;
+ return response;
}
SlangResult LanguageServer::documentSymbol(
const LanguageServerProtocol::DocumentSymbolParams& args, const JSONValue& responseId)
{
+ auto result = m_core.documentSymbol(args);
+ if (SLANG_FAILED(result.returnCode) || result.isNull)
+ {
+ m_connection->sendResult(NullResponse::get(), responseId);
+ return SLANG_OK;
+ }
+ m_connection->sendResult(&result.result, responseId);
+ return SLANG_OK;
+}
+
+LanguageServerResult<List<LanguageServerProtocol::DocumentSymbol>> LanguageServerCore::documentSymbol(
+ const LanguageServerProtocol::DocumentSymbolParams& args)
+{
String canonicalPath = uriToCanonicalPath(args.textDocument.uri);
RefPtr<DocumentVersion> doc;
if (!m_workspace->openedDocuments.tryGetValue(canonicalPath, doc))
{
- m_connection->sendResult(NullResponse::get(), responseId);
- return SLANG_OK;
+ return std::nullopt;
}
auto version = m_workspace->getCurrentVersion();
SLANG_AST_BUILDER_RAII(version->linkage->getASTBuilder());
@@ -1554,22 +1606,31 @@ SlangResult LanguageServer::documentSymbol(
Module* parsedModule = version->getOrLoadModule(canonicalPath);
if (!parsedModule)
{
+ return std::nullopt;
+ }
+ List<DocumentSymbol> symbols = getDocumentSymbols(version->linkage, parsedModule, canonicalPath.getUnownedSlice(), doc.Ptr());
+ return symbols;
+}
+
+SlangResult LanguageServer::inlayHint(const LanguageServerProtocol::InlayHintParams& args, const JSONValue& responseId)
+{
+ auto result = m_core.inlayHint(args);
+ if (SLANG_FAILED(result.returnCode) || result.isNull)
+ {
m_connection->sendResult(NullResponse::get(), responseId);
return SLANG_OK;
}
- List<DocumentSymbol> symbols = getDocumentSymbols(version->linkage, parsedModule, canonicalPath.getUnownedSlice(), doc.Ptr());
- m_connection->sendResult(&symbols, responseId);
+ m_connection->sendResult(&result.result, responseId);
return SLANG_OK;
}
-SlangResult LanguageServer::inlayHint(const LanguageServerProtocol::InlayHintParams& args, const JSONValue& responseId)
+LanguageServerResult<List<LanguageServerProtocol::InlayHint>> LanguageServerCore::inlayHint(const LanguageServerProtocol::InlayHintParams& args)
{
String canonicalPath = uriToCanonicalPath(args.textDocument.uri);
RefPtr<DocumentVersion> doc;
if (!m_workspace->openedDocuments.tryGetValue(canonicalPath, doc))
{
- m_connection->sendResult(NullResponse::get(), responseId);
- return SLANG_OK;
+ return std::nullopt;
}
auto version = m_workspace->getCurrentVersion();
SLANG_AST_BUILDER_RAII(version->linkage->getASTBuilder());
@@ -1577,8 +1638,7 @@ SlangResult LanguageServer::inlayHint(const LanguageServerProtocol::InlayHintPar
Module* parsedModule = version->getOrLoadModule(canonicalPath);
if (!parsedModule)
{
- m_connection->sendResult(NullResponse::get(), responseId);
- return SLANG_OK;
+ return std::nullopt;
}
List<InlayHint> hints = getInlayHints(
version->linkage,
@@ -1587,8 +1647,7 @@ SlangResult LanguageServer::inlayHint(const LanguageServerProtocol::InlayHintPar
doc.Ptr(),
args.range,
m_inlayHintOptions);
- m_connection->sendResult(&hints, responseId);
- return SLANG_OK;
+ return hints;
}
List<LanguageServerProtocol::TextEdit> translateTextEdits(DocumentVersion* doc, List<Edit>& edits)
@@ -1615,12 +1674,24 @@ List<LanguageServerProtocol::TextEdit> translateTextEdits(DocumentVersion* doc,
SlangResult LanguageServer::formatting(const LanguageServerProtocol::DocumentFormattingParams& args, const JSONValue& responseId)
{
+ auto result = m_core.formatting(args);
+ if (SLANG_FAILED(result.returnCode) || result.isNull)
+ {
+ m_connection->sendResult(NullResponse::get(), responseId);
+ return SLANG_OK;
+ }
+ m_connection->sendResult(&result.result, responseId);
+ return SLANG_OK;
+}
+
+LanguageServerResult<List<LanguageServerProtocol::TextEdit>> LanguageServerCore::formatting(
+ const LanguageServerProtocol::DocumentFormattingParams& args)
+{
String canonicalPath = uriToCanonicalPath(args.textDocument.uri);
RefPtr<DocumentVersion> doc;
if (!m_workspace->openedDocuments.tryGetValue(canonicalPath, doc))
{
- m_connection->sendResult(NullResponse::get(), responseId);
- return SLANG_OK;
+ return std::nullopt;
}
if (m_formatOptions.clangFormatLocation.getLength() == 0)
m_formatOptions.clangFormatLocation = findClangFormatTool();
@@ -1629,18 +1700,29 @@ SlangResult LanguageServer::formatting(const LanguageServerProtocol::DocumentFor
List<TextRange> exclusionRange = extractFormattingExclusionRanges(doc->getText().getUnownedSlice());
auto edits = formatSource(doc->getText().getUnownedSlice(), -1, -1, -1, exclusionRange, options);
auto textEdits = translateTextEdits(doc, edits);
- m_connection->sendResult(&textEdits, responseId);
- return SLANG_OK;
+ return textEdits;
}
SlangResult LanguageServer::rangeFormatting(const LanguageServerProtocol::DocumentRangeFormattingParams& args, const JSONValue& responseId)
{
+ auto result = m_core.rangeFormatting(args);
+ if (SLANG_FAILED(result.returnCode) || result.isNull)
+ {
+ m_connection->sendResult(NullResponse::get(), responseId);
+ return SLANG_OK;
+ }
+ m_connection->sendResult(&result.result, responseId);
+ return SLANG_OK;
+}
+
+LanguageServerResult<List<LanguageServerProtocol::TextEdit>> LanguageServerCore::rangeFormatting(
+ const LanguageServerProtocol::DocumentRangeFormattingParams& args)
+{
String canonicalPath = uriToCanonicalPath(args.textDocument.uri);
RefPtr<DocumentVersion> doc;
if (!m_workspace->openedDocuments.tryGetValue(canonicalPath, doc))
{
- m_connection->sendResult(NullResponse::get(), responseId);
- return SLANG_OK;
+ return std::nullopt;
}
Index endLine, endCol;
doc->zeroBasedUTF16LocToOneBasedUTF8Loc(args.range.end.line, args.range.end.character, endLine, endCol);
@@ -1653,23 +1735,33 @@ SlangResult LanguageServer::rangeFormatting(const LanguageServerProtocol::Docume
List<TextRange> exclusionRange = extractFormattingExclusionRanges(doc->getText().getUnownedSlice());
auto edits = formatSource(doc->getText().getUnownedSlice(), args.range.start.line, args.range.end.line, endOffset, exclusionRange, options);
auto textEdits = translateTextEdits(doc, edits);
- m_connection->sendResult(&textEdits, responseId);
- return SLANG_OK;
+ return textEdits;
}
SlangResult LanguageServer::onTypeFormatting(const LanguageServerProtocol::DocumentOnTypeFormattingParams& args, const JSONValue& responseId)
{
+ auto result = m_core.onTypeFormatting(args);
+ if (SLANG_FAILED(result.returnCode) || result.isNull)
+ {
+ m_connection->sendResult(NullResponse::get(), responseId);
+ return SLANG_OK;
+ }
+ m_connection->sendResult(&result.result, responseId);
+ return SLANG_OK;
+}
+
+LanguageServerResult<List<LanguageServerProtocol::TextEdit>> LanguageServerCore::onTypeFormatting(
+ const LanguageServerProtocol::DocumentOnTypeFormattingParams& args)
+{
String canonicalPath = uriToCanonicalPath(args.textDocument.uri);
RefPtr<DocumentVersion> doc;
if (!m_workspace->openedDocuments.tryGetValue(canonicalPath, doc))
{
- m_connection->sendResult(NullResponse::get(), responseId);
- return SLANG_OK;
+ return std::nullopt;
}
if (args.ch == ":" && !doc->getLine((Int)args.position.line + 1).trim().startsWith("case "))
{
- m_connection->sendResult(NullResponse::get(), responseId);
- return SLANG_OK;
+ return std::nullopt;
}
if (m_formatOptions.clangFormatLocation.getLength() == 0)
m_formatOptions.clangFormatLocation = findClangFormatTool();
@@ -1682,20 +1774,18 @@ SlangResult LanguageServer::onTypeFormatting(const LanguageServerProtocol::Docum
List<TextRange> exclusionRange = extractFormattingExclusionRanges(doc->getText().getUnownedSlice());
auto edits = formatSource(doc->getText().getUnownedSlice(), args.position.line, args.position.line, cursorOffset, exclusionRange, options);
auto textEdits = translateTextEdits(doc, edits);
- m_connection->sendResult(&textEdits, responseId);
- return SLANG_OK;
+ return textEdits;
}
void LanguageServer::publishDiagnostics()
{
-
if (std::chrono::system_clock::now() - m_lastDiagnosticUpdateTime < std::chrono::milliseconds(1000))
{
return;
}
m_lastDiagnosticUpdateTime = std::chrono::system_clock::now();
- auto version = m_workspace->getCurrentVersion();
+ auto version = m_core.m_workspace->getCurrentVersion();
SLANG_AST_BUILDER_RAII(version->linkage->getASTBuilder());
// Send updates to clear diagnostics for files that no longer have any messages.
@@ -1747,7 +1837,7 @@ void LanguageServer::updatePredefinedMacros(const JSONValue& macros)
List<String> predefinedMacros;
if (SLANG_SUCCEEDED(converter.convert(macros, &predefinedMacros)))
{
- if (m_workspace->updatePredefinedMacros(predefinedMacros))
+ if (m_core.m_workspace->updatePredefinedMacros(predefinedMacros))
{
sendRefreshRequests(m_connection);
}
@@ -1764,7 +1854,7 @@ void LanguageServer::updateSearchPaths(const JSONValue& value)
List<String> searchPaths;
if (SLANG_SUCCEEDED(converter.convert(value, &searchPaths)))
{
- if (m_workspace->updateSearchPaths(searchPaths))
+ if (m_core.m_workspace->updateSearchPaths(searchPaths))
{
sendRefreshRequests(m_connection);
}
@@ -1781,7 +1871,7 @@ void LanguageServer::updateSearchInWorkspace(const JSONValue& value)
bool searchPaths;
if (SLANG_SUCCEEDED(converter.convert(value, &searchPaths)))
{
- if (m_workspace->updateSearchInWorkspace(searchPaths))
+ if (m_core.m_workspace->updateSearchInWorkspace(searchPaths))
{
sendRefreshRequests(m_connection);
}
@@ -1800,15 +1890,15 @@ void LanguageServer::updateCommitCharacters(const JSONValue& jsonValue)
{
if (value == "on")
{
- m_commitCharacterBehavior = CommitCharacterBehavior::All;
+ m_core.m_commitCharacterBehavior = CommitCharacterBehavior::All;
}
else if (value == "off")
{
- m_commitCharacterBehavior = CommitCharacterBehavior::Disabled;
+ m_core.m_commitCharacterBehavior = CommitCharacterBehavior::Disabled;
}
else
{
- m_commitCharacterBehavior = CommitCharacterBehavior::MembersOnly;
+ m_core.m_commitCharacterBehavior = CommitCharacterBehavior::MembersOnly;
}
}
}
@@ -1819,17 +1909,17 @@ void LanguageServer::updateFormattingOptions(const JSONValue& clangFormatLoc, co
auto container = m_connection->getContainer();
JSONToNativeConverter converter(container, &m_typeMap, m_connection->getSink());
if (clangFormatLoc.isValid())
- converter.convert(clangFormatLoc, &m_formatOptions.clangFormatLocation);
+ converter.convert(clangFormatLoc, &m_core.m_formatOptions.clangFormatLocation);
if (clangFormatStyle.isValid())
- converter.convert(clangFormatStyle, &m_formatOptions.style);
+ converter.convert(clangFormatStyle, &m_core.m_formatOptions.style);
if (clangFormatFallbackStyle.isValid())
- converter.convert(clangFormatFallbackStyle, &m_formatOptions.fallbackStyle);
+ converter.convert(clangFormatFallbackStyle, &m_core.m_formatOptions.fallbackStyle);
if (allowLineBreakOnType.isValid())
- converter.convert(allowLineBreakOnType, &m_formatOptions.allowLineBreakInOnTypeFormatting);
+ converter.convert(allowLineBreakOnType, &m_core.m_formatOptions.allowLineBreakInOnTypeFormatting);
if (allowLineBreakInRange.isValid())
- converter.convert(allowLineBreakInRange, &m_formatOptions.allowLineBreakInRangeFormatting);
- if (m_formatOptions.style.getLength() == 0)
- m_formatOptions.style = Slang::FormatOptions().style;
+ converter.convert(allowLineBreakInRange, &m_core.m_formatOptions.allowLineBreakInRangeFormatting);
+ if (m_core.m_formatOptions.style.getLength() == 0)
+ m_core.m_formatOptions.style = Slang::FormatOptions().style;
}
void LanguageServer::updateInlayHintOptions(const JSONValue& deducedTypes, const JSONValue& parameterNames)
@@ -1840,13 +1930,13 @@ void LanguageServer::updateInlayHintOptions(const JSONValue& deducedTypes, const
bool showParameterNames = false;
converter.convert(deducedTypes, &showDeducedType);
converter.convert(parameterNames, &showParameterNames);
- if (showDeducedType != m_inlayHintOptions.showDeducedType || showParameterNames != m_inlayHintOptions.showParameterNames)
+ if (showDeducedType != m_core.m_inlayHintOptions.showDeducedType || showParameterNames != m_core.m_inlayHintOptions.showParameterNames)
{
m_connection->sendCall(
UnownedStringSlice("workspace/inlayHint/refresh"), JSONValue::makeInt(0));
}
- m_inlayHintOptions.showDeducedType = showDeducedType;
- m_inlayHintOptions.showParameterNames = showParameterNames;
+ m_core.m_inlayHintOptions.showDeducedType = showDeducedType;
+ m_core.m_inlayHintOptions.showParameterNames = showParameterNames;
}
void LanguageServer::updateTraceOptions(const JSONValue& value)
@@ -1921,7 +2011,7 @@ void LanguageServer::logMessage(int type, String message)
m_connection->sendCall(LanguageServerProtocol::LogMessageParams::methodName, &args);
}
-FormatOptions LanguageServer::getFormatOptions(Workspace* workspace, FormatOptions inOptions)
+FormatOptions LanguageServerCore::getFormatOptions(Workspace* workspace, FormatOptions inOptions)
{
FormatOptions result = inOptions;
if (workspace->rootDirectories.getCount())
@@ -1934,8 +2024,8 @@ FormatOptions LanguageServer::getFormatOptions(Workspace* workspace, FormatOptio
return result;
}
-SlangResult LanguageServer::tryGetMacroHoverInfo(
- WorkspaceVersion* version, DocumentVersion* doc, Index line, Index col, JSONValue responseId)
+LanguageServerResult<LanguageServerProtocol::Hover> LanguageServerCore::tryGetMacroHoverInfo(
+ WorkspaceVersion* version, DocumentVersion* doc, Index line, Index col)
{
Index startOffset = 0;
auto identifier = doc->peekIdentifier(line, col, startOffset);
@@ -1981,12 +2071,11 @@ SlangResult LanguageServer::tryGetMacroHoverInfo(
appendDefinitionLocation(sb, m_workspace, humaneLoc);
hover.contents.kind = "markdown";
hover.contents.value = sb.produceString();
- m_connection->sendResult(&hover, responseId);
- return SLANG_OK;
+ return hover;
}
-SlangResult LanguageServer::tryGotoMacroDefinition(
- WorkspaceVersion* version, DocumentVersion* doc, Index line, Index col, JSONValue responseId)
+LanguageServerResult<List<Location>> LanguageServerCore::tryGotoMacroDefinition(
+ WorkspaceVersion* version, DocumentVersion* doc, Index line, Index col)
{
Index startOffset = 0;
auto identifier = doc->peekIdentifier(line, col, startOffset);
@@ -1997,7 +2086,9 @@ SlangResult LanguageServer::tryGotoMacroDefinition(
return SLANG_FAIL;
auto humaneLoc =
version->linkage->getSourceManager()->getHumaneLoc(def->loc, SourceLocType::Actual);
- LanguageServerProtocol::Location result;
+ List<LanguageServerProtocol::Location> results;
+ results.setCount(1);
+ auto& result = results[0];
result.uri = URI::fromLocalFilePath(humaneLoc.pathInfo.foundPath.getUnownedSlice()).uri;
Index outLine, outCol;
doc->oneBasedUTF8LocToZeroBasedUTF16Loc(humaneLoc.line, humaneLoc.column, outLine, outCol);
@@ -2005,12 +2096,11 @@ SlangResult LanguageServer::tryGotoMacroDefinition(
result.range.start.character = (int)outCol;
result.range.end.line = (int)outLine;
result.range.end.character = (int)(outCol + identifier.getLength());
- m_connection->sendResult(&result, responseId);
- return SLANG_OK;
+ return results;
}
-SlangResult LanguageServer::tryGotoFileInclude(
- WorkspaceVersion* version, DocumentVersion* doc, Index line, JSONValue responseId)
+LanguageServerResult<List<Location>> LanguageServerCore::tryGotoFileInclude(
+ WorkspaceVersion* version, DocumentVersion* doc, Index line)
{
auto lineContent = doc->getLine(line).trim();
if (!lineContent.startsWith("#") || lineContent.indexOf(UnownedStringSlice("include")) == -1)
@@ -2021,14 +2111,15 @@ SlangResult LanguageServer::tryGotoFileInclude(
version->linkage->getSourceManager()->getHumaneLoc(include.loc, SourceLocType::Actual);
if (includeLoc.line == line && includeLoc.pathInfo.foundPath == doc->getPath())
{
- LanguageServerProtocol::Location result;
+ List<LanguageServerProtocol::Location> results;
+ results.setCount(1);
+ auto& result = results[0];
result.uri = URI::fromLocalFilePath(include.path.getUnownedSlice()).uri;
result.range.start.line = 0;
result.range.start.character = 0;
result.range.end.line = 0;
result.range.end.character = 0;
- m_connection->sendResult(&result, responseId);
- return SLANG_OK;
+ return results;
}
}
return SLANG_FAIL;
@@ -2267,17 +2358,28 @@ void LanguageServer::processCommands()
SlangResult LanguageServer::didCloseTextDocument(const DidCloseTextDocumentParams& args)
{
+ resetDiagnosticUpdateTime();
+ return m_core.didCloseTextDocument(args);
+}
+
+SlangResult LanguageServerCore::didCloseTextDocument(const DidCloseTextDocumentParams& args)
+{
String canonicalPath = uriToCanonicalPath(args.textDocument.uri);
m_workspace->closeDoc(canonicalPath);
- resetDiagnosticUpdateTime();
return SLANG_OK;
}
+
SlangResult LanguageServer::didChangeTextDocument(const DidChangeTextDocumentParams& args)
{
+ resetDiagnosticUpdateTime();
+ return m_core.didChangeTextDocument(args);
+}
+
+SlangResult LanguageServerCore::didChangeTextDocument(const DidChangeTextDocumentParams& args)
+{
String canonicalPath = uriToCanonicalPath(args.textDocument.uri);
for (auto change : args.contentChanges)
m_workspace->changeDoc(canonicalPath, change.range, change.text);
- resetDiagnosticUpdateTime();
return SLANG_OK;
}
@@ -2297,7 +2399,7 @@ SlangResult LanguageServer::didChangeConfiguration(
void LanguageServer::update()
{
- if (!m_workspace)
+ if (!m_core.m_workspace)
return;
publishDiagnostics();
}
diff --git a/source/slang/slang-language-server.h b/source/slang/slang-language-server.h
index 0a157819d..a0d5420db 100644
--- a/source/slang/slang-language-server.h
+++ b/source/slang/slang-language-server.h
@@ -84,11 +84,8 @@ struct LanguageServerStartupOptions
SLANG_API void parse(int argc, const char* const* argv);
};
-class LanguageServer
+class LanguageServerCore
{
-private:
- static const int kConfigResponseId = 0x1213;
-
public:
enum class TraceOptions
{
@@ -96,26 +93,95 @@ public:
Messages,
Verbose
};
- bool m_initialized = false;
- TraceOptions m_traceOptions = TraceOptions::Off;
CommitCharacterBehavior m_commitCharacterBehavior = CommitCharacterBehavior::MembersOnly;
- RefPtr<JSONRPCConnection> m_connection;
ComPtr<slang::IGlobalSession> m_session;
RefPtr<Workspace> m_workspace;
- Dictionary<String, String> m_lastPublishedDiagnostics;
- std::chrono::time_point<std::chrono::system_clock> m_lastDiagnosticUpdateTime;
FormatOptions m_formatOptions;
Slang::InlayHintOptions m_inlayHintOptions;
- bool m_quit = false;
List<LanguageServerProtocol::WorkspaceFolder> m_workspaceFolders;
- RttiTypeFuncsMap m_typeMap;
LanguageServerStartupOptions m_options;
- LanguageServer(LanguageServerStartupOptions options)
+ LanguageServerCore(LanguageServerStartupOptions options)
: m_options(options)
{}
SlangResult init(const LanguageServerProtocol::InitializeParams& args);
+ SlangResult didOpenTextDocument(const LanguageServerProtocol::DidOpenTextDocumentParams& args);
+ SlangResult didCloseTextDocument(
+ const LanguageServerProtocol::DidCloseTextDocumentParams& args);
+ SlangResult didChangeTextDocument(
+ const LanguageServerProtocol::DidChangeTextDocumentParams& args);
+ LanguageServerResult<LanguageServerProtocol::Hover> hover(const LanguageServerProtocol::HoverParams& args);
+ LanguageServerResult<List<LanguageServerProtocol::Location>> gotoDefinition(
+ const LanguageServerProtocol::DefinitionParams& args);
+
+ LanguageServerResult<CompletionResult> completion(
+ const LanguageServerProtocol::CompletionParams& args);
+ LanguageServerResult<LanguageServerProtocol::CompletionItem> completionResolve(
+ const LanguageServerProtocol::CompletionItem& args, const LanguageServerProtocol::TextEditCompletionItem& editItem);
+ LanguageServerResult<LanguageServerProtocol::SemanticTokens> semanticTokens(
+ const LanguageServerProtocol::SemanticTokensParams& args);
+ LanguageServerResult<LanguageServerProtocol::SignatureHelp> signatureHelp(
+ const LanguageServerProtocol::SignatureHelpParams& args);
+ LanguageServerResult<List<LanguageServerProtocol::DocumentSymbol>> documentSymbol(
+ const LanguageServerProtocol::DocumentSymbolParams& args);
+ LanguageServerResult<List<LanguageServerProtocol::InlayHint>> inlayHint(
+ const LanguageServerProtocol::InlayHintParams& args);
+ LanguageServerResult<List<LanguageServerProtocol::TextEdit>> formatting(
+ const LanguageServerProtocol::DocumentFormattingParams& args);
+ LanguageServerResult<List<LanguageServerProtocol::TextEdit>> rangeFormatting(
+ const LanguageServerProtocol::DocumentRangeFormattingParams& args);
+ LanguageServerResult<List<LanguageServerProtocol::TextEdit>> onTypeFormatting(
+ const LanguageServerProtocol::DocumentOnTypeFormattingParams& args);
+ String getExprDeclSignature(Expr* expr, String* outDocumentation, List<Slang::Range<Index>>* outParamRanges);
+ String getDeclRefSignature(DeclRef<Decl> declRef, String* outDocumentation, List<Slang::Range<Index>>* outParamRanges);
+private:
+ slang::IGlobalSession* getOrCreateGlobalSession();
+
+ FormatOptions getFormatOptions(Workspace* workspace, FormatOptions inOptions);
+ LanguageServerResult<LanguageServerProtocol::Hover> tryGetMacroHoverInfo(
+ WorkspaceVersion* version,
+ DocumentVersion* doc,
+ Index line,
+ Index col);
+ LanguageServerResult<List<LanguageServerProtocol::Location>> tryGotoMacroDefinition(
+ WorkspaceVersion* version,
+ DocumentVersion* doc,
+ Index line,
+ Index col);
+ LanguageServerResult<List<LanguageServerProtocol::Location>> tryGotoFileInclude(
+ WorkspaceVersion* version,
+ DocumentVersion* doc,
+ Index line);
+};
+
+class LanguageServer
+{
+private:
+ static const int kConfigResponseId = 0x1213;
+
+public:
+ enum class TraceOptions
+ {
+ Off,
+ Messages,
+ Verbose
+ };
+
+ bool m_quit = false;
+ LanguageServerCore m_core;
+ RefPtr<JSONRPCConnection> m_connection;
+ RttiTypeFuncsMap m_typeMap;
+ bool m_initialized = false;
+ TraceOptions m_traceOptions = TraceOptions::Off;
+ std::chrono::time_point<std::chrono::system_clock> m_lastDiagnosticUpdateTime;
+ Dictionary<String, String> m_lastPublishedDiagnostics;
+
+ LanguageServer(LanguageServerStartupOptions options)
+ : m_core(options)
+ {}
+
+ SlangResult init(const LanguageServerProtocol::InitializeParams& args);
SlangResult execute();
void update();
void updateConfigFromJSON(const JSONValue& jsonVal);
@@ -147,11 +213,8 @@ public:
const LanguageServerProtocol::DocumentRangeFormattingParams& args, const JSONValue& responseId);
SlangResult onTypeFormatting(
const LanguageServerProtocol::DocumentOnTypeFormattingParams& args, const JSONValue& responseId);
- String getExprDeclSignature(Expr* expr, String* outDocumentation, List<Slang::Range<Index>>* outParamRanges);
- String getDeclRefSignature(DeclRef<Decl> declRef, String* outDocumentation, List<Slang::Range<Index>>* outParamRanges);
private:
SlangResult parseNextMessage();
- slang::IGlobalSession* getOrCreateGlobalSession();
void resetDiagnosticUpdateTime();
void publishDiagnostics();
void updatePredefinedMacros(const JSONValue& macros);
@@ -166,24 +229,6 @@ private:
void registerCapability(const char* methodName);
void logMessage(int type, String message);
- FormatOptions getFormatOptions(Workspace* workspace, FormatOptions inOptions);
- SlangResult tryGetMacroHoverInfo(
- WorkspaceVersion* version,
- DocumentVersion* doc,
- Index line,
- Index col,
- JSONValue responseId);
- SlangResult tryGotoMacroDefinition(
- WorkspaceVersion* version,
- DocumentVersion* doc,
- Index line,
- Index col,
- JSONValue responseId);
- SlangResult tryGotoFileInclude(
- WorkspaceVersion* version,
- DocumentVersion* doc,
- Index line,
- JSONValue responseId);
List<Command> commands;
SlangResult queueJSONCall(JSONRPCCall call);
SlangResult runCommand(Command& cmd);