From 9b9ba70edfedb83594c95b4107cc52330a29c602 Mon Sep 17 00:00:00 2001 From: Yingchi Long Date: Sun, 11 Aug 2024 20:39:03 +0800 Subject: [PATCH] nixd/Controller: handle UTF-16 code units for locations (#580) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 截屏2024-08-11 00 02 30 Handle LSP spec (UTF16) character length for locations. --- nixd/include/nixd/Controller/Controller.h | 2 +- nixd/include/nixd/Controller/NixTU.h | 6 +- nixd/lib/Controller/CodeAction.cpp | 4 +- nixd/lib/Controller/Configuration.cpp | 2 +- nixd/lib/Controller/Convert.cpp | 29 +++++----- nixd/lib/Controller/Convert.h | 6 +- nixd/lib/Controller/Definition.cpp | 17 +++--- nixd/lib/Controller/Diagnostics.cpp | 8 +-- nixd/lib/Controller/DocumentHighlight.cpp | 9 +-- nixd/lib/Controller/DocumentLink.cpp | 8 +-- nixd/lib/Controller/DocumentSymbol.cpp | 68 ++++++++++++----------- nixd/lib/Controller/FindReferences.cpp | 7 ++- nixd/lib/Controller/Hover.cpp | 9 +-- nixd/lib/Controller/InlayHints.cpp | 15 +++-- nixd/lib/Controller/NixTU.cpp | 7 ++- nixd/lib/Controller/Rename.cpp | 13 +++-- nixd/lib/Controller/SemanticTokens.cpp | 22 +++++--- nixd/lib/Controller/Support.cpp | 9 +-- nixd/tools/nixd/test/utf16.md | 52 +++++++++++++++++ 19 files changed, 187 insertions(+), 106 deletions(-) create mode 100644 nixd/tools/nixd/test/utf16.md diff --git a/nixd/include/nixd/Controller/Controller.h b/nixd/include/nixd/Controller/Controller.h index 1fb4e36ea..354aca6ed 100644 --- a/nixd/include/nixd/Controller/Controller.h +++ b/nixd/include/nixd/Controller/Controller.h @@ -211,7 +211,7 @@ class Controller : public lspserver::LSPServer { /// Determine whether or not this diagnostic is suppressed. bool isSuppressed(nixf::Diagnostic::DiagnosticKind Kind); void publishDiagnostics(lspserver::PathRef File, - std::optional Version, + std::optional Version, std::string_view Src, const std::vector &Diagnostics); void onRename(const lspserver::RenameParams &Params, diff --git a/nixd/include/nixd/Controller/NixTU.h b/nixd/include/nixd/Controller/NixTU.h index 3c0bb7e83..8a4a84a39 100644 --- a/nixd/include/nixd/Controller/NixTU.h +++ b/nixd/include/nixd/Controller/NixTU.h @@ -22,13 +22,15 @@ class NixTU { std::optional ASTByteCode; std::unique_ptr VLA; std::unique_ptr PMA; + std::shared_ptr Src; public: NixTU() = default; NixTU(std::vector Diagnostics, std::shared_ptr AST, std::optional ASTByteCode, - std::unique_ptr VLA); + std::unique_ptr VLA, + std::shared_ptr Src); [[nodiscard]] const std::vector &diagnostics() const { return Diagnostics; @@ -43,6 +45,8 @@ class NixTU { [[nodiscard]] const nixf::VariableLookupAnalysis *variableLookup() const { return VLA.get(); } + + [[nodiscard]] std::string_view src() const { return *Src; } }; } // namespace nixd diff --git a/nixd/lib/Controller/CodeAction.cpp b/nixd/lib/Controller/CodeAction.cpp index ee6ba8bcd..7b02fdc7e 100644 --- a/nixd/lib/Controller/CodeAction.cpp +++ b/nixd/lib/Controller/CodeAction.cpp @@ -24,7 +24,7 @@ void Controller::onCodeAction(const lspserver::CodeActionParams &Params, std::vector Actions; Actions.reserve(Diagnostics.size()); for (const nixf::Diagnostic &D : Diagnostics) { - auto DRange = toLSPRange(D.range()); + auto DRange = toLSPRange(TU->src(), D.range()); if (!Range.overlap(DRange)) continue; @@ -34,7 +34,7 @@ void Controller::onCodeAction(const lspserver::CodeActionParams &Params, Edits.reserve(F.edits().size()); for (const nixf::TextEdit &TE : F.edits()) { Edits.emplace_back(TextEdit{ - .range = toLSPRange(TE.oldRange()), + .range = toLSPRange(TU->src(), TE.oldRange()), .newText = std::string(TE.newText()), }); } diff --git a/nixd/lib/Controller/Configuration.cpp b/nixd/lib/Controller/Configuration.cpp index 971ec72c8..3bb28e8a9 100644 --- a/nixd/lib/Controller/Configuration.cpp +++ b/nixd/lib/Controller/Configuration.cpp @@ -84,7 +84,7 @@ void Controller::updateConfig(Configuration NewConfig) { // After all, notify all AST modules the diagnostic set has been updated. std::lock_guard TUsGuard(TUsLock); for (const auto &[File, TU] : TUs) { - publishDiagnostics(File, std::nullopt, TU->diagnostics()); + publishDiagnostics(File, std::nullopt, TU->src(), TU->diagnostics()); } } diff --git a/nixd/lib/Controller/Convert.cpp b/nixd/lib/Controller/Convert.cpp index 8a68164d9..8d969f222 100644 --- a/nixd/lib/Controller/Convert.cpp +++ b/nixd/lib/Controller/Convert.cpp @@ -1,11 +1,14 @@ #include "Convert.h" + #include "nixf/Basic/Diagnostic.h" -using namespace lspserver; +#include "lspserver/SourceCode.h" -namespace nixd { +#include -int getLSPSeverity(nixf::Diagnostic::DiagnosticKind Kind) { +using namespace lspserver; + +int nixd::getLSPSeverity(nixf::Diagnostic::DiagnosticKind Kind) { switch (nixf::Diagnostic::severity(Kind)) { case nixf::Diagnostic::DS_Fatal: case nixf::Diagnostic::DS_Error: @@ -21,25 +24,27 @@ int getLSPSeverity(nixf::Diagnostic::DiagnosticKind Kind) { __builtin_unreachable(); } -lspserver::Position toLSPPosition(const nixf::LexerCursor &P) { - return lspserver::Position{static_cast(P.line()), - static_cast(P.column())}; +lspserver::Position nixd::toLSPPosition(llvm::StringRef Code, + const nixf::LexerCursor &P) { + return lspserver::offsetToPosition(Code, P.offset()); } -nixf::Position toNixfPosition(const lspserver::Position &P) { +nixf::Position nixd::toNixfPosition(const lspserver::Position &P) { return {P.line, P.character}; } -nixf::PositionRange toNixfRange(const lspserver::Range &P) { +nixf::PositionRange nixd::toNixfRange(const lspserver::Range &P) { return {toNixfPosition(P.start), toNixfPosition(P.end)}; } -lspserver::Range toLSPRange(const nixf::LexerCursorRange &R) { - return lspserver::Range{toLSPPosition(R.lCur()), toLSPPosition(R.rCur())}; +lspserver::Range nixd::toLSPRange(llvm::StringRef Code, + const nixf::LexerCursorRange &R) { + return lspserver::Range{toLSPPosition(Code, R.lCur()), + toLSPPosition(Code, R.rCur())}; } llvm::SmallVector -toLSPTags(const std::vector &Tags) { +nixd::toLSPTags(const std::vector &Tags) { llvm::SmallVector Result; Result.reserve(Tags.size()); for (const nixf::DiagnosticTag &Tag : Tags) { @@ -54,5 +59,3 @@ toLSPTags(const std::vector &Tags) { } return Result; } - -} // namespace nixd diff --git a/nixd/lib/Controller/Convert.h b/nixd/lib/Controller/Convert.h index fcb71feec..d203b0154 100644 --- a/nixd/lib/Controller/Convert.h +++ b/nixd/lib/Controller/Convert.h @@ -10,13 +10,15 @@ namespace nixd { -lspserver::Position toLSPPosition(const nixf::LexerCursor &P); +lspserver::Position toLSPPosition(llvm::StringRef Code, + const nixf::LexerCursor &P); nixf::Position toNixfPosition(const lspserver::Position &P); nixf::PositionRange toNixfRange(const lspserver::Range &P); -lspserver::Range toLSPRange(const nixf::LexerCursorRange &R); +lspserver::Range toLSPRange(llvm::StringRef Code, + const nixf::LexerCursorRange &R); int getLSPSeverity(nixf::Diagnostic::DiagnosticKind Kind); diff --git a/nixd/lib/Controller/Definition.cpp b/nixd/lib/Controller/Definition.cpp index 908a58195..0d7a6255b 100644 --- a/nixd/lib/Controller/Definition.cpp +++ b/nixd/lib/Controller/Definition.cpp @@ -113,10 +113,11 @@ const Definition &findVarDefinition(const ExprVar &Var, } /// \brief Convert nixf::Definition to lspserver::Location -Location convertToLocation(const Definition &Def, URIForFile URI) { +Location convertToLocation(llvm::StringRef Src, const Definition &Def, + URIForFile URI) { return Location{ .uri = std::move(URI), - .range = toLSPRange(Def.syntax()->range()), + .range = toLSPRange(Src, Def.syntax()->range()), }; } @@ -280,9 +281,9 @@ Locations defineSelect(const ExprSelect &Sel, const VariableLookupAnalysis &VLA, } Locations defineVarStatic(const ExprVar &Var, const VariableLookupAnalysis &VLA, - const URIForFile &URI) { + const URIForFile &URI, llvm::StringRef Src) { const Definition &Def = findVarDefinition(Var, VLA); - return {convertToLocation(Def, URI)}; + return {convertToLocation(Src, Def, URI)}; } template @@ -293,9 +294,9 @@ std::vector mergeVec(std::vector A, const std::vector &B) { Locations defineVar(const ExprVar &Var, const VariableLookupAnalysis &VLA, const ParentMapAnalysis &PM, AttrSetClient &NixpkgsClient, - const URIForFile &URI) { + const URIForFile &URI, llvm::StringRef Src) { try { - Locations StaticLocs = defineVarStatic(Var, VLA, URI); + Locations StaticLocs = defineVarStatic(Var, VLA, URI, Src); // Nixpkgs locations. try { @@ -374,12 +375,12 @@ void Controller::onDefinition(const TextDocumentPositionParams &Params, return Reply(squash([&]() -> llvm::Expected { // Special case for inherited names. if (const ExprVar *Var = findInheritVar(N, PM, VLA)) - return defineVar(*Var, VLA, PM, *nixpkgsClient(), URI); + return defineVar(*Var, VLA, PM, *nixpkgsClient(), URI, TU->src()); switch (UpExpr.kind()) { case Node::NK_ExprVar: { const auto &Var = static_cast(UpExpr); - return defineVar(Var, VLA, PM, *nixpkgsClient(), URI); + return defineVar(Var, VLA, PM, *nixpkgsClient(), URI, TU->src()); } case Node::NK_ExprSelect: { const auto &Sel = static_cast(UpExpr); diff --git a/nixd/lib/Controller/Diagnostics.cpp b/nixd/lib/Controller/Diagnostics.cpp index 54cf1f4b7..4557888c8 100644 --- a/nixd/lib/Controller/Diagnostics.cpp +++ b/nixd/lib/Controller/Diagnostics.cpp @@ -40,7 +40,7 @@ bool Controller::isSuppressed(nixf::Diagnostic::DiagnosticKind Kind) { } void Controller::publishDiagnostics( - PathRef File, std::optional Version, + PathRef File, std::optional Version, std::string_view Src, const std::vector &Diagnostics) { std::vector LSPDiags; LSPDiags.reserve(Diagnostics.size()); @@ -67,7 +67,7 @@ void Controller::publishDiagnostics( } Diagnostic &Diag = LSPDiags.emplace_back(Diagnostic{ - .range = toLSPRange(D.range()), + .range = toLSPRange(Src, D.range()), .severity = getLSPSeverity(D.kind()), .code = D.sname(), .source = "nixf", @@ -83,7 +83,7 @@ void Controller::publishDiagnostics( .location = Location{ .uri = URIForFile::canonicalize(File, File), - .range = toLSPRange(N.range()), + .range = toLSPRange(Src, N.range()), }, .message = N.format(), }); @@ -93,7 +93,7 @@ void Controller::publishDiagnostics( for (const nixf::Note &N : Notes) { LSPDiags.emplace_back(Diagnostic{ - .range = toLSPRange(N.range()), + .range = toLSPRange(Src, N.range()), .severity = 4, .code = N.sname(), .source = "nixf", diff --git a/nixd/lib/Controller/DocumentHighlight.cpp b/nixd/lib/Controller/DocumentHighlight.cpp index 5f437350f..7587faaf0 100644 --- a/nixd/lib/Controller/DocumentHighlight.cpp +++ b/nixd/lib/Controller/DocumentHighlight.cpp @@ -25,7 +25,8 @@ namespace { std::vector highlight(const nixf::Node &Desc, const ParentMapAnalysis &PMA, const VariableLookupAnalysis &VLA, - const URIForFile &URI) { + const URIForFile &URI, + llvm::StringRef Src) { // Find "definition" auto Def = findDefinition(Desc, PMA, VLA); @@ -34,14 +35,14 @@ std::vector highlight(const nixf::Node &Desc, for (const auto *Use : Def.uses()) { assert(Use); Highlights.emplace_back(DocumentHighlight{ - .range = toLSPRange(Use->range()), + .range = toLSPRange(Src, Use->range()), .kind = DocumentHighlightKind::Read, }); } if (Def.syntax()) { const Node &Syntax = *Def.syntax(); Highlights.emplace_back(DocumentHighlight{ - .range = toLSPRange(Syntax.range()), + .range = toLSPRange(Src, Syntax.range()), .kind = DocumentHighlightKind::Write, }); } @@ -67,7 +68,7 @@ void Controller::onDocumentHighlight( try { const auto &PM = *TU->parentMap(); const auto &VLA = *TU->variableLookup(); - return Reply(highlight(*Desc, PM, VLA, URI)); + return Reply(highlight(*Desc, PM, VLA, URI, TU->src())); } catch (std::exception &E) { elog("textDocument/documentHighlight failed: {0}", E.what()); return Reply(std::vector{}); diff --git a/nixd/lib/Controller/DocumentLink.cpp b/nixd/lib/Controller/DocumentLink.cpp index 50fdadcd3..43fa3511e 100644 --- a/nixd/lib/Controller/DocumentLink.cpp +++ b/nixd/lib/Controller/DocumentLink.cpp @@ -47,7 +47,7 @@ std::optional resolveExprPath(const std::string &BasePath, } void dfs(const Node *N, const std::string &BasePath, - std::vector &Links) { + std::vector &Links, llvm::StringRef Src) { if (!N) return; @@ -59,7 +59,7 @@ void dfs(const Node *N, const std::string &BasePath, // Provide literal path linking. if (auto Link = resolveExprPath(BasePath, Path.parts().literal())) { Links.emplace_back( - DocumentLink{.range = toLSPRange(N->range()), + DocumentLink{.range = toLSPRange(Src, N->range()), .target = URIForFile::canonicalize(*Link, *Link)}); } } @@ -71,7 +71,7 @@ void dfs(const Node *N, const std::string &BasePath, // Traverse on all children for (const Node *Ch : N->children()) { - dfs(Ch, BasePath, Links); + dfs(Ch, BasePath, Links, Src); } } @@ -86,7 +86,7 @@ void Controller::onDocumentLink( if (std::shared_ptr AST = getAST(*TU, Reply)) [[likely]] { // Traverse the AST, provide the links std::vector Links; - dfs(AST.get(), File, Links); + dfs(AST.get(), File, Links, TU->src()); Reply(std::move(Links)); } } diff --git a/nixd/lib/Controller/DocumentSymbol.cpp b/nixd/lib/Controller/DocumentSymbol.cpp index 915664a66..e0dbd21ad 100644 --- a/nixd/lib/Controller/DocumentSymbol.cpp +++ b/nixd/lib/Controller/DocumentSymbol.cpp @@ -8,6 +8,7 @@ #include "nixd/Controller/Controller.h" #include +#include #include #include #include @@ -27,23 +28,24 @@ std::string getLambdaName(const ExprLambda &Lambda) { return Lambda.arg()->id()->name(); } -lspserver::Range getLambdaSelectionRage(const ExprLambda &Lambda) { +lspserver::Range getLambdaSelectionRage(llvm::StringRef Src, + const ExprLambda &Lambda) { if (!Lambda.arg()) { - return toLSPRange(Lambda.range()); + return toLSPRange(Src, Lambda.range()); } if (!Lambda.arg()->id()) { assert(Lambda.arg()->formals()); - return toLSPRange(Lambda.arg()->formals()->range()); + return toLSPRange(Src, Lambda.arg()->formals()->range()); } - return toLSPRange(Lambda.arg()->id()->range()); + return toLSPRange(Src, Lambda.arg()->id()->range()); } -lspserver::Range getAttrRange(const Attribute &Attr) { - auto LCur = toLSPPosition(Attr.key().lCur()); +lspserver::Range getAttrRange(llvm::StringRef Src, const Attribute &Attr) { + auto LCur = toLSPPosition(Src, Attr.key().lCur()); if (Attr.value()) - return {LCur, toLSPPosition(Attr.value()->rCur())}; - return {LCur, toLSPPosition(Attr.key().rCur())}; + return {LCur, toLSPPosition(Src, Attr.value()->rCur())}; + return {LCur, toLSPPosition(Src, Attr.key().rCur())}; } /// Make variable's entry rich. @@ -78,7 +80,7 @@ void richVar(const ExprVar &Var, DocumentSymbol &Sym, /// Collect document symbol on AST. void collect(const Node *AST, std::vector &Symbols, - const VariableLookupAnalysis &VLA) { + const VariableLookupAnalysis &VLA, llvm::StringRef Src) { if (!AST) return; switch (AST->kind()) { @@ -90,8 +92,8 @@ void collect(const Node *AST, std::vector &Symbols, .detail = "string", .kind = SymbolKind::String, .deprecated = false, - .range = toLSPRange(Str.range()), - .selectionRange = toLSPRange(Str.range()), + .range = toLSPRange(Src, Str.range()), + .selectionRange = toLSPRange(Src, Str.range()), .children = {}, }; Symbols.emplace_back(std::move(Sym)); @@ -104,8 +106,8 @@ void collect(const Node *AST, std::vector &Symbols, .detail = "integer", .kind = SymbolKind::Number, .deprecated = false, - .range = toLSPRange(Int.range()), - .selectionRange = toLSPRange(Int.range()), + .range = toLSPRange(Src, Int.range()), + .selectionRange = toLSPRange(Src, Int.range()), .children = {}, }; Symbols.emplace_back(std::move(Sym)); @@ -118,8 +120,8 @@ void collect(const Node *AST, std::vector &Symbols, .detail = "float", .kind = SymbolKind::Number, .deprecated = false, - .range = toLSPRange(Float.range()), - .selectionRange = toLSPRange(Float.range()), + .range = toLSPRange(Src, Float.range()), + .selectionRange = toLSPRange(Src, Float.range()), .children = {}, }; Symbols.emplace_back(std::move(Sym)); @@ -132,8 +134,8 @@ void collect(const Node *AST, std::vector &Symbols, .detail = "attribute name", .kind = SymbolKind::Property, .deprecated = false, - .range = toLSPRange(AN.range()), - .selectionRange = toLSPRange(AN.range()), + .range = toLSPRange(Src, AN.range()), + .selectionRange = toLSPRange(Src, AN.range()), .children = {}, }; Symbols.emplace_back(std::move(Sym)); @@ -146,8 +148,8 @@ void collect(const Node *AST, std::vector &Symbols, .detail = "identifier", .kind = SymbolKind::Variable, .deprecated = false, - .range = toLSPRange(Var.range()), - .selectionRange = toLSPRange(Var.range()), + .range = toLSPRange(Src, Var.range()), + .selectionRange = toLSPRange(Src, Var.range()), .children = {}, }; richVar(Var, Sym, VLA); @@ -157,14 +159,14 @@ void collect(const Node *AST, std::vector &Symbols, case Node::NK_ExprLambda: { std::vector Children; const auto &Lambda = static_cast(*AST); - collect(Lambda.body(), Children, VLA); + collect(Lambda.body(), Children, VLA, Src); DocumentSymbol Sym{ .name = getLambdaName(Lambda), .detail = "lambda", .kind = SymbolKind::Function, .deprecated = false, - .range = toLSPRange(Lambda.range()), - .selectionRange = getLambdaSelectionRage(Lambda), + .range = toLSPRange(Src, Lambda.range()), + .selectionRange = getLambdaSelectionRage(Src, Lambda), .children = std::move(Children), }; Symbols.emplace_back(std::move(Sym)); @@ -174,15 +176,15 @@ void collect(const Node *AST, std::vector &Symbols, std::vector Children; const auto &List = static_cast(*AST); for (const Node *Ch : AST->children()) - collect(Ch, Children, VLA); + collect(Ch, Children, VLA, Src); DocumentSymbol Sym{ .name = "{anonymous}", .detail = "list", .kind = SymbolKind::Array, .deprecated = false, - .range = toLSPRange(List.range()), - .selectionRange = toLSPRange(List.range()), + .range = toLSPRange(Src, List.range()), + .selectionRange = toLSPRange(Src, List.range()), .children = std::move(Children), }; Symbols.emplace_back(std::move(Sym)); @@ -194,28 +196,28 @@ void collect(const Node *AST, std::vector &Symbols, if (!Attr.value()) continue; std::vector Children; - collect(Attr.value(), Children, VLA); + collect(Attr.value(), Children, VLA, Src); DocumentSymbol Sym{ .name = Name, .detail = "attribute", .kind = SymbolKind::Field, .deprecated = false, - .range = getAttrRange(Attr), - .selectionRange = toLSPRange(Attr.key().range()), + .range = getAttrRange(Src, Attr), + .selectionRange = toLSPRange(Src, Attr.key().range()), .children = std::move(Children), }; Symbols.emplace_back(std::move(Sym)); } for (const nixf::Attribute &Attr : SA.dynamicAttrs()) { std::vector Children; - collect(Attr.value(), Children, VLA); + collect(Attr.value(), Children, VLA, Src); DocumentSymbol Sym{ .name = "${dynamic attribute}", .detail = "attribute", .kind = SymbolKind::Field, .deprecated = false, - .range = getAttrRange(Attr), - .selectionRange = toLSPRange(Attr.key().range()), + .range = getAttrRange(Src, Attr), + .selectionRange = toLSPRange(Src, Attr.key().range()), .children = std::move(Children), }; Symbols.emplace_back(std::move(Sym)); @@ -225,7 +227,7 @@ void collect(const Node *AST, std::vector &Symbols, default: // Trivial dispatch. Treat these symbol as same as this level. for (const Node *Ch : AST->children()) - collect(Ch, Symbols, VLA); + collect(Ch, Symbols, VLA, Src); break; } } @@ -239,7 +241,7 @@ void Controller::onDocumentSymbol(const DocumentSymbolParams &Params, if (std::shared_ptr TU = getTU(URI.file().str(), Reply)) { if (std::shared_ptr AST = getAST(*TU, Reply)) { std::vector Symbols; - collect(AST.get(), Symbols, *TU->variableLookup()); + collect(AST.get(), Symbols, *TU->variableLookup(), TU->src()); Reply(std::move(Symbols)); } } diff --git a/nixd/lib/Controller/FindReferences.cpp b/nixd/lib/Controller/FindReferences.cpp index e3369c5eb..f64f4ded2 100644 --- a/nixd/lib/Controller/FindReferences.cpp +++ b/nixd/lib/Controller/FindReferences.cpp @@ -23,7 +23,8 @@ namespace { std::vector findReferences(const nixf::Node &Desc, const ParentMapAnalysis &PMA, const VariableLookupAnalysis &VLA, - const URIForFile &URI) { + const URIForFile &URI, + llvm::StringRef Src) { // Two steps. // 1. Find some "definition" for this node. @@ -37,7 +38,7 @@ std::vector findReferences(const nixf::Node &Desc, assert(Use); Locations.emplace_back(Location{ .uri = URI, - .range = toLSPRange(Use->range()), + .range = toLSPRange(Src, Use->range()), }); } return Locations; @@ -60,7 +61,7 @@ void Controller::onReferences(const TextDocumentPositionParams &Params, const auto &PM = *TU->parentMap(); const auto &VLA = *TU->variableLookup(); try { - return Reply(findReferences(*Desc, PM, VLA, URI)); + return Reply(findReferences(*Desc, PM, VLA, URI, TU->src())); } catch (std::exception &E) { return Reply(error("references: {0}", E.what())); } diff --git a/nixd/lib/Controller/Hover.cpp b/nixd/lib/Controller/Hover.cpp index cc72f92db..0ffe10f9d 100644 --- a/nixd/lib/Controller/Hover.cpp +++ b/nixd/lib/Controller/Hover.cpp @@ -71,7 +71,8 @@ class NixpkgsHoverProvider { } if (Package.Description) { - OS << "## Description" << "\n\n"; + OS << "## Description" + << "\n\n"; OS << *Package.Description; OS << "\n\n"; @@ -141,7 +142,7 @@ void Controller::onHover(const TextDocumentPositionParams &Params, .kind = MarkupKind::Markdown, .value = std::move(*Doc), }, - .range = toLSPRange(N->range()), + .range = toLSPRange(TU->src(), N->range()), }); return; } @@ -173,7 +174,7 @@ void Controller::onHover(const TextDocumentPositionParams &Params, .kind = MarkupKind::Markdown, .value = std::move(Docs), }, - .range = toLSPRange(N->range()), + .range = toLSPRange(TU->src(), N->range()), }); return; } @@ -189,7 +190,7 @@ void Controller::onHover(const TextDocumentPositionParams &Params, .kind = MarkupKind::Markdown, .value = "`" + Name + "`", }, - .range = toLSPRange(N->range()), + .range = toLSPRange(TU->src(), N->range()), }); } } diff --git a/nixd/lib/Controller/InlayHints.cpp b/nixd/lib/Controller/InlayHints.cpp index 58bab19c3..bd9d36d47 100644 --- a/nixd/lib/Controller/InlayHints.cpp +++ b/nixd/lib/Controller/InlayHints.cpp @@ -20,6 +20,7 @@ #include +#include #include #include @@ -51,13 +52,16 @@ class NixpkgsInlayHintsProvider { return Range->contains(R); } + llvm::StringRef Src; + public: NixpkgsInlayHintsProvider(AttrSetClient &NixpkgsProvider, const VariableLookupAnalysis &VLA, const ParentMapAnalysis &PMA, std::optional Range, - std::vector &Hints) - : NixpkgsProvider(NixpkgsProvider), VLA(VLA), PMA(PMA), Hints(Hints) { + std::vector &Hints, llvm::StringRef Src) + : NixpkgsProvider(NixpkgsProvider), VLA(VLA), PMA(PMA), Hints(Hints), + Src(Src) { if (Range) this->Range = toNixfRange(*Range); } @@ -89,10 +93,10 @@ class NixpkgsInlayHintsProvider { if (const std::optional &Version = R.PackageDesc.Version) { // Construct inlay hints. InlayHint H{ - .position = toLSPPosition(N->rCur()), + .position = toLSPPosition(Src, N->rCur()), .label = ": " + *Version, .kind = InlayHintKind::Designator, - .range = toLSPRange(N->range()), + .range = toLSPRange(Src, N->range()), }; Hints.emplace_back(std::move(H)); } @@ -120,7 +124,8 @@ void Controller::onInlayHint(const InlayHintsParams &Params, // Perform inlay hints computation on the range. std::vector Response; NixpkgsInlayHintsProvider NP(*nixpkgsClient(), *TU->variableLookup(), - *TU->parentMap(), Range, Response); + *TU->parentMap(), Range, Response, + TU->src()); NP.dfs(AST.get()); Reply(std::move(Response)); } diff --git a/nixd/lib/Controller/NixTU.cpp b/nixd/lib/Controller/NixTU.cpp index 72e1adefc..8e5324ff7 100644 --- a/nixd/lib/Controller/NixTU.cpp +++ b/nixd/lib/Controller/NixTU.cpp @@ -5,9 +5,12 @@ using namespace nixd; NixTU::NixTU(std::vector Diagnostics, std::shared_ptr AST, std::optional ASTByteCode, - std::unique_ptr VLA) + std::unique_ptr VLA, + std::shared_ptr Src) : Diagnostics(std::move(Diagnostics)), AST(std::move(AST)), - ASTByteCode(std::move(ASTByteCode)), VLA(std::move(VLA)) { + ASTByteCode(std::move(ASTByteCode)), VLA(std::move(VLA)), + Src(std::move(Src)) { + assert(this->Src && "Source code should not be null"); if (this->AST) { PMA = std::make_unique(); PMA->runOnAST(*this->AST); diff --git a/nixd/lib/Controller/Rename.cpp b/nixd/lib/Controller/Rename.cpp index 5e675c1fe..41ba232b8 100644 --- a/nixd/lib/Controller/Rename.cpp +++ b/nixd/lib/Controller/Rename.cpp @@ -36,7 +36,8 @@ struct RenameBuiltinException : RenameException { WorkspaceEdit rename(const nixf::Node &Desc, const std::string &NewText, const ParentMapAnalysis &PMA, - const VariableLookupAnalysis &VLA, const URIForFile &URI) { + const VariableLookupAnalysis &VLA, const URIForFile &URI, + llvm::StringRef Src) { using lspserver::TextEdit; // Find "definition" auto Def = findDefinition(Desc, PMA, VLA); @@ -51,13 +52,13 @@ WorkspaceEdit rename(const nixf::Node &Desc, const std::string &NewText, for (const auto *Use : Def.uses()) { Edits.emplace_back(TextEdit{ - .range = toLSPRange(Use->range()), + .range = toLSPRange(Src, Use->range()), .newText = NewText, }); } Edits.emplace_back(TextEdit{ - .range = toLSPRange(Def.syntax()->range()), + .range = toLSPRange(Src, Def.syntax()->range()), .newText = NewText, }); WorkspaceEdit WE; @@ -83,7 +84,7 @@ void Controller::onRename(const RenameParams &Params, const auto &PM = *TU->parentMap(); const auto &VLA = *TU->variableLookup(); try { - return Reply(rename(*Desc, NewText, PM, VLA, URI)); + return Reply(rename(*Desc, NewText, PM, VLA, URI, TU->src())); } catch (std::exception &E) { return Reply(error(E.what())); } @@ -109,8 +110,8 @@ void Controller::onPrepareRename( const auto &PM = *TU->parentMap(); const auto &VLA = *TU->variableLookup(); try { - WorkspaceEdit WE = rename(*Desc, "", PM, VLA, URI); - return Reply(toLSPRange(Desc->range())); + WorkspaceEdit WE = rename(*Desc, "", PM, VLA, URI, TU->src()); + return Reply(toLSPRange(TU->src(), Desc->range())); } catch (std::exception &E) { return Reply(error(E.what())); } diff --git a/nixd/lib/Controller/SemanticTokens.cpp b/nixd/lib/Controller/SemanticTokens.cpp index b2f0dfe36..a8a090d4c 100644 --- a/nixd/lib/Controller/SemanticTokens.cpp +++ b/nixd/lib/Controller/SemanticTokens.cpp @@ -3,16 +3,20 @@ /// [Semantic Tokens]: /// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_semanticTokens +#include "Convert.h" + #include "nixd/Controller/Controller.h" -#include -#include #include #include #include #include #include +#include + +#include + using namespace nixd; using namespace lspserver; using namespace nixf; @@ -59,15 +63,15 @@ class SemanticTokenBuilder { std::vector Raw; + llvm::StringRef Src; + public: - SemanticTokenBuilder(const VariableLookupAnalysis &VLA) : VLA(VLA) {} + SemanticTokenBuilder(const VariableLookupAnalysis &VLA, llvm::StringRef Src) + : VLA(VLA), Src(Src) {} void addImpl(nixf::LexerCursor Pos, unsigned Length, unsigned TokenType, unsigned TokenModifiers) { - Raw.emplace_back(RawSemanticToken{ - {static_cast(Pos.line()), static_cast(Pos.column())}, - Length, - TokenType, - TokenModifiers}); + auto P = toLSPPosition(Src, Pos); + Raw.emplace_back(RawSemanticToken{P, Length, TokenType, TokenModifiers}); } void add(const Node &N, unsigned TokenType, unsigned TokenModifiers) { @@ -235,7 +239,7 @@ void Controller::onSemanticTokens(const SemanticTokensParams &Params, this]() mutable { if (std::shared_ptr TU = getTU(URI.file().str(), Reply)) { if (std::shared_ptr AST = getAST(*TU, Reply)) { - SemanticTokenBuilder Builder(*TU->variableLookup()); + SemanticTokenBuilder Builder(*TU->variableLookup(), TU->src()); Builder.dfs(AST.get()); Reply(SemanticTokens{.tokens = Builder.finish()}); } diff --git a/nixd/lib/Controller/Support.cpp b/nixd/lib/Controller/Support.cpp index 872d0d54a..f4b44bc9d 100644 --- a/nixd/lib/Controller/Support.cpp +++ b/nixd/lib/Controller/Support.cpp @@ -23,6 +23,7 @@ void Controller::actOnDocumentAdd(PathRef File, std::optional Version) { auto Action = [this, File = std::string(File), Version]() { auto Draft = Store.getDraft(File); + std::shared_ptr Src = Draft->Contents; assert(Draft && "Added document is not in the store?"); std::vector Diagnostics; @@ -31,24 +32,24 @@ void Controller::actOnDocumentAdd(PathRef File, if (!AST) { std::lock_guard G(TUsLock); - publishDiagnostics(File, Version, Diagnostics); + publishDiagnostics(File, Version, *Src, Diagnostics); TUs.insert_or_assign(File, std::make_shared(std::move(Diagnostics), std::move(AST), std::nullopt, - /*VLA=*/nullptr)); + /*VLA=*/nullptr, Src)); return; } auto VLA = std::make_unique(Diagnostics); VLA->runOnAST(*AST); - publishDiagnostics(File, Version, Diagnostics); + publishDiagnostics(File, Version, *Src, Diagnostics); { std::lock_guard G(TUsLock); TUs.insert_or_assign( File, std::make_shared(std::move(Diagnostics), std::move(AST), - std::nullopt, std::move(VLA))); + std::nullopt, std::move(VLA), Src)); return; } }; diff --git a/nixd/tools/nixd/test/utf16.md b/nixd/tools/nixd/test/utf16.md new file mode 100644 index 000000000..5e2e54599 --- /dev/null +++ b/nixd/tools/nixd/test/utf16.md @@ -0,0 +1,52 @@ +# RUN: nixd --lit-test < %s | FileCheck %s + +<-- initialize(0) + +```json +{ + "jsonrpc":"2.0", + "id":0, + "method":"initialize", + "params":{ + "processId":123, + "rootPath":"", + "capabilities":{ + }, + "trace":"off" + } +} +``` + +```json +{ + "jsonrpc":"2.0", + "method":"textDocument/didOpen", + "params":{ + "textDocument":{ + "uri":"file:///basic.nix", + "languageId":"nix", + "version":1, + "text":"{ a = 1; 测试文本 }" + } + } +} +``` + +``` + CHECK: "code": "parse-unexpected", +CHECK-NEXT: "message": "unexpected text (fix available)", +CHECK-NEXT: "range": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 13, +CHECK-NEXT: "line": 0 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 9, +CHECK-NEXT: "line": 0 +CHECK-NEXT: } +CHECK-NEXT: }, +``` + +```json +{"jsonrpc":"2.0","method":"exit"} +```