diff --git a/src/vs/workbench/contrib/bulkEdit/browser/bulkTextEdits.ts b/src/vs/workbench/contrib/bulkEdit/browser/bulkTextEdits.ts index c63d63003c636..f69e60201f238 100644 --- a/src/vs/workbench/contrib/bulkEdit/browser/bulkTextEdits.ts +++ b/src/vs/workbench/contrib/bulkEdit/browser/bulkTextEdits.ts @@ -19,17 +19,19 @@ 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'; +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) { @@ -94,14 +96,28 @@ 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) })); + .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); } if (this._newEol !== undefined) { 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 { @@ -134,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); }