diff --git a/src/vs/editor/contrib/snippet/browser/snippetParser.ts b/src/vs/editor/contrib/snippet/browser/snippetParser.ts
index da4b4629d7d5b..f262ddf34dcfd 100644
--- a/src/vs/editor/contrib/snippet/browser/snippetParser.ts
+++ b/src/vs/editor/contrib/snippet/browser/snippetParser.ts
@@ -165,6 +165,13 @@ export abstract class Marker {
return this._children;
}
+ get rightMostDescendant(): Marker {
+ if (this._children.length > 0) {
+ return this._children[this._children.length - 1].rightMostDescendant;
+ }
+ return this;
+ }
+
get snippet(): TextmateSnippet | undefined {
let candidate: Marker = this;
while (true) {
diff --git a/src/vs/editor/contrib/snippet/browser/snippetSession.ts b/src/vs/editor/contrib/snippet/browser/snippetSession.ts
index a25ee16b15ca0..c50df9d79142b 100644
--- a/src/vs/editor/contrib/snippet/browser/snippetSession.ts
+++ b/src/vs/editor/contrib/snippet/browser/snippetSession.ts
@@ -208,9 +208,23 @@ export class OneSnippet {
return this._snippet.placeholders.length > 0;
}
+ /**
+ * A snippet is trivial when it has no placeholder or only a final placeholder at
+ * its very end
+ */
get isTrivialSnippet(): boolean {
- return this._snippet.placeholders.length === 0
- || (this._snippet.placeholders.length === 1 && this._snippet.placeholders[0].isFinalTabstop);
+ if (this._snippet.placeholders.length === 0) {
+ return true;
+ }
+ if (this._snippet.placeholders.length === 1) {
+ const [placeholder] = this._snippet.placeholders;
+ if (placeholder.isFinalTabstop) {
+ if (this._snippet.rightMostDescendant === placeholder) {
+ return true;
+ }
+ }
+ }
+ return false;
}
computePossibleSelections() {
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 fce4d2c432bd1..4279ca422a481 100644
--- a/src/vs/editor/contrib/snippet/test/browser/snippetController2.test.ts
+++ b/src/vs/editor/contrib/snippet/test/browser/snippetController2.test.ts
@@ -692,4 +692,18 @@ suite('SnippetController2', function () {
assert.deepStrictEqual(editor.getSelections(), [new Selection(1, 5, 1, 5), new Selection(1, 10, 1, 10), new Selection(2, 5, 2, 5), new Selection(2, 10, 2, 10)]);
});
});
+
+ test('Bug: cursor position $0 with user snippets #163808', function () {
+
+ const ctrl = instaService.createInstance(SnippetController2, editor);
+ model.setValue('');
+
+ ctrl.insert('\n \n$0"\n');
+ assert.deepStrictEqual(editor.getSelections(), [new Selection(1, 23, 1, 23)]);
+
+ ctrl.insert('Qualifier="$0"');
+ assert.strictEqual(model.getValue(), '\n \n"\n');
+ assert.deepStrictEqual(editor.getSelections(), [new Selection(1, 34, 1, 34)]);
+
+ });
});