diff --git a/src/vs/editor/contrib/snippet/browser/snippetController2.ts b/src/vs/editor/contrib/snippet/browser/snippetController2.ts index fbf4764ba64d972e43429ce64622dbb76cd05268..4c210d851ac287af1202c33d7e5600fec37be19c 100644 --- a/src/vs/editor/contrib/snippet/browser/snippetController2.ts +++ b/src/vs/editor/contrib/snippet/browser/snippetController2.ts @@ -35,13 +35,11 @@ class SnippetSessions { } get isAtFirstPlaceholder(): boolean { - // return !this.empty && this._stack[0].isAtFirstPlaceholder; return this._stack.every(s => s.isAtFirstPlaceholder); } get isAtFinalPlaceholder(): boolean { - // return !this.empty && this._stack[0].isAtFinalPlaceholder; - return this._stack.every(s => s.isAtFinalPlaceholder); + return !this.empty && this._stack[0].isAtLastPlaceholder; } get isSelectionWithinPlaceholders(): boolean { @@ -61,7 +59,7 @@ class SnippetSessions { next(): void { for (let i = this._stack.length - 1; i >= 0; i--) { const snippet = this._stack[i]; - if (!snippet.isAtFinalPlaceholder) { + if (!snippet.isAtLastPlaceholder) { snippet.next(); break; } @@ -123,8 +121,8 @@ export class SnippetController2 { } const snippet = new SnippetSession(this._editor, template, overwriteBefore, overwriteAfter); - this._sessions.add(snippet); - snippet.insert(); + const newLen = this._sessions.add(snippet); + snippet.insert(newLen > 1); if (undoStopAfter) { this._editor.getModel().pushStackElement(); diff --git a/src/vs/editor/contrib/snippet/browser/snippetSession.ts b/src/vs/editor/contrib/snippet/browser/snippetSession.ts index de1eea466b9fc3e5ac188bcd2586c53c10b682f8..c4fcdaa3e413e81df89c78e4ce4ae088d28a372f 100644 --- a/src/vs/editor/contrib/snippet/browser/snippetSession.ts +++ b/src/vs/editor/contrib/snippet/browser/snippetSession.ts @@ -130,17 +130,11 @@ export class OneSnippet { } get isAtFirstPlaceholder() { - return this._placeholderGroupsIdx === 0 || this._placeholderGroups.length === 0; + return this._placeholderGroupsIdx <= 0 || this._placeholderGroups.length === 0; } - get isAtFinalPlaceholder() { - if (this._placeholderGroups.length === 0) { - return true; - } else if (this._placeholderGroupsIdx < 0) { - return false; - } else { - return this._placeholderGroups[this._placeholderGroupsIdx][0].isFinalTabstop; - } + get isAtLastPlaceholder() { + return this._placeholderGroupsIdx === this._placeholderGroups.length - 1; } get hasPlaceholder() { @@ -215,7 +209,7 @@ export class SnippetSession { dispose(this._snippets); } - insert(): void { + insert(ignoreFinalTabstops: boolean = false): void { const model = this._editor.getModel(); const edits: IIdentifiedSingleEditOperation[] = []; @@ -260,6 +254,17 @@ export class SnippetSession { const adjustedTemplate = SnippetSession.adjustWhitespace(model, start, this._template); const snippet = SnippetParser.parse(adjustedTemplate).resolveVariables(new EditorSnippetVariableResolver(model, snippetSelection)); + + // rewrite final-tabstop to some other placeholder because this + // snippet sits inside another snippet + if (ignoreFinalTabstops) { + for (const placeholder of snippet.placeholders) { + if (placeholder.isFinalTabstop) { + placeholder.index = String(snippet.placeholders.length); + } + } + } + const offset = model.getOffsetAt(start) + delta; delta += snippet.text.length - model.getValueLengthInRange(snippetSelection); @@ -304,8 +309,8 @@ export class SnippetSession { return this._snippets[0].isAtFirstPlaceholder; } - get isAtFinalPlaceholder() { - return this._snippets[0].isAtFinalPlaceholder; + get isAtLastPlaceholder() { + return this._snippets[0].isAtLastPlaceholder; } get hasPlaceholder() { diff --git a/src/vs/editor/contrib/snippet/test/browser/snippetController2.test.ts b/src/vs/editor/contrib/snippet/test/browser/snippetController2.test.ts index ce84d8796d83d63ef3785a6b5e4934ea674993d5..7a485ac4f6b21cb401330e89d3c46ebfb0841c45 100644 --- a/src/vs/editor/contrib/snippet/test/browser/snippetController2.test.ts +++ b/src/vs/editor/contrib/snippet/test/browser/snippetController2.test.ts @@ -154,8 +154,8 @@ suite('SnippetController2', function () { assertContextKeys(contextKeys, true, false, true); assertSelections(editor, new Selection(1, 1, 1, 7), new Selection(2, 5, 2, 11)); - ctrl.insert('farboo$1$0'); - assertSelections(editor, new Selection(1, 7, 1, 7), new Selection(2, 11, 2, 11)); + ctrl.insert('far$1boo$0'); + assertSelections(editor, new Selection(1, 4, 1, 4), new Selection(2, 8, 2, 8)); assertContextKeys(contextKeys, true, false, true); ctrl.next(); diff --git a/src/vs/editor/contrib/snippet/test/browser/snippetSession.test.ts b/src/vs/editor/contrib/snippet/test/browser/snippetSession.test.ts index 5d5db85fb93e8964b0d01f6c09ce6b41f465a917..4691eaad476dd1e917eaad7da360701b00d32ae8 100644 --- a/src/vs/editor/contrib/snippet/test/browser/snippetSession.test.ts +++ b/src/vs/editor/contrib/snippet/test/browser/snippetSession.test.ts @@ -257,22 +257,22 @@ suite('SnippetSession', function () { editor.trigger('test', 'type', { text: '333' }); session.next(); - assert.equal(session.isAtFinalPlaceholder, true); + assert.equal(session.isAtLastPlaceholder, true); }); test('snippets, gracefully move over final tabstop', function () { const session = new SnippetSession(editor, '${1}bar$0'); session.insert(); - assert.equal(session.isAtFinalPlaceholder, false); + assert.equal(session.isAtLastPlaceholder, false); assertSelections(editor, new Selection(1, 1, 1, 1), new Selection(2, 5, 2, 5)); session.next(); - assert.equal(session.isAtFinalPlaceholder, true); + assert.equal(session.isAtLastPlaceholder, true); assertSelections(editor, new Selection(1, 4, 1, 4), new Selection(2, 8, 2, 8)); session.next(); - assert.equal(session.isAtFinalPlaceholder, true); + assert.equal(session.isAtLastPlaceholder, true); assertSelections(editor, new Selection(1, 4, 1, 4), new Selection(2, 8, 2, 8)); }); @@ -285,11 +285,11 @@ suite('SnippetSession', function () { assert.equal(model.getValue(), 'log(XXX);function foo() {\n log(XXX);console.log(a);\n}'); session.next(); - assert.equal(session.isAtFinalPlaceholder, false); + assert.equal(session.isAtLastPlaceholder, false); // assertSelections(editor, new Selection(1, 7, 1, 7), new Selection(2, 11, 2, 11)); session.next(); - assert.equal(session.isAtFinalPlaceholder, true); + assert.equal(session.isAtLastPlaceholder, true); assertSelections(editor, new Selection(1, 10, 1, 10), new Selection(2, 14, 2, 14)); }); @@ -321,7 +321,7 @@ suite('SnippetSession', function () { // reset selection to placeholder session.next(); assert.equal(session.isSelectionWithinPlaceholders(), true); - assert.equal(session.isAtFinalPlaceholder, true); + assert.equal(session.isAtLastPlaceholder, true); assertSelections(editor, new Selection(1, 13, 1, 13), new Selection(2, 17, 2, 17)); }); @@ -341,11 +341,11 @@ suite('SnippetSession', function () { assertSelections(editor, new Selection(1, 6, 1, 10)); second.next(); - assert.equal(second.isAtFinalPlaceholder, true); + assert.equal(second.isAtLastPlaceholder, true); assertSelections(editor, new Selection(1, 10, 1, 10)); first.next(); - assert.equal(first.isAtFinalPlaceholder, true); + assert.equal(first.isAtLastPlaceholder, true); assertSelections(editor, new Selection(1, 13, 1, 13)); }); @@ -353,7 +353,7 @@ suite('SnippetSession', function () { const session = new SnippetSession(editor, 'farboo$0'); session.insert(); - assert.equal(session.isAtFinalPlaceholder, true); + assert.equal(session.isAtLastPlaceholder, true); assert.equal(session.isSelectionWithinPlaceholders(), false); editor.trigger('test', 'type', { text: 'XXX' }); @@ -368,7 +368,7 @@ suite('SnippetSession', function () { editor.setSelection(new Selection(1, 2, 1, 2)); assert.equal(session.isSelectionWithinPlaceholders(), false); - assert.equal(session.isAtFinalPlaceholder, true); + assert.equal(session.isAtLastPlaceholder, true); editor.trigger('test', 'type', { text: 'XXX' }); assert.equal(model.getLineContent(1), 'fXXXfarboounction foo() {');