From f7311af93722134d7f086f16d41e0b7c5b6c263a Mon Sep 17 00:00:00 2001 From: Johannes Date: Tue, 21 Jun 2022 17:49:22 +0200 Subject: [PATCH 1/2] don't escape text edits as snippets fixes https://github.com/microsoft/vscode/issues/152746 --- src/vs/workbench/contrib/bulkEdit/browser/bulkTextEdits.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/bulkEdit/browser/bulkTextEdits.ts b/src/vs/workbench/contrib/bulkEdit/browser/bulkTextEdits.ts index c63d63003c636..b5b95ebc79f8d 100644 --- a/src/vs/workbench/contrib/bulkEdit/browser/bulkTextEdits.ts +++ b/src/vs/workbench/contrib/bulkEdit/browser/bulkTextEdits.ts @@ -19,7 +19,6 @@ import { ResourceMap } from 'vs/base/common/map'; import { IModelService } from 'vs/editor/common/services/model'; import { ResourceTextEdit } from 'vs/editor/browser/services/bulkEditService'; import { CancellationToken } from 'vs/base/common/cancellation'; -import { SnippetParser } from 'vs/editor/contrib/snippet/browser/snippetParser'; import { performSnippetEdits } from 'vs/editor/contrib/snippet/browser/snippetController2'; type ValidationResult = { canApply: true } | { canApply: false; reason: URI }; @@ -94,8 +93,7 @@ class ModelEditTask implements IDisposable { apply(): void { if (this._edits.length > 0) { this._edits = this._edits - .sort((a, b) => Range.compareRangesUsingStarts(a.range, b.range)) - .map(edit => ({ ...edit, text: edit.text && SnippetParser.escape(edit.text) })); + .sort((a, b) => Range.compareRangesUsingStarts(a.range, b.range)); this.model.pushEditOperations(null, this._edits, () => null); } if (this._newEol !== undefined) { From 1fe0c4cda4968a1043d4b9766d9181d569e7b58e Mon Sep 17 00:00:00 2001 From: Johannes Date: Tue, 21 Jun 2022 18:49:55 +0200 Subject: [PATCH 2/2] tranform snippet into normal text whenever a snippet edit cannot be performed --- .../contrib/bulkEdit/browser/bulkTextEdits.ts | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/bulkEdit/browser/bulkTextEdits.ts b/src/vs/workbench/contrib/bulkEdit/browser/bulkTextEdits.ts index b5b95ebc79f8d..f69e60201f238 100644 --- a/src/vs/workbench/contrib/bulkEdit/browser/bulkTextEdits.ts +++ b/src/vs/workbench/contrib/bulkEdit/browser/bulkTextEdits.ts @@ -20,15 +20,18 @@ import { IModelService } from 'vs/editor/common/services/model'; import { ResourceTextEdit } from 'vs/editor/browser/services/bulkEditService'; import { CancellationToken } from 'vs/base/common/cancellation'; import { performSnippetEdits } from 'vs/editor/contrib/snippet/browser/snippetController2'; +import { SnippetParser } from 'vs/editor/contrib/snippet/browser/snippetParser'; type ValidationResult = { canApply: true } | { canApply: false; reason: URI }; +type ISingleSnippetEditOperation = ISingleEditOperation & { insertAsSnippet?: boolean }; + class ModelEditTask implements IDisposable { readonly model: ITextModel; private _expectedModelVersionId: number | undefined; - protected _edits: (ISingleEditOperation & { insertAsSnippet?: boolean })[]; + protected _edits: ISingleSnippetEditOperation[]; protected _newEol: EndOfLineSequence | undefined; constructor(private readonly _modelReference: IReference) { @@ -93,6 +96,7 @@ class ModelEditTask implements IDisposable { apply(): void { if (this._edits.length > 0) { this._edits = this._edits + .map(this._transformSnippetStringToInsertText, this) // no editor -> no snippet mode .sort((a, b) => Range.compareRangesUsingStarts(a.range, b.range)); this.model.pushEditOperations(null, this._edits, () => null); } @@ -100,6 +104,20 @@ class ModelEditTask implements IDisposable { this.model.pushEOL(this._newEol); } } + + protected _transformSnippetStringToInsertText(edit: ISingleSnippetEditOperation): ISingleSnippetEditOperation { + // transform a snippet edit (and only those) into a normal text edit + // for that we need to parse the snippet and get its actual text, e.g without placeholder + // or variable syntaxes + if (!edit.insertAsSnippet) { + return edit; + } + if (!edit.text) { + return edit; + } + const text = new SnippetParser().parse(edit.text, false, false).toString(); + return { ...edit, insertAsSnippet: false, text }; + } } class EditorEditTask extends ModelEditTask { @@ -132,6 +150,7 @@ class EditorEditTask extends ModelEditTask { } else { this._edits = this._edits + .map(this._transformSnippetStringToInsertText, this) // mixed edits (snippet and normal) -> no snippet mode .sort((a, b) => Range.compareRangesUsingStarts(a.range, b.range)); this._editor.executeEdits('', this._edits); }