Path: blob/main/src/vs/editor/contrib/snippet/test/browser/snippetSession.test.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/4import assert from 'assert';5import { mock } from '../../../../../base/test/common/mock.js';6import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js';7import { IActiveCodeEditor } from '../../../../browser/editorBrowser.js';8import { IPosition, Position } from '../../../../common/core/position.js';9import { Range } from '../../../../common/core/range.js';10import { Selection } from '../../../../common/core/selection.js';11import { ILanguageConfigurationService } from '../../../../common/languages/languageConfigurationRegistry.js';12import { TextModel } from '../../../../common/model/textModel.js';13import { SnippetParser } from '../../browser/snippetParser.js';14import { SnippetSession } from '../../browser/snippetSession.js';15import { createTestCodeEditor } from '../../../../test/browser/testCodeEditor.js';16import { TestLanguageConfigurationService } from '../../../../test/common/modes/testLanguageConfigurationService.js';17import { createTextModel } from '../../../../test/common/testTextModel.js';18import { ServiceCollection } from '../../../../../platform/instantiation/common/serviceCollection.js';19import { ILabelService } from '../../../../../platform/label/common/label.js';20import { IWorkspaceContextService } from '../../../../../platform/workspace/common/workspace.js';2122suite('SnippetSession', function () {2324let languageConfigurationService: ILanguageConfigurationService;25let editor: IActiveCodeEditor;26let model: TextModel;2728function assertSelections(editor: IActiveCodeEditor, ...s: Selection[]) {29for (const selection of editor.getSelections()) {30const actual = s.shift()!;31assert.ok(selection.equalsSelection(actual), `actual=${selection.toString()} <> expected=${actual.toString()}`);32}33assert.strictEqual(s.length, 0);34}3536setup(function () {37model = createTextModel('function foo() {\n console.log(a);\n}');38languageConfigurationService = new TestLanguageConfigurationService();39const serviceCollection = new ServiceCollection(40[ILabelService, new class extends mock<ILabelService>() { }],41[ILanguageConfigurationService, languageConfigurationService],42[IWorkspaceContextService, new class extends mock<IWorkspaceContextService>() {43override getWorkspace() {44return {45id: 'workspace-id',46folders: [],47};48}49}],50);51editor = createTestCodeEditor(model, { serviceCollection }) as IActiveCodeEditor;52editor.setSelections([new Selection(1, 1, 1, 1), new Selection(2, 5, 2, 5)]);53assert.strictEqual(model.getEOL(), '\n');54});5556teardown(function () {57model.dispose();58editor.dispose();59});6061ensureNoDisposablesAreLeakedInTestSuite();6263test('normalize whitespace', function () {6465function assertNormalized(position: IPosition, input: string, expected: string): void {66const snippet = new SnippetParser().parse(input);67SnippetSession.adjustWhitespace(model, position, true, snippet);68assert.strictEqual(snippet.toTextmateString(), expected);69}7071assertNormalized(new Position(1, 1), 'foo', 'foo');72assertNormalized(new Position(1, 1), 'foo\rbar', 'foo\nbar');73assertNormalized(new Position(1, 1), 'foo\rbar', 'foo\nbar');74assertNormalized(new Position(2, 5), 'foo\r\tbar', 'foo\n bar');75assertNormalized(new Position(2, 3), 'foo\r\tbar', 'foo\n bar');76assertNormalized(new Position(2, 5), 'foo\r\tbar\nfoo', 'foo\n bar\n foo');7778//Indentation issue with choice elements that span multiple lines #4626679assertNormalized(new Position(2, 5), 'a\nb${1|foo,\nbar|}', 'a\n b${1|foo,\nbar|}');80});8182test('adjust selection (overwrite[Before|After])', function () {8384let range = SnippetSession.adjustSelection(model, new Selection(1, 2, 1, 2), 1, 0);85assert.ok(range.equalsRange(new Range(1, 1, 1, 2)));86range = SnippetSession.adjustSelection(model, new Selection(1, 2, 1, 2), 1111, 0);87assert.ok(range.equalsRange(new Range(1, 1, 1, 2)));88range = SnippetSession.adjustSelection(model, new Selection(1, 2, 1, 2), 0, 10);89assert.ok(range.equalsRange(new Range(1, 2, 1, 12)));90range = SnippetSession.adjustSelection(model, new Selection(1, 2, 1, 2), 0, 10111);91assert.ok(range.equalsRange(new Range(1, 2, 1, 17)));9293});9495test('text edits & selection', function () {96const session = new SnippetSession(editor, 'foo${1:bar}foo$0', undefined, languageConfigurationService);97session.insert();98assert.strictEqual(editor.getModel()!.getValue(), 'foobarfoofunction foo() {\n foobarfooconsole.log(a);\n}');99100assertSelections(editor, new Selection(1, 4, 1, 7), new Selection(2, 8, 2, 11));101session.next();102assertSelections(editor, new Selection(1, 10, 1, 10), new Selection(2, 14, 2, 14));103});104105test('text edit with reversed selection', function () {106107const session = new SnippetSession(editor, '${1:bar}$0', undefined, languageConfigurationService);108editor.setSelections([new Selection(2, 5, 2, 5), new Selection(1, 1, 1, 1)]);109110session.insert();111assert.strictEqual(model.getValue(), 'barfunction foo() {\n barconsole.log(a);\n}');112assertSelections(editor, new Selection(2, 5, 2, 8), new Selection(1, 1, 1, 4));113});114115test('snippets, repeated tabstops', function () {116const session = new SnippetSession(editor, '${1:abc}foo${1:abc}$0', undefined, languageConfigurationService);117session.insert();118assertSelections(editor,119new Selection(1, 1, 1, 4), new Selection(1, 7, 1, 10),120new Selection(2, 5, 2, 8), new Selection(2, 11, 2, 14),121);122session.next();123assertSelections(editor,124new Selection(1, 10, 1, 10),125new Selection(2, 14, 2, 14),126);127});128129test('snippets, just text', function () {130const session = new SnippetSession(editor, 'foobar', undefined, languageConfigurationService);131session.insert();132assert.strictEqual(model.getValue(), 'foobarfunction foo() {\n foobarconsole.log(a);\n}');133assertSelections(editor, new Selection(1, 7, 1, 7), new Selection(2, 11, 2, 11));134});135136test('snippets, selections and new text with newlines', () => {137138const session = new SnippetSession(editor, 'foo\n\t${1:bar}\n$0', undefined, languageConfigurationService);139session.insert();140141assert.strictEqual(editor.getModel()!.getValue(), 'foo\n bar\nfunction foo() {\n foo\n bar\n console.log(a);\n}');142143assertSelections(editor, new Selection(2, 5, 2, 8), new Selection(5, 9, 5, 12));144145session.next();146assertSelections(editor, new Selection(3, 1, 3, 1), new Selection(6, 5, 6, 5));147});148149test('snippets, newline NO whitespace adjust', () => {150151editor.setSelection(new Selection(2, 5, 2, 5));152const session = new SnippetSession(editor, 'abc\n foo\n bar\n$0', { overwriteBefore: 0, overwriteAfter: 0, adjustWhitespace: false, clipboardText: undefined, overtypingCapturer: undefined }, languageConfigurationService);153session.insert();154assert.strictEqual(editor.getModel()!.getValue(), 'function foo() {\n abc\n foo\n bar\nconsole.log(a);\n}');155});156157test('snippets, selections -> next/prev', () => {158159const session = new SnippetSession(editor, 'f$1oo${2:bar}foo$0', undefined, languageConfigurationService);160session.insert();161162// @ $2163assertSelections(editor, new Selection(1, 2, 1, 2), new Selection(2, 6, 2, 6));164// @ $1165session.next();166assertSelections(editor, new Selection(1, 4, 1, 7), new Selection(2, 8, 2, 11));167// @ $2168session.prev();169assertSelections(editor, new Selection(1, 2, 1, 2), new Selection(2, 6, 2, 6));170// @ $1171session.next();172assertSelections(editor, new Selection(1, 4, 1, 7), new Selection(2, 8, 2, 11));173// @ $0174session.next();175assertSelections(editor, new Selection(1, 10, 1, 10), new Selection(2, 14, 2, 14));176});177178test('snippets, selections & typing', function () {179const session = new SnippetSession(editor, 'f${1:oo}_$2_$0', undefined, languageConfigurationService);180session.insert();181182editor.trigger('test', 'type', { text: 'X' });183session.next();184editor.trigger('test', 'type', { text: 'bar' });185186// go back to ${2:oo} which is now just 'X'187session.prev();188assertSelections(editor, new Selection(1, 2, 1, 3), new Selection(2, 6, 2, 7));189190// go forward to $1 which is now 'bar'191session.next();192assertSelections(editor, new Selection(1, 4, 1, 7), new Selection(2, 8, 2, 11));193194// go to final tabstop195session.next();196assert.strictEqual(model.getValue(), 'fX_bar_function foo() {\n fX_bar_console.log(a);\n}');197assertSelections(editor, new Selection(1, 8, 1, 8), new Selection(2, 12, 2, 12));198});199200test('snippets, insert shorter snippet into non-empty selection', function () {201model.setValue('foo_bar_foo');202editor.setSelections([new Selection(1, 1, 1, 4), new Selection(1, 9, 1, 12)]);203204new SnippetSession(editor, 'x$0', undefined, languageConfigurationService).insert();205assert.strictEqual(model.getValue(), 'x_bar_x');206assertSelections(editor, new Selection(1, 2, 1, 2), new Selection(1, 8, 1, 8));207});208209test('snippets, insert longer snippet into non-empty selection', function () {210model.setValue('foo_bar_foo');211editor.setSelections([new Selection(1, 1, 1, 4), new Selection(1, 9, 1, 12)]);212213new SnippetSession(editor, 'LONGER$0', undefined, languageConfigurationService).insert();214assert.strictEqual(model.getValue(), 'LONGER_bar_LONGER');215assertSelections(editor, new Selection(1, 7, 1, 7), new Selection(1, 18, 1, 18));216});217218test('snippets, don\'t grow final tabstop', function () {219model.setValue('foo_zzz_foo');220editor.setSelection(new Selection(1, 5, 1, 8));221const session = new SnippetSession(editor, '$1bar$0', undefined, languageConfigurationService);222session.insert();223224assertSelections(editor, new Selection(1, 5, 1, 5));225editor.trigger('test', 'type', { text: 'foo-' });226227session.next();228assert.strictEqual(model.getValue(), 'foo_foo-bar_foo');229assertSelections(editor, new Selection(1, 12, 1, 12));230231editor.trigger('test', 'type', { text: 'XXX' });232assert.strictEqual(model.getValue(), 'foo_foo-barXXX_foo');233session.prev();234assertSelections(editor, new Selection(1, 5, 1, 9));235session.next();236assertSelections(editor, new Selection(1, 15, 1, 15));237});238239test('snippets, don\'t merge touching tabstops 1/2', function () {240241const session = new SnippetSession(editor, '$1$2$3$0', undefined, languageConfigurationService);242session.insert();243assertSelections(editor, new Selection(1, 1, 1, 1), new Selection(2, 5, 2, 5));244245session.next();246assertSelections(editor, new Selection(1, 1, 1, 1), new Selection(2, 5, 2, 5));247248session.next();249assertSelections(editor, new Selection(1, 1, 1, 1), new Selection(2, 5, 2, 5));250251session.next();252assertSelections(editor, new Selection(1, 1, 1, 1), new Selection(2, 5, 2, 5));253254session.prev();255session.prev();256session.prev();257assertSelections(editor, new Selection(1, 1, 1, 1), new Selection(2, 5, 2, 5));258editor.trigger('test', 'type', { text: '111' });259260session.next();261editor.trigger('test', 'type', { text: '222' });262263session.next();264editor.trigger('test', 'type', { text: '333' });265266session.next();267assert.strictEqual(model.getValue(), '111222333function foo() {\n 111222333console.log(a);\n}');268assertSelections(editor, new Selection(1, 10, 1, 10), new Selection(2, 14, 2, 14));269270session.prev();271assertSelections(editor, new Selection(1, 7, 1, 10), new Selection(2, 11, 2, 14));272session.prev();273assertSelections(editor, new Selection(1, 4, 1, 7), new Selection(2, 8, 2, 11));274session.prev();275assertSelections(editor, new Selection(1, 1, 1, 4), new Selection(2, 5, 2, 8));276});277test('snippets, don\'t merge touching tabstops 2/2', function () {278279const session = new SnippetSession(editor, '$1$2$3$0', undefined, languageConfigurationService);280session.insert();281assertSelections(editor, new Selection(1, 1, 1, 1), new Selection(2, 5, 2, 5));282283editor.trigger('test', 'type', { text: '111' });284285session.next();286assertSelections(editor, new Selection(1, 4, 1, 4), new Selection(2, 8, 2, 8));287editor.trigger('test', 'type', { text: '222' });288289session.next();290assertSelections(editor, new Selection(1, 7, 1, 7), new Selection(2, 11, 2, 11));291editor.trigger('test', 'type', { text: '333' });292293session.next();294assert.strictEqual(session.isAtLastPlaceholder, true);295});296297test('snippets, gracefully move over final tabstop', function () {298const session = new SnippetSession(editor, '${1}bar$0', undefined, languageConfigurationService);299session.insert();300301assert.strictEqual(session.isAtLastPlaceholder, false);302assertSelections(editor, new Selection(1, 1, 1, 1), new Selection(2, 5, 2, 5));303304session.next();305assert.strictEqual(session.isAtLastPlaceholder, true);306assertSelections(editor, new Selection(1, 4, 1, 4), new Selection(2, 8, 2, 8));307308session.next();309assert.strictEqual(session.isAtLastPlaceholder, true);310assertSelections(editor, new Selection(1, 4, 1, 4), new Selection(2, 8, 2, 8));311});312313test('snippets, overwriting nested placeholder', function () {314const session = new SnippetSession(editor, 'log(${1:"$2"});$0', undefined, languageConfigurationService);315session.insert();316assertSelections(editor, new Selection(1, 5, 1, 7), new Selection(2, 9, 2, 11));317318editor.trigger('test', 'type', { text: 'XXX' });319assert.strictEqual(model.getValue(), 'log(XXX);function foo() {\n log(XXX);console.log(a);\n}');320321session.next();322assert.strictEqual(session.isAtLastPlaceholder, false);323// assertSelections(editor, new Selection(1, 7, 1, 7), new Selection(2, 11, 2, 11));324325session.next();326assert.strictEqual(session.isAtLastPlaceholder, true);327assertSelections(editor, new Selection(1, 10, 1, 10), new Selection(2, 14, 2, 14));328});329330test('snippets, selections and snippet ranges', function () {331const session = new SnippetSession(editor, '${1:foo}farboo${2:bar}$0', undefined, languageConfigurationService);332session.insert();333assert.strictEqual(model.getValue(), 'foofarboobarfunction foo() {\n foofarboobarconsole.log(a);\n}');334assertSelections(editor, new Selection(1, 1, 1, 4), new Selection(2, 5, 2, 8));335336assert.strictEqual(session.isSelectionWithinPlaceholders(), true);337338editor.setSelections([new Selection(1, 1, 1, 1)]);339assert.strictEqual(session.isSelectionWithinPlaceholders(), false);340341editor.setSelections([new Selection(1, 6, 1, 6), new Selection(2, 10, 2, 10)]);342assert.strictEqual(session.isSelectionWithinPlaceholders(), false); // in snippet, outside placeholder343344editor.setSelections([new Selection(1, 6, 1, 6), new Selection(2, 10, 2, 10), new Selection(1, 1, 1, 1)]);345assert.strictEqual(session.isSelectionWithinPlaceholders(), false); // in snippet, outside placeholder346347editor.setSelections([new Selection(1, 6, 1, 6), new Selection(2, 10, 2, 10), new Selection(2, 20, 2, 21)]);348assert.strictEqual(session.isSelectionWithinPlaceholders(), false);349350// reset selection to placeholder351session.next();352assert.strictEqual(session.isSelectionWithinPlaceholders(), true);353assertSelections(editor, new Selection(1, 10, 1, 13), new Selection(2, 14, 2, 17));354355// reset selection to placeholder356session.next();357assert.strictEqual(session.isSelectionWithinPlaceholders(), true);358assert.strictEqual(session.isAtLastPlaceholder, true);359assertSelections(editor, new Selection(1, 13, 1, 13), new Selection(2, 17, 2, 17));360});361362test('snippets, nested sessions', function () {363364model.setValue('');365editor.setSelection(new Selection(1, 1, 1, 1));366367const first = new SnippetSession(editor, 'foo${2:bar}foo$0', undefined, languageConfigurationService);368first.insert();369assert.strictEqual(model.getValue(), 'foobarfoo');370assertSelections(editor, new Selection(1, 4, 1, 7));371372const second = new SnippetSession(editor, 'ba${1:zzzz}$0', undefined, languageConfigurationService);373second.insert();374assert.strictEqual(model.getValue(), 'foobazzzzfoo');375assertSelections(editor, new Selection(1, 6, 1, 10));376377second.next();378assert.strictEqual(second.isAtLastPlaceholder, true);379assertSelections(editor, new Selection(1, 10, 1, 10));380381first.next();382assert.strictEqual(first.isAtLastPlaceholder, true);383assertSelections(editor, new Selection(1, 13, 1, 13));384});385386test('snippets, typing at final tabstop', function () {387388const session = new SnippetSession(editor, 'farboo$0', undefined, languageConfigurationService);389session.insert();390assert.strictEqual(session.isAtLastPlaceholder, true);391assert.strictEqual(session.isSelectionWithinPlaceholders(), false);392393editor.trigger('test', 'type', { text: 'XXX' });394assert.strictEqual(session.isSelectionWithinPlaceholders(), false);395});396397test('snippets, typing at beginning', function () {398399editor.setSelection(new Selection(1, 2, 1, 2));400const session = new SnippetSession(editor, 'farboo$0', undefined, languageConfigurationService);401session.insert();402403editor.setSelection(new Selection(1, 2, 1, 2));404assert.strictEqual(session.isSelectionWithinPlaceholders(), false);405assert.strictEqual(session.isAtLastPlaceholder, true);406407editor.trigger('test', 'type', { text: 'XXX' });408assert.strictEqual(model.getLineContent(1), 'fXXXfarboounction foo() {');409assert.strictEqual(session.isSelectionWithinPlaceholders(), false);410411session.next();412assertSelections(editor, new Selection(1, 11, 1, 11));413});414415test('snippets, typing with nested placeholder', function () {416417editor.setSelection(new Selection(1, 1, 1, 1));418const session = new SnippetSession(editor, 'This ${1:is ${2:nested}}.$0', undefined, languageConfigurationService);419session.insert();420assertSelections(editor, new Selection(1, 6, 1, 15));421422session.next();423assertSelections(editor, new Selection(1, 9, 1, 15));424425editor.trigger('test', 'cut', {});426assertSelections(editor, new Selection(1, 9, 1, 9));427428editor.trigger('test', 'type', { text: 'XXX' });429session.prev();430assertSelections(editor, new Selection(1, 6, 1, 12));431});432433test('snippets, snippet with variables', function () {434const session = new SnippetSession(editor, '@line=$TM_LINE_NUMBER$0', undefined, languageConfigurationService);435session.insert();436437assert.strictEqual(model.getValue(), '@line=1function foo() {\n @line=2console.log(a);\n}');438assertSelections(editor, new Selection(1, 8, 1, 8), new Selection(2, 12, 2, 12));439});440441test('snippets, merge', function () {442editor.setSelection(new Selection(1, 1, 1, 1));443const session = new SnippetSession(editor, 'This ${1:is ${2:nested}}.$0', undefined, languageConfigurationService);444session.insert();445session.next();446assertSelections(editor, new Selection(1, 9, 1, 15));447448session.merge('really ${1:nested}$0');449assertSelections(editor, new Selection(1, 16, 1, 22));450451session.next();452assertSelections(editor, new Selection(1, 22, 1, 22));453assert.strictEqual(session.isAtLastPlaceholder, false);454455session.next();456assert.strictEqual(session.isAtLastPlaceholder, true);457assertSelections(editor, new Selection(1, 23, 1, 23));458459session.prev();460editor.trigger('test', 'type', { text: 'AAA' });461462// back to `really ${1:nested}`463session.prev();464assertSelections(editor, new Selection(1, 16, 1, 22));465466// back to `${1:is ...}` which now grew467session.prev();468assertSelections(editor, new Selection(1, 6, 1, 25));469});470471test('snippets, transform', function () {472editor.getModel()!.setValue('');473editor.setSelection(new Selection(1, 1, 1, 1));474const session = new SnippetSession(editor, '${1/foo/bar/}$0', undefined, languageConfigurationService);475session.insert();476assertSelections(editor, new Selection(1, 1, 1, 1));477478editor.trigger('test', 'type', { text: 'foo' });479session.next();480481assert.strictEqual(model.getValue(), 'bar');482assert.strictEqual(session.isAtLastPlaceholder, true);483assertSelections(editor, new Selection(1, 4, 1, 4));484});485486test('snippets, multi placeholder same index one transform', function () {487editor.getModel()!.setValue('');488editor.setSelection(new Selection(1, 1, 1, 1));489const session = new SnippetSession(editor, '$1 baz ${1/foo/bar/}$0', undefined, languageConfigurationService);490session.insert();491assertSelections(editor, new Selection(1, 1, 1, 1), new Selection(1, 6, 1, 6));492493editor.trigger('test', 'type', { text: 'foo' });494session.next();495496assert.strictEqual(model.getValue(), 'foo baz bar');497assert.strictEqual(session.isAtLastPlaceholder, true);498assertSelections(editor, new Selection(1, 12, 1, 12));499});500501test('snippets, transform example', function () {502editor.getModel()!.setValue('');503editor.setSelection(new Selection(1, 1, 1, 1));504const session = new SnippetSession(editor, '${1:name} : ${2:type}${3/\\s:=(.*)/${1:+ :=}${1}/};\n$0', undefined, languageConfigurationService);505session.insert();506507assertSelections(editor, new Selection(1, 1, 1, 5));508editor.trigger('test', 'type', { text: 'clk' });509session.next();510511assertSelections(editor, new Selection(1, 7, 1, 11));512editor.trigger('test', 'type', { text: 'std_logic' });513session.next();514515assertSelections(editor, new Selection(1, 16, 1, 16));516session.next();517518assert.strictEqual(model.getValue(), 'clk : std_logic;\n');519assert.strictEqual(session.isAtLastPlaceholder, true);520assertSelections(editor, new Selection(2, 1, 2, 1));521});522523test('snippets, transform with indent', function () {524const snippet = [525'private readonly ${1} = new Emitter<$2>();',526'readonly ${1/^_(.*)/$1/}: Event<$2> = this.$1.event;',527'$0'528].join('\n');529const expected = [530'{',531'\tprivate readonly _prop = new Emitter<string>();',532'\treadonly prop: Event<string> = this._prop.event;',533'\t',534'}'535].join('\n');536const base = [537'{',538'\t',539'}'540].join('\n');541542editor.getModel()!.setValue(base);543editor.getModel()!.updateOptions({ insertSpaces: false });544editor.setSelection(new Selection(2, 2, 2, 2));545546const session = new SnippetSession(editor, snippet, undefined, languageConfigurationService);547session.insert();548549assertSelections(editor, new Selection(2, 19, 2, 19), new Selection(3, 11, 3, 11), new Selection(3, 28, 3, 28));550editor.trigger('test', 'type', { text: '_prop' });551session.next();552553assertSelections(editor, new Selection(2, 39, 2, 39), new Selection(3, 23, 3, 23));554editor.trigger('test', 'type', { text: 'string' });555session.next();556557assert.strictEqual(model.getValue(), expected);558assert.strictEqual(session.isAtLastPlaceholder, true);559assertSelections(editor, new Selection(4, 2, 4, 2));560561});562563test('snippets, transform example hit if', function () {564editor.getModel()!.setValue('');565editor.setSelection(new Selection(1, 1, 1, 1));566const session = new SnippetSession(editor, '${1:name} : ${2:type}${3/\\s:=(.*)/${1:+ :=}${1}/};\n$0', undefined, languageConfigurationService);567session.insert();568569assertSelections(editor, new Selection(1, 1, 1, 5));570editor.trigger('test', 'type', { text: 'clk' });571session.next();572573assertSelections(editor, new Selection(1, 7, 1, 11));574editor.trigger('test', 'type', { text: 'std_logic' });575session.next();576577assertSelections(editor, new Selection(1, 16, 1, 16));578editor.trigger('test', 'type', { text: ' := \'1\'' });579session.next();580581assert.strictEqual(model.getValue(), 'clk : std_logic := \'1\';\n');582assert.strictEqual(session.isAtLastPlaceholder, true);583assertSelections(editor, new Selection(2, 1, 2, 1));584});585586test('Snippet tab stop selection issue #96545, snippets, transform adjacent to previous placeholder', function () {587editor.getModel()!.setValue('');588editor.setSelection(new Selection(1, 1, 1, 1));589const session = new SnippetSession(editor, '${1:{}${2:fff}${1/{/}/}', undefined, languageConfigurationService);590session.insert();591592assertSelections(editor, new Selection(1, 1, 1, 2), new Selection(1, 5, 1, 6));593session.next();594595assert.strictEqual(model.getValue(), '{fff}');596assertSelections(editor, new Selection(1, 2, 1, 5));597editor.trigger('test', 'type', { text: 'ggg' });598session.next();599600assert.strictEqual(model.getValue(), '{ggg}');601assert.strictEqual(session.isAtLastPlaceholder, true);602assertSelections(editor, new Selection(1, 6, 1, 6));603});604605test('Snippet tab stop selection issue #96545', function () {606editor.getModel().setValue('');607const session = new SnippetSession(editor, '${1:{}${2:fff}${1/[\\{]/}/}$0', undefined, languageConfigurationService);608session.insert();609assert.strictEqual(editor.getModel().getValue(), '{fff{');610611assertSelections(editor, new Selection(1, 1, 1, 2), new Selection(1, 5, 1, 6));612session.next();613assertSelections(editor, new Selection(1, 2, 1, 5));614});615616test('Snippet placeholder index incorrect after using 2+ snippets in a row that each end with a placeholder, #30769', function () {617editor.getModel()!.setValue('');618editor.setSelection(new Selection(1, 1, 1, 1));619const session = new SnippetSession(editor, 'test ${1:replaceme}', undefined, languageConfigurationService);620session.insert();621622editor.trigger('test', 'type', { text: '1' });623editor.trigger('test', 'type', { text: '\n' });624assert.strictEqual(editor.getModel()!.getValue(), 'test 1\n');625626session.merge('test ${1:replaceme}');627editor.trigger('test', 'type', { text: '2' });628editor.trigger('test', 'type', { text: '\n' });629630assert.strictEqual(editor.getModel()!.getValue(), 'test 1\ntest 2\n');631632session.merge('test ${1:replaceme}');633editor.trigger('test', 'type', { text: '3' });634editor.trigger('test', 'type', { text: '\n' });635636assert.strictEqual(editor.getModel()!.getValue(), 'test 1\ntest 2\ntest 3\n');637638session.merge('test ${1:replaceme}');639editor.trigger('test', 'type', { text: '4' });640editor.trigger('test', 'type', { text: '\n' });641642assert.strictEqual(editor.getModel()!.getValue(), 'test 1\ntest 2\ntest 3\ntest 4\n');643});644645test('Snippet variable text isn\'t whitespace normalised, #31124', function () {646editor.getModel()!.setValue([647'start',648'\t\t-one',649'\t\t-two',650'end'651].join('\n'));652653editor.getModel()!.updateOptions({ insertSpaces: false });654editor.setSelection(new Selection(2, 2, 3, 7));655656new SnippetSession(editor, '<div>\n\t$TM_SELECTED_TEXT\n</div>$0', undefined, languageConfigurationService).insert();657658let expected = [659'start',660'\t<div>',661'\t\t\t-one',662'\t\t\t-two',663'\t</div>',664'end'665].join('\n');666667assert.strictEqual(editor.getModel()!.getValue(), expected);668669editor.getModel()!.setValue([670'start',671'\t\t-one',672'\t-two',673'end'674].join('\n'));675676editor.getModel()!.updateOptions({ insertSpaces: false });677editor.setSelection(new Selection(2, 2, 3, 7));678679new SnippetSession(editor, '<div>\n\t$TM_SELECTED_TEXT\n</div>$0', undefined, languageConfigurationService).insert();680681expected = [682'start',683'\t<div>',684'\t\t\t-one',685'\t\t-two',686'\t</div>',687'end'688].join('\n');689690assert.strictEqual(editor.getModel()!.getValue(), expected);691});692693test('Selecting text from left to right, and choosing item messes up code, #31199', function () {694const model = editor.getModel()!;695model.setValue('console.log');696697let actual = SnippetSession.adjustSelection(model, new Selection(1, 12, 1, 9), 3, 0);698assert.ok(actual.equalsSelection(new Selection(1, 9, 1, 6)));699700actual = SnippetSession.adjustSelection(model, new Selection(1, 9, 1, 12), 3, 0);701assert.ok(actual.equalsSelection(new Selection(1, 9, 1, 12)));702703editor.setSelections([new Selection(1, 9, 1, 12)]);704new SnippetSession(editor, 'far', { overwriteBefore: 3, overwriteAfter: 0, adjustWhitespace: true, clipboardText: undefined, overtypingCapturer: undefined }, languageConfigurationService).insert();705assert.strictEqual(model.getValue(), 'console.far');706});707708test('Tabs don\'t get replaced with spaces in snippet transformations #103818', function () {709const model = editor.getModel()!;710model.setValue('\n{\n \n}');711model.updateOptions({ insertSpaces: true, indentSize: 2 });712editor.setSelections([new Selection(1, 1, 1, 1), new Selection(3, 6, 3, 6)]);713const session = new SnippetSession(editor, [714'function animate () {',715'\tvar ${1:a} = 12;',716'\tconsole.log(${1/(.*)/\n\t\t$1\n\t/})',717'}'718].join('\n'), undefined, languageConfigurationService);719720session.insert();721722assert.strictEqual(model.getValue(), [723'function animate () {',724' var a = 12;',725' console.log(a)',726'}',727'{',728' function animate () {',729' var a = 12;',730' console.log(a)',731' }',732'}',733].join('\n'));734735editor.trigger('test', 'type', { text: 'bbb' });736session.next();737738assert.strictEqual(model.getValue(), [739'function animate () {',740' var bbb = 12;',741' console.log(',742' bbb',743' )',744'}',745'{',746' function animate () {',747' var bbb = 12;',748' console.log(',749' bbb',750' )',751' }',752'}',753].join('\n'));754});755756757suite('createEditsAndSnippetsFromEdits', function () {758759test('empty', function () {760761const result = SnippetSession.createEditsAndSnippetsFromEdits(editor, [], true, true, undefined, undefined, languageConfigurationService);762763assert.deepStrictEqual(result.edits, []);764assert.deepStrictEqual(result.snippets, []);765});766767test('basic', function () {768769editor.getModel().setValue('foo("bar")');770771const result = SnippetSession.createEditsAndSnippetsFromEdits(772editor,773[{ range: new Range(1, 5, 1, 9), template: '$1' }, { range: new Range(1, 1, 1, 1), template: 'const ${1:new_const} = "bar"' }],774true, true, undefined, undefined, languageConfigurationService775);776777assert.strictEqual(result.edits.length, 2);778assert.deepStrictEqual(result.edits[0].range, new Range(1, 1, 1, 1));779assert.deepStrictEqual(result.edits[0].text, 'const new_const = "bar"');780assert.deepStrictEqual(result.edits[1].range, new Range(1, 5, 1, 9));781assert.deepStrictEqual(result.edits[1].text, 'new_const');782783assert.strictEqual(result.snippets.length, 1);784assert.strictEqual(result.snippets[0].isTrivialSnippet, false);785});786787test('with $SELECTION variable', function () {788editor.getModel().setValue('Some text and a selection');789editor.setSelections([new Selection(1, 17, 1, 26)]);790791const result = SnippetSession.createEditsAndSnippetsFromEdits(792editor,793[{ range: new Range(1, 17, 1, 26), template: 'wrapped <$SELECTION>' }],794true, true, undefined, undefined, languageConfigurationService795);796797assert.strictEqual(result.edits.length, 1);798assert.deepStrictEqual(result.edits[0].range, new Range(1, 17, 1, 26));799assert.deepStrictEqual(result.edits[0].text, 'wrapped <selection>');800801assert.strictEqual(result.snippets.length, 1);802assert.strictEqual(result.snippets[0].isTrivialSnippet, true);803});804});805});806807808