diff --git a/src/vs/editor/contrib/snippet/snippet.md b/src/vs/editor/contrib/snippet/snippet.md index 6b29d44c16e0..ab479c9c08e3 100644 --- a/src/vs/editor/contrib/snippet/snippet.md +++ b/src/vs/editor/contrib/snippet/snippet.md @@ -85,7 +85,6 @@ tabstop ::= '$' int | '${' int '}' | '${' int transform '}' placeholder ::= '${' int ':' any '}' - | '${' int ':' any transform '}' choice ::= '${' int '|' text (',' text)* '|}' | '${' int '|' text (',' text)* '|' transform '}' variable ::= '$' var | '${' var }' @@ -104,4 +103,4 @@ int ::= [0-9]+ text ::= .* ``` -Transformations for placeholders and choices are an extension to the TextMate snippet grammar and only support by Visual Studio Code. \ No newline at end of file +Transformations for placeholders and choices are an extension to the TextMate snippet grammar and only support by Visual Studio Code. diff --git a/src/vs/editor/contrib/snippet/snippetParser.ts b/src/vs/editor/contrib/snippet/snippetParser.ts index feb84a18b1f2..a51273c773e0 100644 --- a/src/vs/editor/contrib/snippet/snippetParser.ts +++ b/src/vs/editor/contrib/snippet/snippetParser.ts @@ -718,17 +718,6 @@ export class SnippetParser { return true; } - //..///} -> transform - if (this._accept(TokenType.Forwardslash)) { - if (this._parseTransform(placeholder)) { - parent.appendChild(placeholder); - return true; - } - - this._backTo(token); - return false; - } - if (this._parse(placeholder)) { continue; } diff --git a/src/vs/editor/contrib/snippet/test/snippetParser.test.ts b/src/vs/editor/contrib/snippet/test/snippetParser.test.ts index 369d3c79d562..649ad400d790 100644 --- a/src/vs/editor/contrib/snippet/test/snippetParser.test.ts +++ b/src/vs/editor/contrib/snippet/test/snippetParser.test.ts @@ -254,14 +254,6 @@ suite('SnippetParser', () => { assertTextAndMarker('${1/regex/format/options', '${1/regex/format/options', Text); }); - test('Parser, placeholder with defaults and transformation', () => { - assertTextAndMarker('${1:value/foo/bar/}', 'value', Placeholder); - assertTextAndMarker('${1:bar${2:foo}bar/foo/bar/}', 'barfoobar', Placeholder); - - // incomplete - assertTextAndMarker('${1:bar${2:foobar}/foo/bar/', '${1:barfoobar/foo/bar/', Text, Placeholder, Text); - }); - test('Parser, placeholder with choice and transformation', () => { assertTextAndMarker('${1|one,two,three|/foo/bar/}', 'one', Placeholder); assertTextAndMarker('${1|one|/foo/bar/}', 'one', Placeholder); @@ -408,32 +400,37 @@ suite('SnippetParser', () => { }); test('Parser, transform example', () => { - let marker = new SnippetParser().parse('${1:name} : ${2:type}${3: :=/\\s:=(.*)/${1:+ :=}${1}/};\n$0'); - let childs = marker.children; + let { children } = new SnippetParser().parse('${1:name} : ${2:type}${3/\\s:=(.*)/${1:+ :=}${1}/};\n$0'); - assert.ok(childs[0] instanceof Placeholder); - assert.equal(childs[0].children.length, 1); - assert.equal(childs[0].children[0].toString(), 'name'); - assert.equal((childs[0]).transform, undefined); - assert.ok(childs[1] instanceof Text); - assert.equal(childs[1].toString(), ' : '); - assert.ok(childs[2] instanceof Placeholder); - assert.equal(childs[2].children.length, 1); - assert.equal(childs[2].children[0].toString(), 'type'); - assert.ok(childs[3] instanceof Placeholder); - assert.equal(childs[3].children.length, 1); - assert.equal(childs[3].children[0].toString(), ' :='); - assert.notEqual((childs[3]).transform, undefined); - let t = (childs[3]).transform; - assert.equal(t.regexp, '/\\s:=(.*)/'); - assert.equal(t.children.length, 2); - assert.ok(t.children[0] instanceof FormatString); - assert.equal((t.children[0]).index, 1); - assert.equal((t.children[0]).ifValue, ' :='); - assert.ok(t.children[1] instanceof FormatString); - assert.equal((t.children[1]).index, 1); - assert.ok(childs[4] instanceof Text); - assert.equal(childs[4].toString(), ';\n'); + //${1:name} + assert.ok(children[0] instanceof Placeholder); + assert.equal(children[0].children.length, 1); + assert.equal(children[0].children[0].toString(), 'name'); + assert.equal((children[0]).transform, undefined); + + // : + assert.ok(children[1] instanceof Text); + assert.equal(children[1].toString(), ' : '); + + //${2:type} + assert.ok(children[2] instanceof Placeholder); + assert.equal(children[2].children.length, 1); + assert.equal(children[2].children[0].toString(), 'type'); + + //${3/\\s:=(.*)/${1:+ :=}${1}/} + assert.ok(children[3] instanceof Placeholder); + assert.equal(children[3].children.length, 0); + assert.notEqual((children[3]).transform, undefined); + let transform = (children[3]).transform; + assert.equal(transform.regexp, '/\\s:=(.*)/'); + assert.equal(transform.children.length, 2); + assert.ok(transform.children[0] instanceof FormatString); + assert.equal((transform.children[0]).index, 1); + assert.equal((transform.children[0]).ifValue, ' :='); + assert.ok(transform.children[1] instanceof FormatString); + assert.equal((transform.children[1]).index, 1); + assert.ok(children[4] instanceof Text); + assert.equal(children[4].toString(), ';\n'); }); @@ -454,20 +451,6 @@ suite('SnippetParser', () => { test('Parser, default placeholder values and one transform', () => { - assertMarker('errorContext: `${1:err/err/ok/}`, error: $1', Text, Placeholder, Text, Placeholder); - - const [, p1, , p2] = new SnippetParser().parse('errorContext: `${1:err/err/ok/}`, error:$1').children; - - assert.equal((p1).index, '1'); - assert.equal((p1).children.length, '1'); - assert.equal(((p1).children[0]), 'err'); - assert.notEqual((p1).transform, undefined); - - assert.equal((p2).index, '1'); - assert.equal((p2).children.length, '1'); - assert.equal(((p2).children[0]), 'err'); - assert.equal((p2).transform, undefined); - assertMarker('errorContext: `${1:err}`, error: ${1/err/ok/}', Text, Placeholder, Text, Placeholder); const [, p3, , p4] = new SnippetParser().parse('errorContext: `${1:err}`, error:${1/err/ok/}').children; @@ -732,4 +715,8 @@ suite('SnippetParser', () => { let snippet = new SnippetParser().parse('${1/(void$)|(.+)/${1:?-\treturn nil;}/}'); assertMarker(snippet, Placeholder); }); + + test('snippets variable not resolved in JSON proposal #52931', function () { + assertTextAndMarker('FOO${1:/bin/bash}', 'FOO/bin/bash', Text, Placeholder); + }); }); diff --git a/src/vs/editor/contrib/snippet/test/snippetSession.test.ts b/src/vs/editor/contrib/snippet/test/snippetSession.test.ts index 95eaf41c1e8a..2787ad8e2a1f 100644 --- a/src/vs/editor/contrib/snippet/test/snippetSession.test.ts +++ b/src/vs/editor/contrib/snippet/test/snippetSession.test.ts @@ -472,7 +472,7 @@ suite('SnippetSession', function () { test('snippets, transform example', function () { editor.getModel().setValue(''); editor.setSelection(new Selection(1, 1, 1, 1)); - const session = new SnippetSession(editor, '${1:name} : ${2:type}${3: :=/\\s:=(.*)/${1:+ :=}${1}/};\n$0'); + const session = new SnippetSession(editor, '${1:name} : ${2:type}${3/\\s:=(.*)/${1:+ :=}${1}/};\n$0'); session.insert(); assertSelections(editor, new Selection(1, 1, 1, 5)); @@ -483,7 +483,7 @@ suite('SnippetSession', function () { editor.trigger('test', 'type', { text: 'std_logic' }); session.next(); - assertSelections(editor, new Selection(1, 16, 1, 19)); + assertSelections(editor, new Selection(1, 16, 1, 16)); session.next(); assert.equal(model.getValue(), 'clk : std_logic;\n'); @@ -534,7 +534,7 @@ suite('SnippetSession', function () { test('snippets, transform example hit if', function () { editor.getModel().setValue(''); editor.setSelection(new Selection(1, 1, 1, 1)); - const session = new SnippetSession(editor, '${1:name} : ${2:type}${3: :=/\\s:=(.*)/${1:+ :=}${1}/};\n$0'); + const session = new SnippetSession(editor, '${1:name} : ${2:type}${3/\\s:=(.*)/${1:+ :=}${1}/};\n$0'); session.insert(); assertSelections(editor, new Selection(1, 1, 1, 5)); @@ -545,7 +545,7 @@ suite('SnippetSession', function () { editor.trigger('test', 'type', { text: 'std_logic' }); session.next(); - assertSelections(editor, new Selection(1, 16, 1, 19)); + assertSelections(editor, new Selection(1, 16, 1, 16)); editor.trigger('test', 'type', { text: ' := \'1\'' }); session.next();