Skip to content

Commit 4932167

Browse files
authored
Adds selection range provider (#3)
1 parent ad95f08 commit 4932167

File tree

4 files changed

+148
-1
lines changed

4 files changed

+148
-1
lines changed

server/plugins/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import FoldingProvider from "./folding";
55
import FormattingProvider from "./formatting";
66
import LinkedEditProvider from "./linkedEdit";
77
import LinkProvider from "./link";
8+
import SelectionRangeProvider from "./range";
89
import ValidationProvider from "./validation";
910
import Watch from "./watch";
1011

@@ -16,6 +17,7 @@ export {
1617
FormattingProvider,
1718
LinkedEditProvider,
1819
LinkProvider,
20+
SelectionRangeProvider,
1921
ValidationProvider,
2022
Watch,
2123
};

server/plugins/range.test.ts

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import * as LSP from "vscode-languageserver/node";
2+
import * as Markdoc from "@markdoc/markdoc";
3+
import * as assert from "node:assert";
4+
import { test } from "node:test";
5+
import SelectionRangeProvider from "./range";
6+
7+
const example1 = `
8+
# Example 1
9+
10+
{% foo %}
11+
test
12+
{% /foo %}
13+
`;
14+
15+
const example2 = `
16+
# Example 2
17+
18+
{% foo %}
19+
{% bar %}
20+
test
21+
22+
{% baz %}
23+
test
24+
{% /baz %}
25+
{% /bar %}
26+
27+
test
28+
{% /foo %}
29+
`;
30+
31+
const connectionMock = { onSelectionRanges(...args) {} };
32+
33+
test("folding provider", async (t) => {
34+
// @ts-expect-error
35+
const provider = new SelectionRangeProvider({}, connectionMock, {});
36+
37+
await t.test("simple example", () => {
38+
const ast = Markdoc.parse(example1);
39+
const range = provider.findSelectionRange(ast, LSP.Position.create(4, 3));
40+
assert.deepEqual(range, {
41+
parent: {
42+
parent: undefined,
43+
range: {
44+
start: { line: 3, character: 0 },
45+
end: { line: 6, character: 0 },
46+
},
47+
},
48+
range: {
49+
start: { line: 4, character: 0 },
50+
end: { line: 5, character: 0 },
51+
},
52+
});
53+
});
54+
55+
await t.test("nested example", () => {
56+
const ast = Markdoc.parse(example2);
57+
const range = provider.findSelectionRange(ast, LSP.Position.create(8, 3));
58+
const expected = {
59+
parent: {
60+
parent: {
61+
parent: {
62+
parent: {
63+
parent: {
64+
parent: undefined,
65+
range: {
66+
start: { line: 3, character: 0 },
67+
end: { line: 14, character: 0 },
68+
},
69+
},
70+
range: {
71+
start: { line: 4, character: 0 },
72+
end: { line: 13, character: 0 },
73+
},
74+
},
75+
range: {
76+
start: { line: 4, character: 0 },
77+
end: { line: 11, character: 0 },
78+
},
79+
},
80+
range: {
81+
start: { line: 5, character: 0 },
82+
end: { line: 10, character: 0 },
83+
},
84+
},
85+
range: {
86+
start: { line: 7, character: 0 },
87+
end: { line: 10, character: 0 },
88+
},
89+
},
90+
range: {
91+
start: { line: 8, character: 0 },
92+
end: { line: 9, character: 0 },
93+
},
94+
};
95+
96+
assert.deepEqual(range, expected);
97+
});
98+
});

server/plugins/range.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import * as LSP from "vscode-languageserver/node";
2+
import * as utils from "../utils";
3+
import type { Config, ServiceInstances } from "../types";
4+
import type * as Markdoc from "@markdoc/markdoc";
5+
6+
export default class SelectionRangeProvider {
7+
constructor(
8+
protected config: Config,
9+
protected connection: LSP.Connection,
10+
protected services: ServiceInstances
11+
) {
12+
connection.onSelectionRanges(this.onSelectionRange.bind(this));
13+
}
14+
15+
register(registration: LSP.BulkRegistration) {
16+
registration.add(LSP.SelectionRangeRequest.type, {
17+
documentSelector: null,
18+
});
19+
}
20+
21+
findSelectionRange(ast: Markdoc.Node, position: LSP.Position) {
22+
let currentRange: LSP.SelectionRange | undefined;
23+
for (const range of utils.getBlockRanges(ast)) {
24+
if (range.start > position.line) break;
25+
if (range.end > position.line) {
26+
currentRange = {
27+
range: LSP.Range.create(range.start + 1, 0, range.end, 0),
28+
parent: {
29+
range: LSP.Range.create(range.start, 0, range.end + 1, 0),
30+
parent: currentRange,
31+
},
32+
};
33+
}
34+
}
35+
36+
return currentRange ?? { range: LSP.Range.create(position, position) };
37+
}
38+
39+
onSelectionRange({ textDocument, positions }: LSP.SelectionRangeParams) {
40+
const ast = this.services.Documents.ast(textDocument.uri);
41+
if (ast)
42+
return positions.map((position) =>
43+
this.findSelectionRange(ast, position)
44+
);
45+
}
46+
}

server/plugins/validation.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,11 @@ export default class ValidationProvider {
3636
} = err;
3737

3838
return {
39+
code: error.id,
3940
range: this.createRange(line, error.location ?? location),
4041
severity: this.severity(error.level),
4142
message: error.message,
42-
source: `markdoc ${this.config.id ?? ""}`,
43+
source: `markdoc:${this.config.id ?? ""}`,
4344
};
4445
}
4546

0 commit comments

Comments
 (0)