diff options
| author | Yong He <yonghe@outlook.com> | 2024-01-26 16:30:19 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-01-26 16:30:19 -0800 |
| commit | 470c5a28f5b84353f077c2d871db65cddd5f923a (patch) | |
| tree | e970a1c44173673bdc6dd5ec22e6b0c5bde93787 /source | |
| parent | 013bcf28da22fd569154bd9f98368e670fbeb873 (diff) | |
Fix LSP compatibility issues with Visual Studio. (#3520)
* [LSP] compatibility logic for Visual Studio.
* [LSP] Fix diagnostic rank parsing.
* [LSP] Fix semantic highlighting of cbuffer types.
* Fix.
* Fix.
---------
Co-authored-by: Yong He <yhe@nvidia.com>
Diffstat (limited to 'source')
| -rw-r--r-- | source/compiler-core/slang-language-server-protocol.cpp | 34 | ||||
| -rw-r--r-- | source/compiler-core/slang-language-server-protocol.h | 14 | ||||
| -rw-r--r-- | source/slang/slang-language-server-semantic-tokens.cpp | 8 | ||||
| -rw-r--r-- | source/slang/slang-language-server.cpp | 97 | ||||
| -rw-r--r-- | source/slang/slang-language-server.h | 17 | ||||
| -rw-r--r-- | source/slang/slang-parser.cpp | 30 | ||||
| -rw-r--r-- | source/slang/slang-workspace-version.cpp | 4 |
7 files changed, 160 insertions, 44 deletions
diff --git a/source/compiler-core/slang-language-server-protocol.cpp b/source/compiler-core/slang-language-server-protocol.cpp index 628baf08d..93ea0c9e3 100644 --- a/source/compiler-core/slang-language-server-protocol.cpp +++ b/source/compiler-core/slang-language-server-protocol.cpp @@ -257,6 +257,29 @@ static const StructRttiInfo _makeServerCapabilitiesRtti() } const StructRttiInfo ServerCapabilities::g_rttiInfo = _makeServerCapabilitiesRtti(); +static const StructRttiInfo _makeVSServerCapabilitiesRtti() +{ + VSServerCapabilities obj; + StructRttiBuilder builder(&obj, "LanguageServerProtocol::ServerCapabilities", nullptr); + builder.addField("positionEncoding", &obj.positionEncoding); + builder.addField("textDocumentSync", &obj.textDocumentSync); + builder.addField("workspace", &obj.workspace); + builder.addField("hoverProvider", &obj.hoverProvider); + builder.addField("inlayHintProvider", &obj.inlayHintProvider); + builder.addField("documentOnTypeFormattingProvider", &obj.documentOnTypeFormattingProvider); + builder.addField("documentFormattingProvider", &obj.documentFormattingProvider); + builder.addField("documentRangeFormattingProvider", &obj.documentRangeFormattingProvider); + builder.addField("definitionProvider", &obj.definitionProvider); + builder.addField("completionProvider", &obj.completionProvider); + builder.addField("semanticTokensProvider", &obj.semanticTokensProvider); + builder.addField("signatureHelpProvider", &obj.signatureHelpProvider); + builder.addField("documentSymbolProvider", &obj.documentSymbolProvider); + builder.addField("_vs_projectContextProvider", &obj._vs_projectContextProvider); + builder.ignoreUnknownFields(); + return builder.make(); +} +const StructRttiInfo VSServerCapabilities::g_rttiInfo = _makeVSServerCapabilitiesRtti(); + static const StructRttiInfo _makeServerInfoRtti() { ServerInfo obj; @@ -280,6 +303,17 @@ static const StructRttiInfo _makeInitializeResultRtti() } const StructRttiInfo InitializeResult::g_rttiInfo = _makeInitializeResultRtti(); +static const StructRttiInfo _makeVSInitializeResultRtti() +{ + VSInitializeResult obj; + StructRttiBuilder builder(&obj, "LanguageServerProtocol::VSInitializeResult", nullptr); + builder.addField("capabilities", &obj.capabilities); + builder.addField("serverInfo", &obj.serverInfo); + builder.ignoreUnknownFields(); + return builder.make(); +} +const StructRttiInfo VSInitializeResult::g_rttiInfo = _makeVSInitializeResultRtti(); + const UnownedStringSlice InitializeParams::methodName = UnownedStringSlice::fromLiteral("initialize"); diff --git a/source/compiler-core/slang-language-server-protocol.h b/source/compiler-core/slang-language-server-protocol.h index 316c15c04..3dcc90be1 100644 --- a/source/compiler-core/slang-language-server-protocol.h +++ b/source/compiler-core/slang-language-server-protocol.h @@ -299,6 +299,12 @@ struct ServerCapabilities static const StructRttiInfo g_rttiInfo; }; +struct VSServerCapabilities : ServerCapabilities +{ + bool _vs_projectContextProvider = false; + static const StructRttiInfo g_rttiInfo; +}; + struct WorkspaceFolder { String uri; @@ -327,6 +333,14 @@ struct InitializeResult static const StructRttiInfo g_rttiInfo; }; +struct VSInitializeResult +{ + VSServerCapabilities capabilities; + ServerInfo serverInfo; + + static const StructRttiInfo g_rttiInfo; +}; + struct ShutdownParams { static const UnownedStringSlice methodName; diff --git a/source/slang/slang-language-server-semantic-tokens.cpp b/source/slang/slang-language-server-semantic-tokens.cpp index 837aad06c..ae10d62e8 100644 --- a/source/slang/slang-language-server-semantic-tokens.cpp +++ b/source/slang/slang-language-server-semantic-tokens.cpp @@ -40,6 +40,8 @@ SemanticToken _createSemanticToken(SourceManager* manager, SourceLoc loc, Name* List<SemanticToken> getSemanticTokens(Linkage* linkage, Module* module, UnownedStringSlice fileName, DocumentVersion* doc) { auto manager = linkage->getSourceManager(); + + auto cbufferName = linkage->getNamePool()->getName(toSlice("ConstantBuffer")); List<SemanticToken> result; auto maybeInsertToken = [&](const SemanticToken& token) @@ -73,6 +75,10 @@ List<SemanticToken> getSemanticTokens(Linkage* linkage, Module* module, UnownedS if (target->hasModifier<BuiltinTypeModifier>()) return; token.type = SemanticTokenType::Type; + if (name == cbufferName) + { + token.length = doc->getTokenLength(token.line, token.col); + } } else if (as<ConstructorDecl>(target)) { @@ -156,7 +162,7 @@ List<SemanticToken> getSemanticTokens(Linkage* linkage, Module* module, UnownedS } else if (auto aggTypeDecl = as<AggTypeDeclBase>(node)) { - if (aggTypeDecl->getName()) + if (aggTypeDecl->getName() && aggTypeDecl->findModifier<ImplicitParameterGroupElementTypeModifier>() == nullptr) { SemanticToken token = _createSemanticToken( manager, aggTypeDecl->getNameLoc(), aggTypeDecl->getName()); diff --git a/source/slang/slang-language-server.cpp b/source/slang/slang-language-server.cpp index 84dd1b330..76e21c2ca 100644 --- a/source/slang/slang-language-server.cpp +++ b/source/slang/slang-language-server.cpp @@ -106,42 +106,58 @@ SlangResult LanguageServer::parseNextMessage() { InitializeParams args; m_connection->toNativeArgsOrSendError(call.params, &args, call.id); - init(args); + auto fillCapability = [&](ServerCapabilities& caps) + { + caps.positionEncoding = "utf-16"; + caps.textDocumentSync.openClose = true; + caps.textDocumentSync.change = (int)TextDocumentSyncKind::Incremental; + caps.workspace.workspaceFolders.supported = true; + caps.workspace.workspaceFolders.changeNotifications = false; + caps.hoverProvider = true; + caps.definitionProvider = true; + caps.documentSymbolProvider = true; + caps.inlayHintProvider.resolveProvider = false; + caps.documentFormattingProvider = true; + caps.documentOnTypeFormattingProvider.firstTriggerCharacter = "}"; + caps.documentOnTypeFormattingProvider.moreTriggerCharacter.add(";"); + caps.documentOnTypeFormattingProvider.moreTriggerCharacter.add(":"); + caps.documentOnTypeFormattingProvider.moreTriggerCharacter.add("{"); + caps.documentRangeFormattingProvider = true; + caps.completionProvider.triggerCharacters.add("."); + caps.completionProvider.triggerCharacters.add(":"); + caps.completionProvider.triggerCharacters.add("["); + caps.completionProvider.triggerCharacters.add("\""); + caps.completionProvider.triggerCharacters.add("/"); + caps.completionProvider.resolveProvider = true; + caps.completionProvider.workDoneToken = ""; + caps.semanticTokensProvider.full = true; + caps.semanticTokensProvider.range = false; + caps.signatureHelpProvider.triggerCharacters.add("("); + caps.signatureHelpProvider.triggerCharacters.add(","); + caps.signatureHelpProvider.retriggerCharacters.add(","); + for (auto tokenType : kSemanticTokenTypes) + caps.semanticTokensProvider.legend.tokenTypes.add(tokenType); + }; + ServerInfo serverInfo; + serverInfo.name = "SlangLanguageServer"; + serverInfo.version = "1.8"; - InitializeResult result; - result.serverInfo.name = "SlangLanguageServer"; - result.serverInfo.version = "1.3"; - result.capabilities.positionEncoding = "utf-16"; - result.capabilities.textDocumentSync.openClose = true; - result.capabilities.textDocumentSync.change = (int)TextDocumentSyncKind::Incremental; - result.capabilities.workspace.workspaceFolders.supported = true; - result.capabilities.workspace.workspaceFolders.changeNotifications = false; - result.capabilities.hoverProvider = true; - result.capabilities.definitionProvider = true; - result.capabilities.documentSymbolProvider = true; - result.capabilities.inlayHintProvider.resolveProvider = false; - result.capabilities.documentFormattingProvider = true; - result.capabilities.documentOnTypeFormattingProvider.firstTriggerCharacter = "}"; - result.capabilities.documentOnTypeFormattingProvider.moreTriggerCharacter.add(";"); - result.capabilities.documentOnTypeFormattingProvider.moreTriggerCharacter.add(":"); - result.capabilities.documentOnTypeFormattingProvider.moreTriggerCharacter.add("{"); - result.capabilities.documentRangeFormattingProvider = true; - result.capabilities.completionProvider.triggerCharacters.add("."); - result.capabilities.completionProvider.triggerCharacters.add(":"); - result.capabilities.completionProvider.triggerCharacters.add("["); - result.capabilities.completionProvider.triggerCharacters.add("\""); - result.capabilities.completionProvider.triggerCharacters.add("/"); - result.capabilities.completionProvider.resolveProvider = true; - result.capabilities.completionProvider.workDoneToken = ""; - result.capabilities.semanticTokensProvider.full = true; - result.capabilities.semanticTokensProvider.range = false; - result.capabilities.signatureHelpProvider.triggerCharacters.add("("); - result.capabilities.signatureHelpProvider.triggerCharacters.add(","); - result.capabilities.signatureHelpProvider.retriggerCharacters.add(","); - for (auto tokenType : kSemanticTokenTypes) - result.capabilities.semanticTokensProvider.legend.tokenTypes.add(tokenType); - m_connection->sendResult(&result, call.id); + if (m_options.isVisualStudio) + { + VSInitializeResult vsResult; + vsResult.serverInfo = serverInfo; + fillCapability(vsResult.capabilities); + vsResult.capabilities._vs_projectContextProvider = true; + m_connection->sendResult(&vsResult, call.id); + } + else + { + InitializeResult result; + result.serverInfo = serverInfo; + fillCapability(result.capabilities); + m_connection->sendResult(&result, call.id); + } return SLANG_OK; } else if (call.method == "initialized") @@ -2301,9 +2317,18 @@ SlangResult LanguageServer::execute() return SLANG_OK; } -SLANG_API SlangResult runLanguageServer() +SLANG_API void LanguageServerStartupOptions::parse(int argc, const char* const* argv) +{ + for (int i = 1; i < argc; i++) + { + if (strcmp(argv[i], "-vs") == 0) + isVisualStudio = true; + } +} + +SLANG_API SlangResult runLanguageServer(Slang::LanguageServerStartupOptions options) { - Slang::LanguageServer server; + Slang::LanguageServer server(options); SLANG_RETURN_ON_FAIL(server.execute()); return SLANG_OK; } diff --git a/source/slang/slang-language-server.h b/source/slang/slang-language-server.h index e244ad9f5..956ad9769 100644 --- a/source/slang/slang-language-server.h +++ b/source/slang/slang-language-server.h @@ -76,6 +76,14 @@ struct Command Optional<LanguageServerProtocol::CancelParams> cancelArgs; }; +struct LanguageServerStartupOptions +{ + // Are we working with Visual Studio client? + bool isVisualStudio = false; + + SLANG_API void parse(int argc, const char* const* argv); +}; + class LanguageServer { private: @@ -101,7 +109,12 @@ public: bool m_quit = false; List<LanguageServerProtocol::WorkspaceFolder> m_workspaceFolders; RttiTypeFuncsMap m_typeMap; - + LanguageServerStartupOptions m_options; + + LanguageServer(LanguageServerStartupOptions options) + : m_options(options) + {} + SlangResult init(const LanguageServerProtocol::InitializeParams& args); SlangResult execute(); void update(); @@ -182,5 +195,5 @@ inline bool _isIdentifierChar(char ch) return ch >= '0' && ch <= '9' || ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' || ch == '_'; } -SLANG_API SlangResult runLanguageServer(); +SLANG_API SlangResult runLanguageServer(LanguageServerStartupOptions options); } // namespace Slang diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp index 909a8eb72..f0c9e175f 100644 --- a/source/slang/slang-parser.cpp +++ b/source/slang/slang-parser.cpp @@ -114,7 +114,7 @@ namespace Slang DiagnosticSink* sink; SourceLoc lastErrorLoc; ParserOptions options; - + Modifiers* pendingModifiers = nullptr; int genericDepth = 0; // Is the parser in a "recovering" state? @@ -3095,7 +3095,7 @@ namespace Slang } static Decl* ParseHLSLBufferDecl( - Parser* parser, + Parser* parser, String bufferWrapperTypeName) { // An HLSL declaration of a constant buffer like this: @@ -3119,7 +3119,19 @@ namespace Slang // the second is a variable declaration that uses the buffer type. StructDecl* bufferDataTypeDecl = parser->astBuilder->create<StructDecl>(); - addModifier(bufferDataTypeDecl, parser->astBuilder->create<PublicModifier>()); + if (parser->pendingModifiers) + { + // Clone visibility modifier from cbuffer decl to the internal struct type decl. + // For example, if cbuffer is public, we want the element buffer type to also be + // public. + if (auto visModifier = parser->pendingModifiers->findModifier<VisibilityModifier>()) + { + auto cloneVisModifier = (VisibilityModifier*)parser->astBuilder->createByNodeType(visModifier->astNodeType); + cloneVisModifier->keywordName = visModifier->keywordName; + cloneVisModifier->loc = visModifier->loc; + addModifier(bufferDataTypeDecl, cloneVisModifier); + } + } VarDecl* bufferVarDecl = parser->astBuilder->create<VarDecl>(); @@ -4396,6 +4408,18 @@ namespace Slang Modifiers modifiers ) { DeclBase* decl = nullptr; + + struct RestorePendingModifiersRAII + { + Modifiers* oldValue; + Parser* parser; + ~RestorePendingModifiersRAII() + { + parser->pendingModifiers = oldValue; + } + }; + RestorePendingModifiersRAII restorePendingModifiersRAII{ parser->pendingModifiers, parser }; + parser->pendingModifiers = &modifiers; auto loc = parser->tokenReader.peekLoc(); diff --git a/source/slang/slang-workspace-version.cpp b/source/slang/slang-workspace-version.cpp index 9a707aae7..1b17f3170 100644 --- a/source/slang/slang-workspace-version.cpp +++ b/source/slang/slang-workspace-version.cpp @@ -243,11 +243,11 @@ void WorkspaceVersion::parseDiagnostics(String compilerOutput) pos = line.indexOf(' '); diagnostic.code = StringUtil::parseIntAndAdvancePos(line, pos); diagnostic.message = line.tail(colonIndex + 2); - if (lineIndex + 1 < lines.getCount() && lines[lineIndex].startsWith("^+")) + if (lineIndex + 1 < lines.getCount() && lines[lineIndex+1].startsWith("^+")) { lineIndex++; pos = 2; - auto tokenLength = StringUtil::parseIntAndAdvancePos(line, pos); + auto tokenLength = StringUtil::parseIntAndAdvancePos(lines[lineIndex], pos); diagnostic.range.end.character += tokenLength; } |
