Skip to content

Commit f947f24

Browse files
authored
Adds symbol provider (#10)
* Adds a symbol provider plugin * Adds schema merging to schema service * Increment version
1 parent 815f159 commit f947f24

File tree

7 files changed

+93
-5
lines changed

7 files changed

+93
-5
lines changed

client/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"description": "Markdoc Extension",
44
"author": "Ryan Paul",
55
"license": "MIT",
6-
"version": "0.0.7",
6+
"version": "0.0.8",
77
"scripts": {
88
"build": "esbuild index.ts --bundle --outdir=dist --sourcemap=linked --external:vscode --platform=node --format=cjs",
99
"build:server": "esbuild server.ts --bundle --outdir=dist --sourcemap=linked --external:vscode --platform=node --format=cjs"

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"author": "Ryan Paul",
88
"publisher": "stripe",
99
"license": "MIT",
10-
"version": "0.0.7",
10+
"version": "0.0.8",
1111
"description": "A Markdoc language server and Visual Studio Code extension",
1212
"repository": {
1313
"type": "git",

server/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@markdoc/language-server",
3-
"version": "0.0.7",
3+
"version": "0.0.8",
44
"description": "A Markdoc language server",
55
"main": "dist/index.js",
66
"author": "Ryan Paul",

server/plugins/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import FormattingProvider from "./formatting";
77
import LinkedEditProvider from "./linkedEdit";
88
import LinkProvider from "./link";
99
import SelectionRangeProvider from "./range";
10+
import SymbolProvider from "./symbols";
1011
import ValidationProvider from "./validation";
1112
import Watch from "./watch";
1213

@@ -20,6 +21,7 @@ export {
2021
LinkedEditProvider,
2122
LinkProvider,
2223
SelectionRangeProvider,
24+
SymbolProvider,
2325
ValidationProvider,
2426
Watch,
2527
};

server/plugins/symbols.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import * as LSP from "vscode-languageserver/node";
2+
import { toPlainText } from "../utils";
3+
import type { Config, ServiceInstances } from "../types";
4+
import type * as Markdoc from "@markdoc/markdoc";
5+
6+
export default class SymbolProvider {
7+
constructor(
8+
protected config: Config,
9+
protected connection: LSP.Connection,
10+
protected services: ServiceInstances
11+
) {
12+
connection.onDocumentSymbol(this.onDocumentSymbol.bind(this));
13+
}
14+
15+
register(registration: LSP.BulkRegistration) {
16+
registration.add(LSP.DocumentSymbolRequest.type, {
17+
documentSelector: null,
18+
});
19+
}
20+
21+
headings(node: Markdoc.Node) {
22+
let stack: Array<Partial<LSP.DocumentSymbol> & { level: number }> =
23+
[{ level: 0, children: [] }];
24+
25+
for (const child of node.walk()) {
26+
if (child.type !== "heading" || typeof child.attributes.level !== 'number')
27+
continue;
28+
29+
const [start, finish] = child.lines;
30+
if (!start || !finish) continue;
31+
32+
const range = LSP.Range.create(start, 0, finish + 1, 0);
33+
const entry = {
34+
name: `${"#".repeat(child.attributes.level)} ${toPlainText(child)}`,
35+
level: child.attributes.level,
36+
kind: LSP.SymbolKind.Key,
37+
range,
38+
selectionRange: range,
39+
children: [],
40+
};
41+
42+
while (entry.level <= stack[stack.length - 1].level)
43+
stack.pop();
44+
45+
stack[stack.length - 1].children?.push(entry);
46+
47+
if (entry.level > stack[stack.length - 1].level)
48+
stack.push(entry);
49+
}
50+
51+
return stack[0].children;
52+
}
53+
54+
onDocumentSymbol({ textDocument }: LSP.DocumentSymbolParams) {
55+
const ast = this.services.Documents.ast(textDocument.uri);
56+
return ast && this.headings(ast);
57+
}
58+
}

server/services/schema.ts

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as LSP from "vscode-languageserver/node";
22
import * as pathutil from "path";
3-
import type * as Markdoc from "@markdoc/markdoc";
3+
import * as Markdoc from "@markdoc/markdoc";
44
import type { Config } from "../types";
55

66
export default class Schema<TConfig extends Config = Config> {
@@ -17,7 +17,26 @@ export default class Schema<TConfig extends Config = Config> {
1717
}
1818

1919
async reload() {
20-
this.schema = await this.load();
20+
const schema = await this.load();
21+
this.schema = schema && this.merge(schema);
22+
}
23+
24+
merge(config: Markdoc.Config) {
25+
return {
26+
...config,
27+
tags: {
28+
...Markdoc.tags,
29+
...config.tags,
30+
},
31+
nodes: {
32+
...Markdoc.nodes,
33+
...config.nodes,
34+
},
35+
functions: {
36+
...Markdoc.functions,
37+
...config.functions,
38+
},
39+
};
2140
}
2241

2342
async load(): Promise<Markdoc.Config | undefined> {

server/utils.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,15 @@ export async function* findFiles(
1919
}
2020
}
2121

22+
export function toPlainText(node: Markdoc.Node): string {
23+
let output = "";
24+
for (const child of node.walk())
25+
if (child.type === "text")
26+
output += child.attributes.content;
27+
28+
return output;
29+
}
30+
2231
export function getContentRangeInLine(
2332
line: number,
2433
doc: TextDocument,

0 commit comments

Comments
 (0)