Skip to content

Commit

Permalink
feat(cmds): support snippet text edit
Browse files Browse the repository at this point in the history
  • Loading branch information
fannheyward committed May 20, 2020
1 parent 8109959 commit e43fffc
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 2 deletions.
46 changes: 45 additions & 1 deletion src/client.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,26 @@
import { Executable, LanguageClient, LanguageClientOptions, ServerOptions, Uri, workspace } from 'coc.nvim';
import { Executable, LanguageClient, LanguageClientOptions, ServerOptions, StaticFeature, Uri, workspace } from 'coc.nvim';
import { ClientCapabilities, CodeAction, CodeActionParams, CodeActionRequest, Command, InsertTextFormat, TextDocumentEdit } from 'vscode-languageserver-protocol';

class SnippetTextEditFeature implements StaticFeature {
fillClientCapabilities(capabilities: ClientCapabilities): void {
const caps: any = capabilities.experimental ?? {};
caps.snippetTextEdit = true;
capabilities.experimental = caps;
}
initialize(): void {}
}

function isSnippetEdit(action: CodeAction): boolean {
const documentChanges = action.edit?.documentChanges ?? [];
for (const edit of documentChanges) {
if (TextDocumentEdit.is(edit)) {
if (edit.edits.some((indel) => (indel as any).insertTextFormat === InsertTextFormat.Snippet)) {
return true;
}
}
}
return false;
}

export function createClient(bin: string): LanguageClient {
let folder = '.';
Expand All @@ -24,6 +46,26 @@ export function createClient(bin: string): LanguageClient {
position.character = character - 1;
return help;
},
provideCodeActions(document, range, context, token) {
const params: CodeActionParams = {
textDocument: { uri: document.uri },
range,
context,
};
// eslint-disable-next-line @typescript-eslint/no-use-before-define
return client.sendRequest(CodeActionRequest.type, params, token).then((values) => {
if (values === null) return undefined;
const result: (CodeAction | Command)[] = [];
for (const item of values) {
if (CodeAction.is(item) && isSnippetEdit(item)) {
item.command = Command.create('', 'rust-analyzer.applySnippetWorkspaceEdit', item.edit);
item.edit = undefined;
}
result.push(item);
}
return result;
});
},
},
outputChannel,
};
Expand Down Expand Up @@ -51,5 +93,7 @@ export function createClient(bin: string): LanguageClient {
},
};
client.registerProposedFeatures();
client.registerFeature(new SnippetTextEditFeature());

return client;
}
31 changes: 30 additions & 1 deletion src/cmds/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { commands, Uri, workspace } from 'coc.nvim';
import { Location, Position } from 'vscode-languageserver-protocol';
import { Location, Position, Range, TextDocumentEdit, TextEdit, WorkspaceEdit } from 'vscode-languageserver-protocol';
import { Cmd, Ctx } from '../ctx';
import * as ra from '../rust-analyzer-api';
import * as sourceChange from '../source_change';
Expand Down Expand Up @@ -67,3 +67,32 @@ export function toggleInlayHints(ctx: Ctx) {
}
};
}

export function applySnippetWorkspaceEdit(): Cmd {
return async (edit: WorkspaceEdit) => {
if (edit.documentChanges && edit.documentChanges.length) {
let editWithSnippet: TextEdit | undefined = undefined;
let lineDelta = 0;

const edits = (edit.documentChanges as TextDocumentEdit[])[0].edits;
for (const indel of edits) {
const isSnippet = indel.newText.indexOf('$0') !== -1 || indel.newText.indexOf('${') !== -1;
if (isSnippet) {
editWithSnippet = indel;
} else {
if (!editWithSnippet) {
lineDelta = (indel.newText.match(/\n/g) || []).length - (indel.range.end.line - indel.range.start.line);
}
TextEdit.replace(indel.range, indel.newText);
}
}

if (editWithSnippet) {
const snip = editWithSnippet as TextEdit;
const range = Range.create(snip.range.start.line + lineDelta, snip.range.start.character, snip.range.end.line + lineDelta, snip.range.end.character);
snip.range = range;
await commands.executeCommand('editor.action.insertSnippet', snip);
}
}
};
}
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export async function activate(context: ExtensionContext): Promise<void> {

ctx.registerCommand('analyzerStatus', cmds.analyzerStatus);
ctx.registerCommand('applySourceChange', cmds.applySourceChange);
ctx.registerCommand('applySnippetWorkspaceEdit', cmds.applySnippetWorkspaceEdit);
ctx.registerCommand('selectAndApplySourceChange', cmds.selectAndApplySourceChange);
ctx.registerCommand('collectGarbage', cmds.collectGarbage);
ctx.registerCommand('expandMacro', cmds.expandMacro);
Expand Down

0 comments on commit e43fffc

Please sign in to comment.