diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 1d7bec23dfa..5f60c994fad 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -2039,7 +2039,35 @@ declare module 'vscode' { */ value: string; - constructor(value: string); + constructor(value?: string); + + /** + * Builder-function that appends the given string to + * the [`value`](#SnippetString.value) of this snippet string. + * + * @param string A value to append 'as given'. The string will be escaped. + */ + appendText(string: string): SnippetString; + + /** + * Builder-function that appends a tabstop (`$1`, `$2` etc) to + * the [`value`](#SnippetString.value) of this snippet string. + * + * @param number The number of this tabstop, defaults to an auto-incremet + * value starting at 1. + */ + appendTabstop(number?: number): SnippetString; + + /** + * Builder-function that appends a placeholder (`${1:value}`) to + * the [`value`](#SnippetString.value) of this snippet string. + * + * @param value The value of this placeholder - either a string or a function + * with which a nested snippet can be created. + * @param number The number of this tabstop, defaults to an auto-incremet + * value starting at 1. + */ + appendPlaceholder(value: string | ((snippet: SnippetString) => any), number?: number): SnippetString; } /** diff --git a/src/vs/workbench/api/node/extHostTypes.ts b/src/vs/workbench/api/node/extHostTypes.ts index c48ab48683b..8a61703dac0 100644 --- a/src/vs/workbench/api/node/extHostTypes.ts +++ b/src/vs/workbench/api/node/extHostTypes.ts @@ -524,10 +524,44 @@ export class WorkspaceEdit { export class SnippetString { + private _tabstop: number = 1; + value: string; - constructor(value: string) { - this.value = value; + constructor(value?: string) { + this.value = value || ''; + } + + appendText(string: string): SnippetString { + this.value += string.replace(/\$/g, '\\$'); + return this; + } + + appendTabstop(number: number = this._tabstop++): SnippetString { + this.value += '$'; + this.value += number; + return this; + } + + appendPlaceholder(value: string | ((snippet: SnippetString) => any), number: number = this._tabstop++): SnippetString { + + if (typeof value === 'function') { + const nested = new SnippetString(); + nested._tabstop = this._tabstop; + value(nested); + this._tabstop = nested._tabstop; + value = nested.value; + } else { + value = value.replace(/\$|}/g, '\\$&'); + } + + this.value += '${'; + this.value += number; + this.value += ':'; + this.value += value; + this.value += '}'; + + return this; } } diff --git a/src/vs/workbench/test/node/api/extHostTypes.test.ts b/src/vs/workbench/test/node/api/extHostTypes.test.ts index 3603459f831..3119db332cc 100644 --- a/src/vs/workbench/test/node/api/extHostTypes.test.ts +++ b/src/vs/workbench/test/node/api/extHostTypes.test.ts @@ -416,4 +416,41 @@ suite('ExtHostTypes', function () { assert.ok(info.location instanceof types.Location); assert.equal(info.location.uri, undefined); }); -}); \ No newline at end of file + + test('SnippetString, builder-methods', function () { + + let string: types.SnippetString; + + string = new types.SnippetString(); + assert.equal(string.appendText('I need $ and $').value, 'I need \\$ and \\$'); + + string = new types.SnippetString(); + string.appendPlaceholder('fo$o}'); + assert.equal(string.value, '${1:fo\\$o\\}}'); + + string = new types.SnippetString(); + string.appendText('foo').appendTabstop(0).appendText('bar'); + assert.equal(string.value, 'foo$0bar'); + + string = new types.SnippetString(); + string.appendText('foo').appendTabstop().appendText('bar'); + assert.equal(string.value, 'foo$1bar'); + + string = new types.SnippetString(); + string.appendText('foo').appendTabstop(42).appendText('bar'); + assert.equal(string.value, 'foo$42bar'); + + string = new types.SnippetString(); + string.appendText('foo').appendPlaceholder('farboo').appendText('bar'); + assert.equal(string.value, 'foo${1:farboo}bar'); + + string = new types.SnippetString(); + string.appendText('foo').appendPlaceholder('far$boo').appendText('bar'); + assert.equal(string.value, 'foo${1:far\\$boo}bar'); + + string = new types.SnippetString(); + string.appendText('foo').appendPlaceholder(b => b.appendText('abc').appendPlaceholder('nested')).appendText('bar'); + assert.equal(string.value, 'foo${1:abc${2:nested}}bar'); + + }); +});