Skip to content

Commit adc3862

Browse files
nixd: enable completion and hover in config sets
In NixOS modules options can be defined at the top-level, e.g: { foo = true; } or inside of `config`, e.g: { config = { foo = true; }; } Autocompletion and hover information before only worked for the former because the option resolving code had no special handling for `config`. Fixes #566.
1 parent 3aa27fd commit adc3862

File tree

7 files changed

+190
-3
lines changed

7 files changed

+190
-3
lines changed

nixd/lib/Controller/AST.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,3 +315,19 @@ nixd::FindAttrPathResult nixd::findAttrPath(const nixf::Node &N,
315315

316316
return R::NotAttrPath;
317317
}
318+
319+
nixd::FindAttrPathResult
320+
nixd::findAttrPathForOptions(const nixf::Node &N,
321+
const nixf::ParentMapAnalysis &PM,
322+
std::vector<std::string> &Path) {
323+
324+
const auto R = findAttrPath(N, PM, Path);
325+
if (R == FindAttrPathResult::OK) {
326+
// FIXME: This is naive because it will wrongly strip away a top-level
327+
// "config" in a flake.nix.
328+
if (!Path.empty() && Path[0] == "config") {
329+
Path.erase(Path.begin());
330+
}
331+
}
332+
return R;
333+
}

nixd/lib/Controller/AST.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,4 +129,12 @@ FindAttrPathResult findAttrPath(const nixf::Node &N,
129129
const nixf::ParentMapAnalysis &PM,
130130
std::vector<std::string> &Path);
131131

132+
/// \brief Heuristically find attrpath suitable for "attrpath" completion.
133+
/// Strips "config." from the start to support config sections in NixOS modules.
134+
///
135+
/// \param[out] Path the attrpath.
136+
FindAttrPathResult findAttrPathForOptions(const nixf::Node &N,
137+
const nixf::ParentMapAnalysis &PM,
138+
std::vector<std::string> &Path);
139+
132140
} // namespace nixd

nixd/lib/Controller/Completion.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ void completeAttrPath(const Node &N, const ParentMapAnalysis &PM,
275275
std::vector<lspserver::CompletionItem> &Items) {
276276
std::vector<std::string> Scope;
277277
using PathResult = FindAttrPathResult;
278-
auto R = findAttrPath(N, PM, Scope);
278+
auto R = findAttrPathForOptions(N, PM, Scope);
279279
if (R == PathResult::OK) {
280280
// Construct request.
281281
std::string Prefix = Scope.back();

nixd/lib/Controller/Definition.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ Locations defineAttrPath(const Node &N, const ParentMapAnalysis &PM,
240240
Controller::OptionMapTy &Options) {
241241
using PathResult = FindAttrPathResult;
242242
std::vector<std::string> Scope;
243-
auto R = findAttrPath(N, PM, Scope);
243+
auto R = findAttrPathForOptions(N, PM, Scope);
244244
Locations Locs;
245245
if (R == PathResult::OK) {
246246
std::lock_guard _(OptionsLock);

nixd/lib/Controller/Hover.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ void Controller::onHover(const TextDocumentPositionParams &Params,
147147
}
148148

149149
auto Scope = std::vector<std::string>();
150-
const auto R = findAttrPath(N, PM, Scope);
150+
const auto R = findAttrPathForOptions(N, PM, Scope);
151151
if (R == FindAttrPathResult::OK) {
152152
std::lock_guard _(OptionsLock);
153153
for (const auto &[_, Client] : Options) {
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# RUN: nixd --lit-test \
2+
# RUN: --nixos-options-expr="{ foo.bar = { _type = \"option\"; }; }" \
3+
# RUN: < %s | FileCheck %s
4+
5+
<-- initialize(0)
6+
7+
```json
8+
{
9+
"jsonrpc":"2.0",
10+
"id":0,
11+
"method":"initialize",
12+
"params":{
13+
"processId":123,
14+
"rootPath":"",
15+
"capabilities":{
16+
},
17+
"trace":"off"
18+
}
19+
}
20+
```
21+
22+
23+
<-- textDocument/didOpen
24+
25+
26+
```json
27+
{
28+
"jsonrpc":"2.0",
29+
"method":"textDocument/didOpen",
30+
"params":{
31+
"textDocument":{
32+
"uri":"file:///completion.nix",
33+
"languageId":"nix",
34+
"version":1,
35+
"text":"{ config = { fo }; }"
36+
}
37+
}
38+
}
39+
```
40+
41+
```json
42+
{
43+
"jsonrpc": "2.0",
44+
"id": 1,
45+
"method": "textDocument/completion",
46+
"params": {
47+
"textDocument": {
48+
"uri": "file:///completion.nix"
49+
},
50+
"position": {
51+
"line": 0,
52+
"character": 15
53+
},
54+
"context": {
55+
"triggerKind": 1
56+
}
57+
}
58+
}
59+
```
60+
61+
```
62+
CHECK: "id": 1,
63+
CHECK-NEXT: "jsonrpc": "2.0",
64+
CHECK-NEXT: "result": {
65+
CHECK-NEXT: "isIncomplete": false,
66+
CHECK-NEXT: "items": [
67+
CHECK-NEXT: {
68+
CHECK-NEXT: "data": "",
69+
CHECK-NEXT: "detail": "nixos",
70+
CHECK-NEXT: "kind": 7,
71+
CHECK-NEXT: "label": "foo",
72+
CHECK-NEXT: "score": 0
73+
CHECK-NEXT: }
74+
CHECK-NEXT: ]
75+
CHECK-NEXT: }
76+
```
77+
78+
79+
```json
80+
{"jsonrpc":"2.0","method":"exit"}
81+
```
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# RUN: nixd --lit-test \
2+
# RUN: --nixos-options-expr="{ foo = { _type = \"option\"; description = \"test option\"; type.description = \"test type\"; }; }" \
3+
# RUN: < %s | FileCheck %s
4+
5+
<-- initialize(0)
6+
7+
```json
8+
{
9+
"jsonrpc":"2.0",
10+
"id":0,
11+
"method":"initialize",
12+
"params":{
13+
"processId":123,
14+
"rootPath":"",
15+
"capabilities":{
16+
},
17+
"trace":"off"
18+
}
19+
}
20+
```
21+
22+
23+
<-- textDocument/didOpen
24+
25+
26+
```json
27+
{
28+
"jsonrpc":"2.0",
29+
"method":"textDocument/didOpen",
30+
"params":{
31+
"textDocument":{
32+
"uri":"file:///test.nix",
33+
"languageId":"nix",
34+
"version":1,
35+
"text":"{ config = { foo }; }"
36+
}
37+
}
38+
}
39+
```
40+
41+
```json
42+
{
43+
"jsonrpc": "2.0",
44+
"id": 2,
45+
"method": "textDocument/hover",
46+
"params":{
47+
"textDocument":{
48+
"uri": "file:///test.nix"
49+
},
50+
"position":{
51+
"line": 0,
52+
"character": 15
53+
}
54+
}
55+
}
56+
```
57+
58+
```
59+
CHECK: "id": 2,
60+
CHECK-NEXT: "jsonrpc": "2.0",
61+
CHECK-NEXT: "result": {
62+
CHECK-NEXT: "contents": {
63+
CHECK-NEXT: "kind": "markdown",
64+
CHECK-NEXT: "value": " (test type)\n\ntest option"
65+
CHECK-NEXT: },
66+
CHECK-NEXT: "range": {
67+
CHECK-NEXT: "end": {
68+
CHECK-NEXT: "character": 16,
69+
CHECK-NEXT: "line": 0
70+
CHECK-NEXT: },
71+
CHECK-NEXT: "start": {
72+
CHECK-NEXT: "character": 13,
73+
CHECK-NEXT: "line": 0
74+
CHECK-NEXT: }
75+
CHECK-NEXT: }
76+
CHECK-NEXT: }
77+
```
78+
79+
80+
```json
81+
{"jsonrpc":"2.0","method":"exit"}
82+
```

0 commit comments

Comments
 (0)