From eb9a079b42e4566a1e8a7700ca9aedca5179d63b Mon Sep 17 00:00:00 2001 From: Yingchi Long Date: Wed, 10 Apr 2024 05:48:22 +0800 Subject: [PATCH] nixd: support `textDocument/documentSymbol` (#406) --- nixd/include/nixd/Controller/Controller.h | 4 + nixd/lib/Controller/DocumentSymbol.cpp | 249 ++++++ nixd/lib/Controller/LifeTime.cpp | 1 + nixd/lib/Controller/Support.cpp | 2 + nixd/meson.build | 1 + .../nixd/test/document-symbol-dynamic-attr.md | 118 +++ nixd/tools/nixd/test/document-symbol.md | 758 ++++++++++++++++++ nixd/tools/nixd/test/initialize.md | 1 + 8 files changed, 1134 insertions(+) create mode 100644 nixd/lib/Controller/DocumentSymbol.cpp create mode 100644 nixd/tools/nixd/test/document-symbol-dynamic-attr.md create mode 100644 nixd/tools/nixd/test/document-symbol.md diff --git a/nixd/include/nixd/Controller/Controller.h b/nixd/include/nixd/Controller/Controller.h index c37438d9b..17f01fe8e 100644 --- a/nixd/include/nixd/Controller/Controller.h +++ b/nixd/include/nixd/Controller/Controller.h @@ -77,6 +77,10 @@ class Controller : public lspserver::LSPServer { void onHover(const lspserver::TextDocumentPositionParams &Params, lspserver::Callback> Reply); + void onDocumentSymbol( + const lspserver::DocumentSymbolParams &Params, + lspserver::Callback> Reply); + void onDefinition(const lspserver::TextDocumentPositionParams &Params, lspserver::Callback Reply); diff --git a/nixd/lib/Controller/DocumentSymbol.cpp b/nixd/lib/Controller/DocumentSymbol.cpp new file mode 100644 index 000000000..843f34699 --- /dev/null +++ b/nixd/lib/Controller/DocumentSymbol.cpp @@ -0,0 +1,249 @@ +/// \file +/// \brief Implementation of [Document Symbol]. +/// [Document Symbol]: +/// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_documentSymbol + +#include "Convert.h" + +#include "nixd/Controller/Controller.h" + +#include +#include +#include +#include +#include + +#include + +using namespace nixd; +using namespace lspserver; +using namespace nixf; + +namespace { + +std::string getLambdaName(const ExprLambda &Lambda) { + if (!Lambda.arg() || !Lambda.arg()->id()) + return "(anonymous lambda)"; + return Lambda.arg()->id()->name(); +} + +lspserver::Range getLambdaSelectionRage(const ExprLambda &Lambda) { + if (!Lambda.arg()) { + return toLSPRange(Lambda.range()); + } + + if (!Lambda.arg()->id()) { + assert(Lambda.arg()->formals()); + return toLSPRange(Lambda.arg()->formals()->range()); + } + return toLSPRange(Lambda.arg()->id()->range()); +} + +lspserver::Range getAttrRange(const Attribute &Attr) { + auto LCur = toLSPPosition(Attr.key().lCur()); + if (Attr.value()) + return {LCur, toLSPPosition(Attr.value()->rCur())}; + return {LCur, toLSPPosition(Attr.key().rCur())}; +} + +/// Make variable's entry rich. +void richVar(const ExprVar &Var, DocumentSymbol &Sym, + const VariableLookupAnalysis &VLA) { + if (Var.id().name() == "true" || Var.id().name() == "false") { + Sym.kind = SymbolKind::Boolean; + Sym.detail = "builtin boolean"; + return; + } + + if (Var.id().name() == "null") { + Sym.kind = SymbolKind::Null; + Sym.detail = "null"; + return; + } + + auto Result = VLA.query(Var); + using ResultKind = VariableLookupAnalysis::LookupResultKind; + if (Result.Kind == ResultKind::Defined) + Sym.kind = SymbolKind::Constant; + else if (Result.Kind == ResultKind::FromWith) + Sym.kind = SymbolKind::Variable; + else { + Sym.deprecated = true; + return; + } + + if (Result.Def->isBuiltin()) + Sym.kind = SymbolKind::Event; +} + +/// Collect document symbol on AST. +void collect(const Node *AST, std::vector &Symbols, + const VariableLookupAnalysis &VLA) { + if (!AST) + return; + switch (AST->kind()) { + + case Node::NK_ExprString: { + const auto &Str = static_cast(*AST); + DocumentSymbol Sym{ + .name = Str.isLiteral() ? Str.literal() : "(dynamic string)", + .detail = "string", + .kind = SymbolKind::String, + .deprecated = false, + .range = toLSPRange(Str.range()), + .selectionRange = toLSPRange(Str.range()), + .children = {}, + }; + Symbols.emplace_back(std::move(Sym)); + break; + } + case Node::NK_ExprInt: { + const auto &Int = static_cast(*AST); + DocumentSymbol Sym{ + .name = std::to_string(Int.value()), + .detail = "integer", + .kind = SymbolKind::Number, + .deprecated = false, + .range = toLSPRange(Int.range()), + .selectionRange = toLSPRange(Int.range()), + .children = {}, + }; + Symbols.emplace_back(std::move(Sym)); + break; + } + case Node::NK_ExprFloat: { + const auto &Float = static_cast(*AST); + DocumentSymbol Sym{ + .name = std::to_string(Float.value()), + .detail = "float", + .kind = SymbolKind::Number, + .deprecated = false, + .range = toLSPRange(Float.range()), + .selectionRange = toLSPRange(Float.range()), + .children = {}, + }; + Symbols.emplace_back(std::move(Sym)); + break; + } + case Node::NK_AttrName: { + const auto &AN = static_cast(*AST); + DocumentSymbol Sym{ + .name = AN.isStatic() ? AN.staticName() : "(dynamic attribute name)", + .detail = "attribute name", + .kind = SymbolKind::Property, + .deprecated = false, + .range = toLSPRange(AN.range()), + .selectionRange = toLSPRange(AN.range()), + .children = {}, + }; + Symbols.emplace_back(std::move(Sym)); + break; + } + case Node::NK_ExprVar: { + const auto &Var = static_cast(*AST); + DocumentSymbol Sym{ + .name = Var.id().name(), + .detail = "identifier", + .kind = SymbolKind::Variable, + .deprecated = false, + .range = toLSPRange(Var.range()), + .selectionRange = toLSPRange(Var.range()), + .children = {}, + }; + richVar(Var, Sym, VLA); + Symbols.emplace_back(std::move(Sym)); + break; + } + case Node::NK_ExprLambda: { + std::vector Children; + const auto &Lambda = static_cast(*AST); + collect(Lambda.body(), Children, VLA); + DocumentSymbol Sym{ + .name = getLambdaName(Lambda), + .detail = "lambda", + .kind = SymbolKind::Function, + .deprecated = false, + .range = toLSPRange(Lambda.range()), + .selectionRange = getLambdaSelectionRage(Lambda), + .children = std::move(Children), + }; + Symbols.emplace_back(std::move(Sym)); + break; + } + case Node::NK_ExprList: { + std::vector Children; + const auto &List = static_cast(*AST); + for (const Node *Ch : AST->children()) + collect(Ch, Children, VLA); + + DocumentSymbol Sym{ + .name = "{anonymous}", + .detail = "list", + .kind = SymbolKind::Array, + .deprecated = false, + .range = toLSPRange(List.range()), + .selectionRange = toLSPRange(List.range()), + .children = std::move(Children), + }; + Symbols.emplace_back(std::move(Sym)); + break; + } + case Node::NK_ExprAttrs: { + const SemaAttrs &SA = static_cast(*AST).sema(); + for (const auto &[Name, Attr] : SA.staticAttrs()) { + if (!Attr.value()) + continue; + std::vector Children; + collect(Attr.value(), Children, VLA); + DocumentSymbol Sym{ + .name = Name, + .detail = "attribute", + .kind = SymbolKind::Field, + .deprecated = false, + .range = getAttrRange(Attr), + .selectionRange = toLSPRange(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); + DocumentSymbol Sym{ + .name = "${dynamic attribute}", + .detail = "attribute", + .kind = SymbolKind::Field, + .deprecated = false, + .range = getAttrRange(Attr), + .selectionRange = toLSPRange(Attr.key().range()), + .children = std::move(Children), + }; + Symbols.emplace_back(std::move(Sym)); + } + break; + } + default: + // Trivial dispatch. Treat these symbol as same as this level. + for (const Node *Ch : AST->children()) + collect(Ch, Symbols, VLA); + break; + } +} + +} // namespace + +void Controller::onDocumentSymbol(const DocumentSymbolParams &Params, + Callback> Reply) { + auto Action = [Reply = std::move(Reply), URI = Params.textDocument.uri, + this]() mutable { + if (std::shared_ptr TU = + getTU(URI.file().str(), Reply, /*Ignore=*/true)) { + if (std::shared_ptr AST = getAST(*TU, Reply)) { + std::vector Symbols; + collect(AST.get(), Symbols, *TU->variableLookup()); + Reply(std::move(Symbols)); + } + } + }; + boost::asio::post(Pool, std::move(Action)); +} diff --git a/nixd/lib/Controller/LifeTime.cpp b/nixd/lib/Controller/LifeTime.cpp index c1f345c7f..7a83081c0 100644 --- a/nixd/lib/Controller/LifeTime.cpp +++ b/nixd/lib/Controller/LifeTime.cpp @@ -37,6 +37,7 @@ void Controller:: }, }, {"definitionProvider", true}, + {"documentSymbolProvider", true}, {"referencesProvider", true}, {"documentHighlightProvider", true}, {"hoverProvider", true}, diff --git a/nixd/lib/Controller/Support.cpp b/nixd/lib/Controller/Support.cpp index a57e91a27..91049d0d7 100644 --- a/nixd/lib/Controller/Support.cpp +++ b/nixd/lib/Controller/Support.cpp @@ -125,6 +125,8 @@ Controller::Controller(std::unique_ptr In, // Language Features Registry.addMethod("textDocument/definition", this, &Controller::onDefinition); + Registry.addMethod("textDocument/documentSymbol", this, + &Controller::onDocumentSymbol); Registry.addMethod("textDocument/references", this, &Controller::onReferences); Registry.addMethod("textDocument/documentHighlight", this, diff --git a/nixd/meson.build b/nixd/meson.build index 1fb997b29..c38471951 100644 --- a/nixd/meson.build +++ b/nixd/meson.build @@ -9,6 +9,7 @@ libnixd_lib = library( 'lib/Controller/Definition.cpp', 'lib/Controller/Diagnostics.cpp', 'lib/Controller/DocumentHighlight.cpp', + 'lib/Controller/DocumentSymbol.cpp', 'lib/Controller/EvalClient.cpp', 'lib/Controller/FindReferences.cpp', 'lib/Controller/Hover.cpp', diff --git a/nixd/tools/nixd/test/document-symbol-dynamic-attr.md b/nixd/tools/nixd/test/document-symbol-dynamic-attr.md new file mode 100644 index 000000000..82035c0c7 --- /dev/null +++ b/nixd/tools/nixd/test/document-symbol-dynamic-attr.md @@ -0,0 +1,118 @@ +# RUN: nixd --lit-test < %s | FileCheck %s + +<-- initialize(0) + +```json +{ + "jsonrpc":"2.0", + "id":0, + "method":"initialize", + "params":{ + "processId":123, + "rootPath":"", + "capabilities":{ + }, + "trace":"off" + } +} +``` + + +<-- textDocument/didOpen + + + +```json +{ + "jsonrpc":"2.0", + "method":"textDocument/didOpen", + "params":{ + "textDocument":{ + "uri":"file:///basic.nix", + "languageId":"nix", + "version":1, + "text":"{ ${builtins.foo} = bar; }" + } + } +} +``` + +<-- textDocument/documentSymbol(2) + + +```json +{ + "jsonrpc":"2.0", + "id":2, + "method":"textDocument/documentSymbol", + "params":{ + "textDocument":{ + "uri":"file:///basic.nix" + } + } +} +``` + +``` + CHECK: "id": 2, +CHECK-NEXT: "jsonrpc": "2.0", +CHECK-NEXT: "result": [ +CHECK-NEXT: { +CHECK-NEXT: "children": [ +CHECK-NEXT: { +CHECK-NEXT: "deprecated": true, +CHECK-NEXT: "detail": "identifier", +CHECK-NEXT: "kind": 13, +CHECK-NEXT: "name": "bar", +CHECK-NEXT: "range": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 23, +CHECK-NEXT: "line": 0 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 20, +CHECK-NEXT: "line": 0 +CHECK-NEXT: } +CHECK-NEXT: }, +CHECK-NEXT: "selectionRange": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 23, +CHECK-NEXT: "line": 0 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 20, +CHECK-NEXT: "line": 0 +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: ], +CHECK-NEXT: "detail": "attribute", +CHECK-NEXT: "kind": 8, +CHECK-NEXT: "name": "${dynamic attribute}", +CHECK-NEXT: "range": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 23, +CHECK-NEXT: "line": 0 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 2, +CHECK-NEXT: "line": 0 +CHECK-NEXT: } +CHECK-NEXT: }, +CHECK-NEXT: "selectionRange": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 17, +CHECK-NEXT: "line": 0 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 2, +CHECK-NEXT: "line": 0 +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: ] +``` + +```json +{"jsonrpc":"2.0","method":"exit"} +``` diff --git a/nixd/tools/nixd/test/document-symbol.md b/nixd/tools/nixd/test/document-symbol.md new file mode 100644 index 000000000..6216e7413 --- /dev/null +++ b/nixd/tools/nixd/test/document-symbol.md @@ -0,0 +1,758 @@ +# RUN: nixd --lit-test < %s | FileCheck %s + +<-- initialize(0) + +```json +{ + "jsonrpc":"2.0", + "id":0, + "method":"initialize", + "params":{ + "processId":123, + "rootPath":"", + "capabilities":{ + }, + "trace":"off" + } +} +``` + + +<-- textDocument/didOpen + + +```nix +{ + x = 1; + anonymousLambda = { a }: a; + namedLambda = a: a; + numbers = 1 + 2.0; + bool = true; + bool2= false; + string = "1"; + string2 = "${builtins.foo}"; + undefined = x; + list = [ 1 2 3 ]; + null = null; + wit = with builtins; [ a b c]; +} +``` + +```json +{ + "jsonrpc":"2.0", + "method":"textDocument/didOpen", + "params":{ + "textDocument":{ + "uri":"file:///basic.nix", + "languageId":"nix", + "version":1, + "text":"{\n x = 1;\n anonymousLambda = { a }: a;\n namedLambda = a: a;\n numbers = 1 + 2.0;\n bool = true;\n bool2= false;\n string = \"1\";\n string2 = \"${builtins.foo}\";\n undefined = x;\n list = [ 1 2 3 ];\n}\n" + } + } +} +``` + +<-- textDocument/documentSymbol(2) + + +```json +{ + "jsonrpc":"2.0", + "id":2, + "method":"textDocument/documentSymbol", + "params":{ + "textDocument":{ + "uri":"file:///basic.nix" + } + } +} +``` + +``` + CHECK: "id": 2, +CHECK-NEXT: "jsonrpc": "2.0", +CHECK-NEXT: "result": [ +CHECK-NEXT: { +CHECK-NEXT: "children": [ +CHECK-NEXT: { +CHECK-NEXT: "children": [ +CHECK-NEXT: { +CHECK-NEXT: "detail": "identifier", +CHECK-NEXT: "kind": 14, +CHECK-NEXT: "name": "a", +CHECK-NEXT: "range": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 30, +CHECK-NEXT: "line": 2 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 29, +CHECK-NEXT: "line": 2 +CHECK-NEXT: } +CHECK-NEXT: }, +CHECK-NEXT: "selectionRange": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 30, +CHECK-NEXT: "line": 2 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 29, +CHECK-NEXT: "line": 2 +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: ], +CHECK-NEXT: "detail": "lambda", +CHECK-NEXT: "kind": 12, +CHECK-NEXT: "name": "(anonymous lambda)", +CHECK-NEXT: "range": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 30, +CHECK-NEXT: "line": 2 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 22, +CHECK-NEXT: "line": 2 +CHECK-NEXT: } +CHECK-NEXT: }, +CHECK-NEXT: "selectionRange": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 27, +CHECK-NEXT: "line": 2 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 22, +CHECK-NEXT: "line": 2 +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: ], +CHECK-NEXT: "detail": "attribute", +CHECK-NEXT: "kind": 8, +CHECK-NEXT: "name": "anonymousLambda", +CHECK-NEXT: "range": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 30, +CHECK-NEXT: "line": 2 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 4, +CHECK-NEXT: "line": 2 +CHECK-NEXT: } +CHECK-NEXT: }, +CHECK-NEXT: "selectionRange": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 19, +CHECK-NEXT: "line": 2 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 4, +CHECK-NEXT: "line": 2 +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: }, +CHECK-NEXT: { +CHECK-NEXT: "children": [ +CHECK-NEXT: { +CHECK-NEXT: "detail": "builtin boolean", +CHECK-NEXT: "kind": 17, +CHECK-NEXT: "name": "true", +CHECK-NEXT: "range": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 15, +CHECK-NEXT: "line": 5 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 11, +CHECK-NEXT: "line": 5 +CHECK-NEXT: } +CHECK-NEXT: }, +CHECK-NEXT: "selectionRange": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 15, +CHECK-NEXT: "line": 5 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 11, +CHECK-NEXT: "line": 5 +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: ], +CHECK-NEXT: "detail": "attribute", +CHECK-NEXT: "kind": 8, +CHECK-NEXT: "name": "bool", +CHECK-NEXT: "range": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 15, +CHECK-NEXT: "line": 5 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 4, +CHECK-NEXT: "line": 5 +CHECK-NEXT: } +CHECK-NEXT: }, +CHECK-NEXT: "selectionRange": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 8, +CHECK-NEXT: "line": 5 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 4, +CHECK-NEXT: "line": 5 +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: }, +CHECK-NEXT: { +CHECK-NEXT: "children": [ +CHECK-NEXT: { +CHECK-NEXT: "detail": "builtin boolean", +CHECK-NEXT: "kind": 17, +CHECK-NEXT: "name": "false", +CHECK-NEXT: "range": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 16, +CHECK-NEXT: "line": 6 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 11, +CHECK-NEXT: "line": 6 +CHECK-NEXT: } +CHECK-NEXT: }, +CHECK-NEXT: "selectionRange": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 16, +CHECK-NEXT: "line": 6 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 11, +CHECK-NEXT: "line": 6 +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: ], +CHECK-NEXT: "detail": "attribute", +CHECK-NEXT: "kind": 8, +CHECK-NEXT: "name": "bool2", +CHECK-NEXT: "range": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 16, +CHECK-NEXT: "line": 6 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 4, +CHECK-NEXT: "line": 6 +CHECK-NEXT: } +CHECK-NEXT: }, +CHECK-NEXT: "selectionRange": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 9, +CHECK-NEXT: "line": 6 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 4, +CHECK-NEXT: "line": 6 +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: }, +CHECK-NEXT: { +CHECK-NEXT: "children": [ +CHECK-NEXT: { +CHECK-NEXT: "children": [ +CHECK-NEXT: { +CHECK-NEXT: "detail": "integer", +CHECK-NEXT: "kind": 16, +CHECK-NEXT: "name": "1", +CHECK-NEXT: "range": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 14, +CHECK-NEXT: "line": 10 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 13, +CHECK-NEXT: "line": 10 +CHECK-NEXT: } +CHECK-NEXT: }, +CHECK-NEXT: "selectionRange": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 14, +CHECK-NEXT: "line": 10 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 13, +CHECK-NEXT: "line": 10 +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: }, +CHECK-NEXT: { +CHECK-NEXT: "detail": "integer", +CHECK-NEXT: "kind": 16, +CHECK-NEXT: "name": "2", +CHECK-NEXT: "range": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 16, +CHECK-NEXT: "line": 10 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 15, +CHECK-NEXT: "line": 10 +CHECK-NEXT: } +CHECK-NEXT: }, +CHECK-NEXT: "selectionRange": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 16, +CHECK-NEXT: "line": 10 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 15, +CHECK-NEXT: "line": 10 +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: }, +CHECK-NEXT: { +CHECK-NEXT: "detail": "integer", +CHECK-NEXT: "kind": 16, +CHECK-NEXT: "name": "3", +CHECK-NEXT: "range": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 18, +CHECK-NEXT: "line": 10 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 17, +CHECK-NEXT: "line": 10 +CHECK-NEXT: } +CHECK-NEXT: }, +CHECK-NEXT: "selectionRange": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 18, +CHECK-NEXT: "line": 10 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 17, +CHECK-NEXT: "line": 10 +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: ], +CHECK-NEXT: "detail": "list", +CHECK-NEXT: "kind": 18, +CHECK-NEXT: "name": "{anonymous}", +CHECK-NEXT: "range": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 20, +CHECK-NEXT: "line": 10 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 11, +CHECK-NEXT: "line": 10 +CHECK-NEXT: } +CHECK-NEXT: }, +CHECK-NEXT: "selectionRange": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 20, +CHECK-NEXT: "line": 10 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 11, +CHECK-NEXT: "line": 10 +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: ], +CHECK-NEXT: "detail": "attribute", +CHECK-NEXT: "kind": 8, +CHECK-NEXT: "name": "list", +CHECK-NEXT: "range": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 20, +CHECK-NEXT: "line": 10 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 4, +CHECK-NEXT: "line": 10 +CHECK-NEXT: } +CHECK-NEXT: }, +CHECK-NEXT: "selectionRange": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 8, +CHECK-NEXT: "line": 10 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 4, +CHECK-NEXT: "line": 10 +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: }, +CHECK-NEXT: { +CHECK-NEXT: "children": [ +CHECK-NEXT: { +CHECK-NEXT: "children": [ +CHECK-NEXT: { +CHECK-NEXT: "detail": "identifier", +CHECK-NEXT: "kind": 14, +CHECK-NEXT: "name": "a", +CHECK-NEXT: "range": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 22, +CHECK-NEXT: "line": 3 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 21, +CHECK-NEXT: "line": 3 +CHECK-NEXT: } +CHECK-NEXT: }, +CHECK-NEXT: "selectionRange": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 22, +CHECK-NEXT: "line": 3 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 21, +CHECK-NEXT: "line": 3 +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: ], +CHECK-NEXT: "detail": "lambda", +CHECK-NEXT: "kind": 12, +CHECK-NEXT: "name": "a", +CHECK-NEXT: "range": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 22, +CHECK-NEXT: "line": 3 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 18, +CHECK-NEXT: "line": 3 +CHECK-NEXT: } +CHECK-NEXT: }, +CHECK-NEXT: "selectionRange": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 19, +CHECK-NEXT: "line": 3 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 18, +CHECK-NEXT: "line": 3 +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: ], +CHECK-NEXT: "detail": "attribute", +CHECK-NEXT: "kind": 8, +CHECK-NEXT: "name": "namedLambda", +CHECK-NEXT: "range": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 22, +CHECK-NEXT: "line": 3 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 4, +CHECK-NEXT: "line": 3 +CHECK-NEXT: } +CHECK-NEXT: }, +CHECK-NEXT: "selectionRange": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 15, +CHECK-NEXT: "line": 3 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 4, +CHECK-NEXT: "line": 3 +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: }, +CHECK-NEXT: { +CHECK-NEXT: "children": [ +CHECK-NEXT: { +CHECK-NEXT: "detail": "integer", +CHECK-NEXT: "kind": 16, +CHECK-NEXT: "name": "1", +CHECK-NEXT: "range": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 15, +CHECK-NEXT: "line": 4 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 14, +CHECK-NEXT: "line": 4 +CHECK-NEXT: } +CHECK-NEXT: }, +CHECK-NEXT: "selectionRange": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 15, +CHECK-NEXT: "line": 4 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 14, +CHECK-NEXT: "line": 4 +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: }, +CHECK-NEXT: { +CHECK-NEXT: "detail": "float", +CHECK-NEXT: "kind": 16, +CHECK-NEXT: "name": "2.000000", +CHECK-NEXT: "range": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 21, +CHECK-NEXT: "line": 4 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 18, +CHECK-NEXT: "line": 4 +CHECK-NEXT: } +CHECK-NEXT: }, +CHECK-NEXT: "selectionRange": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 21, +CHECK-NEXT: "line": 4 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 18, +CHECK-NEXT: "line": 4 +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: ], +CHECK-NEXT: "detail": "attribute", +CHECK-NEXT: "kind": 8, +CHECK-NEXT: "name": "numbers", +CHECK-NEXT: "range": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 21, +CHECK-NEXT: "line": 4 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 4, +CHECK-NEXT: "line": 4 +CHECK-NEXT: } +CHECK-NEXT: }, +CHECK-NEXT: "selectionRange": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 11, +CHECK-NEXT: "line": 4 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 4, +CHECK-NEXT: "line": 4 +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: }, +CHECK-NEXT: { +CHECK-NEXT: "children": [ +CHECK-NEXT: { +CHECK-NEXT: "detail": "string", +CHECK-NEXT: "kind": 15, +CHECK-NEXT: "name": "1", +CHECK-NEXT: "range": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 16, +CHECK-NEXT: "line": 7 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 13, +CHECK-NEXT: "line": 7 +CHECK-NEXT: } +CHECK-NEXT: }, +CHECK-NEXT: "selectionRange": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 16, +CHECK-NEXT: "line": 7 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 13, +CHECK-NEXT: "line": 7 +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: ], +CHECK-NEXT: "detail": "attribute", +CHECK-NEXT: "kind": 8, +CHECK-NEXT: "name": "string", +CHECK-NEXT: "range": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 16, +CHECK-NEXT: "line": 7 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 4, +CHECK-NEXT: "line": 7 +CHECK-NEXT: } +CHECK-NEXT: }, +CHECK-NEXT: "selectionRange": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 10, +CHECK-NEXT: "line": 7 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 4, +CHECK-NEXT: "line": 7 +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: }, +CHECK-NEXT: { +CHECK-NEXT: "children": [ +CHECK-NEXT: { +CHECK-NEXT: "detail": "string", +CHECK-NEXT: "kind": 15, +CHECK-NEXT: "name": "(dynamic string)", +CHECK-NEXT: "range": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 31, +CHECK-NEXT: "line": 8 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 14, +CHECK-NEXT: "line": 8 +CHECK-NEXT: } +CHECK-NEXT: }, +CHECK-NEXT: "selectionRange": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 31, +CHECK-NEXT: "line": 8 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 14, +CHECK-NEXT: "line": 8 +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: ], +CHECK-NEXT: "detail": "attribute", +CHECK-NEXT: "kind": 8, +CHECK-NEXT: "name": "string2", +CHECK-NEXT: "range": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 31, +CHECK-NEXT: "line": 8 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 4, +CHECK-NEXT: "line": 8 +CHECK-NEXT: } +CHECK-NEXT: }, +CHECK-NEXT: "selectionRange": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 11, +CHECK-NEXT: "line": 8 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 4, +CHECK-NEXT: "line": 8 +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: }, +CHECK-NEXT: { +CHECK-NEXT: "children": [ +CHECK-NEXT: { +CHECK-NEXT: "deprecated": true, +CHECK-NEXT: "detail": "identifier", +CHECK-NEXT: "kind": 13, +CHECK-NEXT: "name": "x", +CHECK-NEXT: "range": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 17, +CHECK-NEXT: "line": 9 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 16, +CHECK-NEXT: "line": 9 +CHECK-NEXT: } +CHECK-NEXT: }, +CHECK-NEXT: "selectionRange": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 17, +CHECK-NEXT: "line": 9 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 16, +CHECK-NEXT: "line": 9 +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: ], +CHECK-NEXT: "detail": "attribute", +CHECK-NEXT: "kind": 8, +CHECK-NEXT: "name": "undefined", +CHECK-NEXT: "range": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 17, +CHECK-NEXT: "line": 9 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 4, +CHECK-NEXT: "line": 9 +CHECK-NEXT: } +CHECK-NEXT: }, +CHECK-NEXT: "selectionRange": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 13, +CHECK-NEXT: "line": 9 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 4, +CHECK-NEXT: "line": 9 +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: }, +CHECK-NEXT: { +CHECK-NEXT: "children": [ +CHECK-NEXT: { +CHECK-NEXT: "detail": "integer", +CHECK-NEXT: "kind": 16, +CHECK-NEXT: "name": "1", +CHECK-NEXT: "range": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 9, +CHECK-NEXT: "line": 1 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 8, +CHECK-NEXT: "line": 1 +CHECK-NEXT: } +CHECK-NEXT: }, +CHECK-NEXT: "selectionRange": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 9, +CHECK-NEXT: "line": 1 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 8, +CHECK-NEXT: "line": 1 +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: ], +CHECK-NEXT: "detail": "attribute", +CHECK-NEXT: "kind": 8, +CHECK-NEXT: "name": "x", +CHECK-NEXT: "range": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 9, +CHECK-NEXT: "line": 1 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 4, +CHECK-NEXT: "line": 1 +CHECK-NEXT: } +CHECK-NEXT: }, +CHECK-NEXT: "selectionRange": { +CHECK-NEXT: "end": { +CHECK-NEXT: "character": 5, +CHECK-NEXT: "line": 1 +CHECK-NEXT: }, +CHECK-NEXT: "start": { +CHECK-NEXT: "character": 4, +CHECK-NEXT: "line": 1 +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: } +CHECK-NEXT: ] +``` + +```json +{"jsonrpc":"2.0","method":"exit"} +``` diff --git a/nixd/tools/nixd/test/initialize.md b/nixd/tools/nixd/test/initialize.md index 1c1419de4..3012c4ebc 100644 --- a/nixd/tools/nixd/test/initialize.md +++ b/nixd/tools/nixd/test/initialize.md @@ -34,6 +34,7 @@ CHECK-NEXT: "resolveProvider": false CHECK-NEXT: }, CHECK-NEXT: "definitionProvider": true, CHECK-NEXT: "documentHighlightProvider": true, +CHECK-NEXT: "documentSymbolProvider": true, CHECK-NEXT: "hoverProvider": true, CHECK-NEXT: "referencesProvider": true, CHECK-NEXT: "renameProvider": {