Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'editors/code/src/snippets.ts')
-rw-r--r--editors/code/src/snippets.ts87
1 files changed, 36 insertions, 51 deletions
diff --git a/editors/code/src/snippets.ts b/editors/code/src/snippets.ts
index d81765649f..fb12125bcd 100644
--- a/editors/code/src/snippets.ts
+++ b/editors/code/src/snippets.ts
@@ -3,20 +3,28 @@ import * as vscode from "vscode";
import { assert } from "./util";
import { unwrapUndefinable } from "./undefinable";
-export async function applySnippetWorkspaceEdit(edit: vscode.WorkspaceEdit) {
- if (edit.entries().length === 1) {
- const [uri, edits] = unwrapUndefinable(edit.entries()[0]);
+export type SnippetTextDocumentEdit = [vscode.Uri, (vscode.TextEdit | vscode.SnippetTextEdit)[]];
+
+export async function applySnippetWorkspaceEdit(
+ edit: vscode.WorkspaceEdit,
+ editEntries: SnippetTextDocumentEdit[],
+) {
+ if (editEntries.length === 1) {
+ const [uri, edits] = unwrapUndefinable(editEntries[0]);
const editor = await editorFromUri(uri);
- if (editor) await applySnippetTextEdits(editor, edits);
+ if (editor) {
+ edit.set(uri, edits);
+ await vscode.workspace.applyEdit(edit);
+ }
return;
}
- for (const [uri, edits] of edit.entries()) {
+ for (const [uri, edits] of editEntries) {
const editor = await editorFromUri(uri);
if (editor) {
await editor.edit((builder) => {
for (const indel of edits) {
assert(
- !parseSnippet(indel.newText),
+ !(indel instanceof vscode.SnippetTextEdit),
`bad ws edit: snippet received with multiple edits: ${JSON.stringify(
edit,
)}`,
@@ -39,53 +47,30 @@ async function editorFromUri(uri: vscode.Uri): Promise<vscode.TextEditor | undef
}
export async function applySnippetTextEdits(editor: vscode.TextEditor, edits: vscode.TextEdit[]) {
- const selections: vscode.Selection[] = [];
- let lineDelta = 0;
- await editor.edit((builder) => {
- for (const indel of edits) {
- const parsed = parseSnippet(indel.newText);
- if (parsed) {
- const [newText, [placeholderStart, placeholderLength]] = parsed;
- const prefix = newText.substr(0, placeholderStart);
- const lastNewline = prefix.lastIndexOf("\n");
-
- const startLine = indel.range.start.line + lineDelta + countLines(prefix);
- const startColumn =
- lastNewline === -1
- ? indel.range.start.character + placeholderStart
- : prefix.length - lastNewline - 1;
- const endColumn = startColumn + placeholderLength;
- selections.push(
- new vscode.Selection(
- new vscode.Position(startLine, startColumn),
- new vscode.Position(startLine, endColumn),
- ),
- );
- builder.replace(indel.range, newText);
- } else {
- builder.replace(indel.range, indel.newText);
- }
- lineDelta +=
- countLines(indel.newText) - (indel.range.end.line - indel.range.start.line);
- }
- });
- if (selections.length > 0) editor.selections = selections;
- if (selections.length === 1) {
- const selection = unwrapUndefinable(selections[0]);
- editor.revealRange(selection, vscode.TextEditorRevealType.InCenterIfOutsideViewport);
- }
+ const edit = new vscode.WorkspaceEdit();
+ edit.set(editor.document.uri, toSnippetTextEdits(edits));
+ await vscode.workspace.applyEdit(edit);
}
-function parseSnippet(snip: string): [string, [number, number]] | undefined {
- const m = snip.match(/\$(0|\{0:([^}]*)\})/);
- if (!m) return undefined;
- const placeholder = m[2] ?? "";
- if (m.index == null) return undefined;
- const range: [number, number] = [m.index, placeholder.length];
- const insert = snip.replace(m[0], placeholder);
- return [insert, range];
+function hasSnippet(snip: string): boolean {
+ const m = snip.match(/\$\d+|\{\d+:[^}]*\}/);
+ return m != null;
}
-function countLines(text: string): number {
- return (text.match(/\n/g) || []).length;
+function toSnippetTextEdits(
+ edits: vscode.TextEdit[],
+): (vscode.TextEdit | vscode.SnippetTextEdit)[] {
+ return edits.map((textEdit) => {
+ // Note: text edits without any snippets are returned as-is instead of
+ // being wrapped in a SnippetTextEdit, as otherwise it would be
+ // treated as if it had a tab stop at the end.
+ if (hasSnippet(textEdit.newText)) {
+ return new vscode.SnippetTextEdit(
+ textEdit.range,
+ new vscode.SnippetString(textEdit.newText),
+ );
+ } else {
+ return textEdit;
+ }
+ });
}