jvikstrom updated this revision to Diff 207031. jvikstrom marked an inline comment as done. jvikstrom added a comment.
Added SemanticHighlightingInformation and SemantigHighlightingParams. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D63919/new/ https://reviews.llvm.org/D63919 Files: clang-tools-extra/clangd/ClangdLSPServer.cpp clang-tools-extra/clangd/ClangdLSPServer.h clang-tools-extra/clangd/Protocol.cpp clang-tools-extra/clangd/Protocol.h clang-tools-extra/clangd/SemanticHighlighting.cpp clang-tools-extra/clangd/SemanticHighlighting.h clang-tools-extra/clangd/test/initialize-params.test clang-tools-extra/clangd/test/semantic-highlighting.test
Index: clang-tools-extra/clangd/test/semantic-highlighting.test =================================================================== --- /dev/null +++ clang-tools-extra/clangd/test/semantic-highlighting.test @@ -0,0 +1,21 @@ +# RUN: clangd -lit-test < %s | FileCheck -strict-whitespace %s +{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{"textDocument": {"semanticHighlightingCapabilities": {"semanticHighlighting": true}}},"trace":"off"}} +--- +{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///foo.cpp","languageId":"cpp","version":1,"text":"int x = 2;"}}} +# CHECK: "method": "textDocument/semanticHighlighting", +# CHECK-NEXT: "params": { +# CHECK-NEXT: "lines": [ +# CHECK-NEXT: { +# CHECK-NEXT: "line": 0, +# CHECK-NEXT: "tokens": "AAAABAABAAA=" +# CHECK-NEXT: } +# CHECK-NEXT: ], +# CHECK-NEXT: "textDocument": { +# CHECK-NEXT: "uri": "file:///clangd-test/foo.cpp" +# CHECK-NEXT: } +# CHECK-NEXT: } +# CHECK-NEXT:} +--- +{"jsonrpc":"2.0","id":3,"method":"shutdown"} +--- +{"jsonrpc":"2.0","method":"exit"} Index: clang-tools-extra/clangd/test/initialize-params.test =================================================================== --- clang-tools-extra/clangd/test/initialize-params.test +++ clang-tools-extra/clangd/test/initialize-params.test @@ -33,6 +33,16 @@ # CHECK-NEXT: "hoverProvider": true, # CHECK-NEXT: "referencesProvider": true, # CHECK-NEXT: "renameProvider": true, +# CHECK-NEXT: "semanticHighlighting": { +# CHECK-NEXT: "scopes": [ +# CHECK-NEXT: [ +# CHECK-NEXT: "variable.cpp" +# CHECK-NEXT: ], +# CHECK-NEXT: [ +# CHECK-NEXT: "entity.name.function.cpp" +# CHECK-NEXT: ] +# CHECK-NEXT: ] +# CHECK-NEXT: }, # CHECK-NEXT: "signatureHelpProvider": { # CHECK-NEXT: "triggerCharacters": [ # CHECK-NEXT: "(", Index: clang-tools-extra/clangd/SemanticHighlighting.h =================================================================== --- clang-tools-extra/clangd/SemanticHighlighting.h +++ clang-tools-extra/clangd/SemanticHighlighting.h @@ -10,6 +10,7 @@ #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_SEMANTICHIGHLIGHTING_H #include "ClangdUnit.h" +#include "Protocol.h" namespace clang { namespace clangd { @@ -31,6 +32,20 @@ // main AST. std::vector<HighlightingToken> getSemanticHighlightings(ParsedAST &AST); +// Gets the TextMate scopes as a double nested array where the +// SemanticHighlightKind indexes correctly into this vector. +std::vector<std::vector<std::string>> getSemanticTextMateScopes(); + +// Converts a vector of HighlightingTokens to a vector of +// SemanticHighlightingInformation. Assumes the HighlightingToken's vector is +// ordered in ascending order by line and secondarily by column of the token's +// start position. The returned SemanticHighlightingInformation vector will be +// ordered in ascending order according to the line number. The token string in +// SemanticHighlightingInformation is base64 encoded. +std::vector<SemanticHighlightingInformation> +highlightingTokensToSemanticHighlightingInformation( + llvm::ArrayRef<HighlightingToken> Tokens); + } // namespace clangd } // namespace clang Index: clang-tools-extra/clangd/SemanticHighlighting.cpp =================================================================== --- clang-tools-extra/clangd/SemanticHighlighting.cpp +++ clang-tools-extra/clangd/SemanticHighlighting.cpp @@ -8,6 +8,7 @@ #include "SemanticHighlighting.h" #include "Logger.h" +#include "Protocol.h" #include "SourceCode.h" #include "clang/AST/ASTContext.h" #include "clang/AST/RecursiveASTVisitor.h" @@ -63,6 +64,48 @@ } }; +// Encode binary data into base64. +// This was copied from compiler-rt/lib/fuzzer/FuzzerUtil.cpp. +// FIXME: Factor this out into llvm/Support? +std::string encodeBase64(const llvm::SmallVectorImpl<char> &U) { + static const char Table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + std::string Res; + size_t I; + for (I = 0; I + 2 < U.size(); I += 3) { + uint32_t X = (U[I] << 16) + (U[I + 1] << 8) + U[I + 2]; + Res += Table[(X >> 18) & 63]; + Res += Table[(X >> 12) & 63]; + Res += Table[(X >> 6) & 63]; + Res += Table[X & 63]; + } + if (I + 1 == U.size()) { + uint32_t X = (U[I] << 16); + Res += Table[(X >> 18) & 63]; + Res += Table[(X >> 12) & 63]; + Res += "=="; + } else if (I + 2 == U.size()) { + uint32_t X = (U[I] << 16) + (U[I + 1] << 8); + Res += Table[(X >> 18) & 63]; + Res += Table[(X >> 12) & 63]; + Res += Table[(X >> 6) & 63]; + Res += "="; + } + return Res; +} + +void write32be(uint32_t I, llvm::raw_ostream &OS) { + std::array<char, 4> Buf; + llvm::support::endian::write32be(Buf.data(), I); + OS.write(Buf.data(), Buf.size()); +} + +void write16be(uint16_t I, llvm::raw_ostream &OS) { + std::array<char, 2> Buf; + llvm::support::endian::write16be(Buf.data(), I); + OS.write(Buf.data(), Buf.size()); +} } // namespace bool operator==(const HighlightingToken &Lhs, const HighlightingToken &Rhs) { @@ -73,5 +116,48 @@ return HighlightingTokenCollector(AST).collectTokens(); } +std::vector<SemanticHighlightingInformation> +highlightingTokensToSemanticHighlightingInformation( + llvm::ArrayRef<HighlightingToken> Tokens) { + if (Tokens.size() == 0) { + return {}; + } + + std::vector<SemanticHighlightingInformation> Lines; + int LastLine = Tokens.front().R.start.line; + // FIXME: Tokens might be multiple lines long (block comments) in this case + // this needs to add multiple lines for those tokens. + llvm::SmallVector<char, 128> LineHighlights; + llvm::raw_svector_ostream OS(LineHighlights); + for (const auto &Token : Tokens) { + if (Token.R.start.line != LastLine) { + Lines.push_back( + {static_cast<unsigned int>(LastLine), encodeBase64(LineHighlights)}); + LastLine = Token.R.start.line; + LineHighlights.clear(); + } + + write32be(Token.R.start.character, OS); + write16be(Token.R.end.character - Token.R.start.character, OS); + write16be(static_cast<int>(Token.Kind), OS); + } + + Lines.push_back( + {static_cast<unsigned int>(LastLine), encodeBase64(LineHighlights)}); + return Lines; +} + +std::vector<std::vector<std::string>> getSemanticTextMateScopes() { + std::map<HighlightingKind, std::vector<std::string>> Scopes = { + {HighlightingKind::Variable, {"variable.cpp"}}, + {HighlightingKind::Function, {"entity.name.function.cpp"}}}; + std::vector<std::vector<std::string>> NestedScopes(Scopes.size()); + for (const auto &Scope : Scopes) { + NestedScopes[static_cast<int>(Scope.first)] = Scope.second; + } + + return NestedScopes; +} + } // namespace clangd } // namespace clang Index: clang-tools-extra/clangd/Protocol.h =================================================================== --- clang-tools-extra/clangd/Protocol.h +++ clang-tools-extra/clangd/Protocol.h @@ -406,6 +406,9 @@ /// textDocument.codeAction.codeActionLiteralSupport. bool CodeActionStructure = false; + /// Client supports semantic highlighting. + bool SemanticHighlighting = false; + /// Supported encodings for LSP character offsets. (clangd extension). llvm::Optional<std::vector<OffsetEncoding>> offsetEncoding; @@ -1173,6 +1176,25 @@ }; llvm::json::Value toJSON(const FileStatus &FStatus); +// Contains all highlightings in a single line. +struct SemanticHighlightingInformation { + // The line these highlightings belong to. + unsigned int Line; + // The base64 encoded string of highlighting tokens. + std::string Tokens; +}; + +llvm::json::Value toJSON(const SemanticHighlightingInformation &Highlighting); + +struct SemanticHighlightingParams { + // The textdocument these highlightings belong to. + TextDocumentIdentifier TextDocument; + // The lines of highlightings that should be sent. + std::vector<SemanticHighlightingInformation> Lines; +}; + +llvm::json::Value toJSON(const SemanticHighlightingParams &Highlighting); + } // namespace clangd } // namespace clang Index: clang-tools-extra/clangd/Protocol.cpp =================================================================== --- clang-tools-extra/clangd/Protocol.cpp +++ clang-tools-extra/clangd/Protocol.cpp @@ -273,6 +273,12 @@ if (!O) return false; if (auto *TextDocument = O->getObject("textDocument")) { + if (auto *SemanticHighlighting = + TextDocument->getObject("semanticHighlightingCapabilities")) { + if (auto SemanticHighlightingSupport = + SemanticHighlighting->getBoolean("semanticHighlighting")) + R.SemanticHighlighting = *SemanticHighlightingSupport; + } if (auto *Diagnostics = TextDocument->getObject("publishDiagnostics")) { if (auto CategorySupport = Diagnostics->getBoolean("categorySupport")) R.DiagnosticCategory = *CategorySupport; @@ -1027,5 +1033,17 @@ return OS << toString(Enc); } +llvm::json::Value toJSON(const SemanticHighlightingInformation &Highlighting) { + return llvm::json::Object{{"line", Highlighting.Line}, + {"tokens", Highlighting.Tokens}}; +} + +llvm::json::Value toJSON(const SemanticHighlightingParams &Highlighting) { + return llvm::json::Object{ + {"textDocument", Highlighting.TextDocument}, + {"lines", std::move(Highlighting.Lines)}, + }; +} + } // namespace clangd } // namespace clang Index: clang-tools-extra/clangd/ClangdLSPServer.h =================================================================== --- clang-tools-extra/clangd/ClangdLSPServer.h +++ clang-tools-extra/clangd/ClangdLSPServer.h @@ -55,6 +55,8 @@ // Implement DiagnosticsConsumer. void onDiagnosticsReady(PathRef File, std::vector<Diag> Diagnostics) override; void onFileUpdated(PathRef File, const TUStatus &Status) override; + void onHighlightingsReady(PathRef File, + std::vector<HighlightingToken> Highlightings) override; // LSP methods. Notifications have signature void(const Params&). // Calls have signature void(const Params&, Callback<Response>). @@ -115,6 +117,9 @@ void reparseOpenedFiles(); void applyConfiguration(const ConfigurationSettings &Settings); + /// Sends a "publishSemanticHighlighting" notification to the LSP client. + void publishSemanticHighlighting(SemanticHighlightingParams Params); + /// Sends a "publishDiagnostics" notification to the LSP client. void publishDiagnostics(const URIForFile &File, std::vector<clangd::Diagnostic> Diagnostics); Index: clang-tools-extra/clangd/ClangdLSPServer.cpp =================================================================== --- clang-tools-extra/clangd/ClangdLSPServer.cpp +++ clang-tools-extra/clangd/ClangdLSPServer.cpp @@ -11,6 +11,7 @@ #include "FormattedString.h" #include "GlobalCompilationDatabase.h" #include "Protocol.h" +#include "SemanticHighlighting.h" #include "SourceCode.h" #include "Trace.h" #include "URI.h" @@ -328,6 +329,8 @@ WithOffsetEncoding.emplace(kCurrentOffsetEncoding, *NegotiatedOffsetEncoding); + ClangdServerOpts.SemanticHighlighting = + Params.capabilities.SemanticHighlighting; if (Params.rootUri && *Params.rootUri) ClangdServerOpts.WorkspaceRoot = Params.rootUri->file(); else if (Params.rootPath && !Params.rootPath->empty()) @@ -403,6 +406,8 @@ {ExecuteCommandParams::CLANGD_APPLY_FIX_COMMAND, ExecuteCommandParams::CLANGD_APPLY_TWEAK}}, }}, + {"semanticHighlighting", + llvm::json::Object{{"scopes", getSemanticTextMateScopes()}}}, {"typeHierarchyProvider", true}, }}}}; if (NegotiatedOffsetEncoding) @@ -927,6 +932,11 @@ reparseOpenedFiles(); } +void ClangdLSPServer::publishSemanticHighlighting( + SemanticHighlightingParams Params) { + notify("textDocument/semanticHighlighting", Params); +} + void ClangdLSPServer::publishDiagnostics( const URIForFile &File, std::vector<clangd::Diagnostic> Diagnostics) { // Publish diagnostics. @@ -1063,6 +1073,13 @@ return true; } +void ClangdLSPServer::onHighlightingsReady( + PathRef File, std::vector<HighlightingToken> Highlightings) { + publishSemanticHighlighting( + {{URIForFile::canonicalize(File, /*TUPath=*/File)}, + highlightingTokensToSemanticHighlightingInformation(Highlightings)}); +} + void ClangdLSPServer::onDiagnosticsReady(PathRef File, std::vector<Diag> Diagnostics) { auto URI = URIForFile::canonicalize(File, /*TUPath=*/File);
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits