Skip to content

Commit

Permalink
Adds symbol provider (#10)
Browse files Browse the repository at this point in the history
* Adds a symbol provider plugin

* Adds schema merging to schema service

* Increment version
  • Loading branch information
rpaul-stripe authored Aug 17, 2023
1 parent 815f159 commit f947f24
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 5 deletions.
2 changes: 1 addition & 1 deletion client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"description": "Markdoc Extension",
"author": "Ryan Paul",
"license": "MIT",
"version": "0.0.7",
"version": "0.0.8",
"scripts": {
"build": "esbuild index.ts --bundle --outdir=dist --sourcemap=linked --external:vscode --platform=node --format=cjs",
"build:server": "esbuild server.ts --bundle --outdir=dist --sourcemap=linked --external:vscode --platform=node --format=cjs"
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"author": "Ryan Paul",
"publisher": "stripe",
"license": "MIT",
"version": "0.0.7",
"version": "0.0.8",
"description": "A Markdoc language server and Visual Studio Code extension",
"repository": {
"type": "git",
Expand Down
2 changes: 1 addition & 1 deletion server/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@markdoc/language-server",
"version": "0.0.7",
"version": "0.0.8",
"description": "A Markdoc language server",
"main": "dist/index.js",
"author": "Ryan Paul",
Expand Down
2 changes: 2 additions & 0 deletions server/plugins/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import FormattingProvider from "./formatting";
import LinkedEditProvider from "./linkedEdit";
import LinkProvider from "./link";
import SelectionRangeProvider from "./range";
import SymbolProvider from "./symbols";
import ValidationProvider from "./validation";
import Watch from "./watch";

Expand All @@ -20,6 +21,7 @@ export {
LinkedEditProvider,
LinkProvider,
SelectionRangeProvider,
SymbolProvider,
ValidationProvider,
Watch,
};
58 changes: 58 additions & 0 deletions server/plugins/symbols.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import * as LSP from "vscode-languageserver/node";
import { toPlainText } from "../utils";
import type { Config, ServiceInstances } from "../types";
import type * as Markdoc from "@markdoc/markdoc";

export default class SymbolProvider {
constructor(
protected config: Config,
protected connection: LSP.Connection,
protected services: ServiceInstances
) {
connection.onDocumentSymbol(this.onDocumentSymbol.bind(this));
}

register(registration: LSP.BulkRegistration) {
registration.add(LSP.DocumentSymbolRequest.type, {
documentSelector: null,
});
}

headings(node: Markdoc.Node) {
let stack: Array<Partial<LSP.DocumentSymbol> & { level: number }> =
[{ level: 0, children: [] }];

for (const child of node.walk()) {
if (child.type !== "heading" || typeof child.attributes.level !== 'number')
continue;

const [start, finish] = child.lines;
if (!start || !finish) continue;

const range = LSP.Range.create(start, 0, finish + 1, 0);
const entry = {
name: `${"#".repeat(child.attributes.level)} ${toPlainText(child)}`,
level: child.attributes.level,
kind: LSP.SymbolKind.Key,
range,
selectionRange: range,
children: [],
};

while (entry.level <= stack[stack.length - 1].level)
stack.pop();

stack[stack.length - 1].children?.push(entry);

if (entry.level > stack[stack.length - 1].level)
stack.push(entry);
}

return stack[0].children;
}

onDocumentSymbol({ textDocument }: LSP.DocumentSymbolParams) {
const ast = this.services.Documents.ast(textDocument.uri);
return ast && this.headings(ast);
}
}
23 changes: 21 additions & 2 deletions server/services/schema.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as LSP from "vscode-languageserver/node";
import * as pathutil from "path";
import type * as Markdoc from "@markdoc/markdoc";
import * as Markdoc from "@markdoc/markdoc";
import type { Config } from "../types";

export default class Schema<TConfig extends Config = Config> {
Expand All @@ -17,7 +17,26 @@ export default class Schema<TConfig extends Config = Config> {
}

async reload() {
this.schema = await this.load();
const schema = await this.load();
this.schema = schema && this.merge(schema);
}

merge(config: Markdoc.Config) {
return {
...config,
tags: {
...Markdoc.tags,
...config.tags,
},
nodes: {
...Markdoc.nodes,
...config.nodes,
},
functions: {
...Markdoc.functions,
...config.functions,
},
};
}

async load(): Promise<Markdoc.Config | undefined> {
Expand Down
9 changes: 9 additions & 0 deletions server/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@ export async function* findFiles(
}
}

export function toPlainText(node: Markdoc.Node): string {
let output = "";
for (const child of node.walk())
if (child.type === "text")
output += child.attributes.content;

return output;
}

export function getContentRangeInLine(
line: number,
doc: TextDocument,
Expand Down

0 comments on commit f947f24

Please sign in to comment.