Skip to content

Commit

Permalink
Adds partial codeactions (#13)
Browse files Browse the repository at this point in the history
  • Loading branch information
rpaul-stripe authored Oct 20, 2023
1 parent 97e92a9 commit 8baf207
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 8 deletions.
29 changes: 29 additions & 0 deletions client/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ export default class Extension {
...commands(),
this.status,
this.preview,
VSC.commands.registerCommand(
"markdoc.extractPartial",
this.onExtractPartial.bind(this)
),
VSC.commands.registerCommand(
"markdoc.newFileFromTemplate",
this.onNewFileFromTemplate.bind(this)
Expand Down Expand Up @@ -173,6 +177,31 @@ export default class Extension {
VSC.window.showTextDocument(doc);
}

async onExtractPartial() {
const editor = VSC.window.activeTextEditor;
if (!editor) return;

const uri = await VSC.window.showSaveDialog({
saveLabel: 'Create',
title: 'Name the new partial',
filters: {'Markdoc': ['md', 'mdoc', 'markdoc', 'markdoc.md']}
});

if (!uri) return;

const client = this.findClient(uri);
if (!client) return;

const path = uri.fsPath.slice(client.uri.fsPath.length + 1);
const partialTag = `{% partial file="${path}" /%}`;

const edit = new VSC.WorkspaceEdit();
const contents = new TextEncoder().encode(editor.document.getText(editor.selection));
edit.createFile(uri, {overwrite: true, contents});
edit.replace(editor.document.uri, editor.selection, partialTag);
VSC.workspace.applyEdit(edit);
}

async onPreview(previewUri: VSC.Uri) {
const uri = previewUri ?? VSC.window.activeTextEditor?.document.uri;
if (!uri) return;
Expand Down
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.10",
"version": "0.0.11",
"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.10",
"version": "0.0.11",
"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.10",
"version": "0.0.11",
"description": "A Markdoc language server",
"main": "dist/index.js",
"author": "Ryan Paul",
Expand Down
52 changes: 47 additions & 5 deletions server/plugins/codeaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,33 +32,75 @@ export default class CodeActionProvider {
}
}

findTables(ast: Markdoc.Node, params: LSP.CodeActionParams): LSP.CodeAction[] {
async inlinePartial(uri: string, line: number, file: string): Promise<LSP.WorkspaceEdit | void> {
const ast = this.services.Documents.ast(uri);
if (!ast) return;

for (const node of ast.walk()) {
if (node.tag === 'partial' && node.lines[0] === line && !node.attributes.variables) {
const fullPath = this.services.Scanner.fullPath(file);
const newText = await this.services.Scanner.read(fullPath);
const [start, end] = node.lines;
const range = LSP.Range.create(start, 0, end, 0);
return {changes: {[uri]: [{range, newText}]}};
}
}
}

findActions(ast: Markdoc.Node, params: LSP.CodeActionParams): LSP.CodeAction[] {
const output: LSP.CodeAction[] = [];
const {line} = params.range.start;
const {uri} = params.textDocument;

if (params.range.end.line - params.range.start.line > 3)
output.push({
title: 'Extract content to new partial',
command: LSP.Command.create('Extract Partial', 'markdoc.extractPartial')
});

for (const node of ast.walk())
if (node.type === 'table' && node.lines.includes(line))
for (const node of ast.walk()) {
if (node.type === 'table' && node.lines.includes(line)) {
output.push({
data: {type: 'convertTable', uri, line},
title: 'Convert to Markdoc Table',
});

continue;
}

if (node.tag === 'partial' && node.lines[0] === line && !node.attributes.variables) {
output.push({
data: {type: 'inlinePartial', uri, line, file: node.attributes.file},
title: 'Inline contents of this partial',
});

continue;
}
}

return output;
}

onCodeAction(params: LSP.CodeActionParams): (LSP.CodeAction | LSP.Command)[] {
const ast = this.services.Documents.ast(params.textDocument.uri);
return ast ? this.findTables(ast, params) : [];
return ast ? this.findActions(ast, params) : [];
}

onCodeActionResolve(action: LSP.CodeAction): LSP.CodeAction {
async onCodeActionResolve(action: LSP.CodeAction): Promise<LSP.CodeAction> {
if (!action.data?.type) return action;

if (action.data.type === 'convertTable') {
const {uri, line} = action.data;
const edit = this.convertTable(uri, line);
if (edit) return {...action, edit};
}

if (action.data.type === 'inlinePartial') {
const {uri, line, file} = action.data;
const edit = await this.inlinePartial(uri, line, file);
if (edit) return {...action, edit};
}

return action;
}
}

0 comments on commit 8baf207

Please sign in to comment.