Path: blob/main/src/vs/editor/contrib/find/test/browser/findModel.test.ts
4780 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*--------------------------------------------------------------------------------------------*/45import assert from 'assert';6import { DisposableStore } from '../../../../../base/common/lifecycle.js';7import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js';8import { CoreNavigationCommands } from '../../../../browser/coreCommands.js';9import { IActiveCodeEditor, ICodeEditor } from '../../../../browser/editorBrowser.js';10import { Position } from '../../../../common/core/position.js';11import { Range } from '../../../../common/core/range.js';12import { Selection } from '../../../../common/core/selection.js';13import { PieceTreeTextBufferBuilder } from '../../../../common/model/pieceTreeTextBuffer/pieceTreeTextBufferBuilder.js';14import { FindModelBoundToEditorModel } from '../../browser/findModel.js';15import { FindReplaceState } from '../../browser/findState.js';16import { withTestCodeEditor } from '../../../../test/browser/testCodeEditor.js';1718suite('FindModel', () => {1920let disposables: DisposableStore;2122setup(() => {23disposables = new DisposableStore();24});2526teardown(() => {27disposables.dispose();28});2930ensureNoDisposablesAreLeakedInTestSuite();3132function findTest(testName: string, callback: (editor: IActiveCodeEditor) => void): void {33test(testName, () => {34const textArr = [35'// my cool header',36'#include "cool.h"',37'#include <iostream>',38'',39'int main() {',40' cout << "hello world, Hello!" << endl;',41' cout << "hello world again" << endl;',42' cout << "Hello world again" << endl;',43' cout << "helloworld again" << endl;',44'}',45'// blablablaciao',46''47];48withTestCodeEditor(textArr, {}, (editor) => callback(editor as IActiveCodeEditor));4950const text = textArr.join('\n');51const ptBuilder = new PieceTreeTextBufferBuilder();52ptBuilder.acceptChunk(text.substr(0, 94));53ptBuilder.acceptChunk(text.substr(94, 101));54ptBuilder.acceptChunk(text.substr(195, 59));55const factory = ptBuilder.finish();56withTestCodeEditor(57factory,58{},59(editor) => callback(editor as IActiveCodeEditor)60);61});62}6364function fromRange(rng: Range): number[] {65return [rng.startLineNumber, rng.startColumn, rng.endLineNumber, rng.endColumn];66}6768function _getFindState(editor: ICodeEditor) {69const model = editor.getModel()!;70const currentFindMatches: Range[] = [];71const allFindMatches: Range[] = [];7273for (const dec of model.getAllDecorations()) {74if (dec.options.className === 'currentFindMatch') {75currentFindMatches.push(dec.range);76allFindMatches.push(dec.range);77} else if (dec.options.className === 'findMatch') {78allFindMatches.push(dec.range);79}80}8182currentFindMatches.sort(Range.compareRangesUsingStarts);83allFindMatches.sort(Range.compareRangesUsingStarts);8485return {86highlighted: currentFindMatches.map(fromRange),87findDecorations: allFindMatches.map(fromRange)88};89}9091function assertFindState(editor: ICodeEditor, cursor: number[], highlighted: number[] | null, findDecorations: number[][]): void {92assert.deepStrictEqual(fromRange(editor.getSelection()!), cursor, 'cursor');9394const expectedState = {95highlighted: highlighted ? [highlighted] : [],96findDecorations: findDecorations97};98assert.deepStrictEqual(_getFindState(editor), expectedState, 'state');99}100101findTest('incremental find from beginning of file', (editor) => {102editor.setPosition({ lineNumber: 1, column: 1 });103const findState = disposables.add(new FindReplaceState());104const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));105106// simulate typing the search string107findState.change({ searchString: 'H' }, true);108assertFindState(109editor,110[1, 12, 1, 13],111[1, 12, 1, 13],112[113[1, 12, 1, 13],114[2, 16, 2, 17],115[6, 14, 6, 15],116[6, 27, 6, 28],117[7, 14, 7, 15],118[8, 14, 8, 15],119[9, 14, 9, 15]120]121);122123// simulate typing the search string124findState.change({ searchString: 'He' }, true);125assertFindState(126editor,127[1, 12, 1, 14],128[1, 12, 1, 14],129[130[1, 12, 1, 14],131[6, 14, 6, 16],132[6, 27, 6, 29],133[7, 14, 7, 16],134[8, 14, 8, 16],135[9, 14, 9, 16]136]137);138139// simulate typing the search string140findState.change({ searchString: 'Hello' }, true);141assertFindState(142editor,143[6, 14, 6, 19],144[6, 14, 6, 19],145[146[6, 14, 6, 19],147[6, 27, 6, 32],148[7, 14, 7, 19],149[8, 14, 8, 19],150[9, 14, 9, 19]151]152);153154// simulate toggling on `matchCase`155findState.change({ matchCase: true }, true);156assertFindState(157editor,158[6, 27, 6, 32],159[6, 27, 6, 32],160[161[6, 27, 6, 32],162[8, 14, 8, 19]163]164);165166// simulate typing the search string167findState.change({ searchString: 'hello' }, true);168assertFindState(169editor,170[6, 14, 6, 19],171[6, 14, 6, 19],172[173[6, 14, 6, 19],174[7, 14, 7, 19],175[9, 14, 9, 19]176]177);178179// simulate toggling on `wholeWord`180findState.change({ wholeWord: true }, true);181assertFindState(182editor,183[6, 14, 6, 19],184[6, 14, 6, 19],185[186[6, 14, 6, 19],187[7, 14, 7, 19]188]189);190191// simulate toggling off `matchCase`192findState.change({ matchCase: false }, true);193assertFindState(194editor,195[6, 14, 6, 19],196[6, 14, 6, 19],197[198[6, 14, 6, 19],199[6, 27, 6, 32],200[7, 14, 7, 19],201[8, 14, 8, 19]202]203);204205// simulate toggling off `wholeWord`206findState.change({ wholeWord: false }, true);207assertFindState(208editor,209[6, 14, 6, 19],210[6, 14, 6, 19],211[212[6, 14, 6, 19],213[6, 27, 6, 32],214[7, 14, 7, 19],215[8, 14, 8, 19],216[9, 14, 9, 19]217]218);219220// simulate adding a search scope221findState.change({ searchScope: [new Range(8, 1, 10, 1)] }, true);222assertFindState(223editor,224[8, 14, 8, 19],225[8, 14, 8, 19],226[227[8, 14, 8, 19],228[9, 14, 9, 19]229]230);231232// simulate removing the search scope233findState.change({ searchScope: null }, true);234assertFindState(235editor,236[6, 14, 6, 19],237[6, 14, 6, 19],238[239[6, 14, 6, 19],240[6, 27, 6, 32],241[7, 14, 7, 19],242[8, 14, 8, 19],243[9, 14, 9, 19]244]245);246247findModel.dispose();248findState.dispose();249});250251findTest('find model removes its decorations', (editor) => {252const findState = disposables.add(new FindReplaceState());253findState.change({ searchString: 'hello' }, false);254const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));255256assert.strictEqual(findState.matchesCount, 5);257assertFindState(258editor,259[1, 1, 1, 1],260null,261[262[6, 14, 6, 19],263[6, 27, 6, 32],264[7, 14, 7, 19],265[8, 14, 8, 19],266[9, 14, 9, 19]267]268);269270findModel.dispose();271findState.dispose();272273assertFindState(274editor,275[1, 1, 1, 1],276null,277[]278);279});280281findTest('find model updates state matchesCount', (editor) => {282const findState = disposables.add(new FindReplaceState());283findState.change({ searchString: 'hello' }, false);284const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));285286assert.strictEqual(findState.matchesCount, 5);287assertFindState(288editor,289[1, 1, 1, 1],290null,291[292[6, 14, 6, 19],293[6, 27, 6, 32],294[7, 14, 7, 19],295[8, 14, 8, 19],296[9, 14, 9, 19]297]298);299300findState.change({ searchString: 'helloo' }, false);301assert.strictEqual(findState.matchesCount, 0);302assertFindState(303editor,304[1, 1, 1, 1],305null,306[]307);308309findModel.dispose();310findState.dispose();311});312313findTest('find model reacts to position change', (editor) => {314const findState = disposables.add(new FindReplaceState());315findState.change({ searchString: 'hello' }, false);316const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));317318assertFindState(319editor,320[1, 1, 1, 1],321null,322[323[6, 14, 6, 19],324[6, 27, 6, 32],325[7, 14, 7, 19],326[8, 14, 8, 19],327[9, 14, 9, 19]328]329);330331editor.trigger('mouse', CoreNavigationCommands.MoveTo.id, {332position: new Position(6, 20)333});334335assertFindState(336editor,337[6, 20, 6, 20],338null,339[340[6, 14, 6, 19],341[6, 27, 6, 32],342[7, 14, 7, 19],343[8, 14, 8, 19],344[9, 14, 9, 19]345]346);347348findState.change({ searchString: 'Hello' }, true);349assertFindState(350editor,351[6, 27, 6, 32],352[6, 27, 6, 32],353[354[6, 14, 6, 19],355[6, 27, 6, 32],356[7, 14, 7, 19],357[8, 14, 8, 19],358[9, 14, 9, 19]359]360);361362findModel.dispose();363findState.dispose();364});365366findTest('find model next', (editor) => {367const findState = disposables.add(new FindReplaceState());368findState.change({ searchString: 'hello', wholeWord: true }, false);369const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));370371assertFindState(372editor,373[1, 1, 1, 1],374null,375[376[6, 14, 6, 19],377[6, 27, 6, 32],378[7, 14, 7, 19],379[8, 14, 8, 19]380]381);382383findModel.moveToNextMatch();384assertFindState(385editor,386[6, 14, 6, 19],387[6, 14, 6, 19],388[389[6, 14, 6, 19],390[6, 27, 6, 32],391[7, 14, 7, 19],392[8, 14, 8, 19]393]394);395396findModel.moveToNextMatch();397assertFindState(398editor,399[6, 27, 6, 32],400[6, 27, 6, 32],401[402[6, 14, 6, 19],403[6, 27, 6, 32],404[7, 14, 7, 19],405[8, 14, 8, 19]406]407);408409findModel.moveToNextMatch();410assertFindState(411editor,412[7, 14, 7, 19],413[7, 14, 7, 19],414[415[6, 14, 6, 19],416[6, 27, 6, 32],417[7, 14, 7, 19],418[8, 14, 8, 19]419]420);421422findModel.moveToNextMatch();423assertFindState(424editor,425[8, 14, 8, 19],426[8, 14, 8, 19],427[428[6, 14, 6, 19],429[6, 27, 6, 32],430[7, 14, 7, 19],431[8, 14, 8, 19]432]433);434435findModel.moveToNextMatch();436assertFindState(437editor,438[6, 14, 6, 19],439[6, 14, 6, 19],440[441[6, 14, 6, 19],442[6, 27, 6, 32],443[7, 14, 7, 19],444[8, 14, 8, 19]445]446);447448findModel.dispose();449findState.dispose();450});451452findTest('find model next stays in scope', (editor) => {453const findState = disposables.add(new FindReplaceState());454findState.change({ searchString: 'hello', wholeWord: true, searchScope: [new Range(7, 1, 9, 1)] }, false);455const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));456457assertFindState(458editor,459[1, 1, 1, 1],460null,461[462[7, 14, 7, 19],463[8, 14, 8, 19]464]465);466467findModel.moveToNextMatch();468assertFindState(469editor,470[7, 14, 7, 19],471[7, 14, 7, 19],472[473[7, 14, 7, 19],474[8, 14, 8, 19]475]476);477478findModel.moveToNextMatch();479assertFindState(480editor,481[8, 14, 8, 19],482[8, 14, 8, 19],483[484[7, 14, 7, 19],485[8, 14, 8, 19]486]487);488489findModel.moveToNextMatch();490assertFindState(491editor,492[7, 14, 7, 19],493[7, 14, 7, 19],494[495[7, 14, 7, 19],496[8, 14, 8, 19]497]498);499500findModel.dispose();501findState.dispose();502});503504findTest('multi-selection find model next stays in scope (overlap)', (editor) => {505const findState = disposables.add(new FindReplaceState());506findState.change({ searchString: 'hello', wholeWord: true, searchScope: [new Range(7, 1, 8, 2), new Range(8, 1, 9, 1)] }, false);507const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));508509assertFindState(510editor,511[1, 1, 1, 1],512null,513[514[7, 14, 7, 19],515[8, 14, 8, 19]516]517);518519findModel.moveToNextMatch();520assertFindState(521editor,522[7, 14, 7, 19],523[7, 14, 7, 19],524[525[7, 14, 7, 19],526[8, 14, 8, 19]527]528);529530findModel.moveToNextMatch();531assertFindState(532editor,533[8, 14, 8, 19],534[8, 14, 8, 19],535[536[7, 14, 7, 19],537[8, 14, 8, 19]538]539);540541findModel.moveToNextMatch();542assertFindState(543editor,544[7, 14, 7, 19],545[7, 14, 7, 19],546[547[7, 14, 7, 19],548[8, 14, 8, 19]549]550);551552findModel.dispose();553findState.dispose();554});555556findTest('multi-selection find model next stays in scope', (editor) => {557const findState = disposables.add(new FindReplaceState());558findState.change({ searchString: 'hello', matchCase: true, wholeWord: false, searchScope: [new Range(6, 1, 7, 38), new Range(9, 3, 9, 38)] }, false);559const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));560561assertFindState(562editor,563[1, 1, 1, 1],564null,565[566[6, 14, 6, 19],567// `matchCase: false` would568// find this match as well:569// [6, 27, 6, 32],570[7, 14, 7, 19],571// `wholeWord: true` would572// exclude this match:573[9, 14, 9, 19],574]575);576577findModel.moveToNextMatch();578assertFindState(579editor,580[6, 14, 6, 19],581[6, 14, 6, 19],582[583[6, 14, 6, 19],584[7, 14, 7, 19],585[9, 14, 9, 19],586]587);588589findModel.moveToNextMatch();590assertFindState(591editor,592[7, 14, 7, 19],593[7, 14, 7, 19],594[595[6, 14, 6, 19],596[7, 14, 7, 19],597[9, 14, 9, 19],598]599);600601findModel.moveToNextMatch();602assertFindState(603editor,604[9, 14, 9, 19],605[9, 14, 9, 19],606[607[6, 14, 6, 19],608[7, 14, 7, 19],609[9, 14, 9, 19],610]611);612613findModel.moveToNextMatch();614assertFindState(615editor,616[6, 14, 6, 19],617[6, 14, 6, 19],618[619[6, 14, 6, 19],620[7, 14, 7, 19],621[9, 14, 9, 19],622]623);624625findModel.dispose();626findState.dispose();627});628629findTest('find model prev', (editor) => {630const findState = disposables.add(new FindReplaceState());631findState.change({ searchString: 'hello', wholeWord: true }, false);632const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));633634assertFindState(635editor,636[1, 1, 1, 1],637null,638[639[6, 14, 6, 19],640[6, 27, 6, 32],641[7, 14, 7, 19],642[8, 14, 8, 19]643]644);645646findModel.moveToPrevMatch();647assertFindState(648editor,649[8, 14, 8, 19],650[8, 14, 8, 19],651[652[6, 14, 6, 19],653[6, 27, 6, 32],654[7, 14, 7, 19],655[8, 14, 8, 19]656]657);658659findModel.moveToPrevMatch();660assertFindState(661editor,662[7, 14, 7, 19],663[7, 14, 7, 19],664[665[6, 14, 6, 19],666[6, 27, 6, 32],667[7, 14, 7, 19],668[8, 14, 8, 19]669]670);671672findModel.moveToPrevMatch();673assertFindState(674editor,675[6, 27, 6, 32],676[6, 27, 6, 32],677[678[6, 14, 6, 19],679[6, 27, 6, 32],680[7, 14, 7, 19],681[8, 14, 8, 19]682]683);684685findModel.moveToPrevMatch();686assertFindState(687editor,688[6, 14, 6, 19],689[6, 14, 6, 19],690[691[6, 14, 6, 19],692[6, 27, 6, 32],693[7, 14, 7, 19],694[8, 14, 8, 19]695]696);697698findModel.moveToPrevMatch();699assertFindState(700editor,701[8, 14, 8, 19],702[8, 14, 8, 19],703[704[6, 14, 6, 19],705[6, 27, 6, 32],706[7, 14, 7, 19],707[8, 14, 8, 19]708]709);710711findModel.dispose();712findState.dispose();713});714715findTest('find model prev stays in scope', (editor) => {716const findState = disposables.add(new FindReplaceState());717findState.change({ searchString: 'hello', wholeWord: true, searchScope: [new Range(7, 1, 9, 1)] }, false);718const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));719720assertFindState(721editor,722[1, 1, 1, 1],723null,724[725[7, 14, 7, 19],726[8, 14, 8, 19]727]728);729730findModel.moveToPrevMatch();731assertFindState(732editor,733[8, 14, 8, 19],734[8, 14, 8, 19],735[736[7, 14, 7, 19],737[8, 14, 8, 19]738]739);740741findModel.moveToPrevMatch();742assertFindState(743editor,744[7, 14, 7, 19],745[7, 14, 7, 19],746[747[7, 14, 7, 19],748[8, 14, 8, 19]749]750);751752findModel.moveToPrevMatch();753assertFindState(754editor,755[8, 14, 8, 19],756[8, 14, 8, 19],757[758[7, 14, 7, 19],759[8, 14, 8, 19]760]761);762763findModel.dispose();764findState.dispose();765});766767findTest('find model next/prev with no matches', (editor) => {768const findState = disposables.add(new FindReplaceState());769findState.change({ searchString: 'helloo', wholeWord: true }, false);770const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));771772assertFindState(773editor,774[1, 1, 1, 1],775null,776[]777);778779findModel.moveToNextMatch();780assertFindState(781editor,782[1, 1, 1, 1],783null,784[]785);786787findModel.moveToPrevMatch();788assertFindState(789editor,790[1, 1, 1, 1],791null,792[]793);794795findModel.dispose();796findState.dispose();797});798799findTest('find model next/prev respects cursor position', (editor) => {800const findState = disposables.add(new FindReplaceState());801findState.change({ searchString: 'hello', wholeWord: true }, false);802const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));803804assertFindState(805editor,806[1, 1, 1, 1],807null,808[809[6, 14, 6, 19],810[6, 27, 6, 32],811[7, 14, 7, 19],812[8, 14, 8, 19]813]814);815816editor.trigger('mouse', CoreNavigationCommands.MoveTo.id, {817position: new Position(6, 20)818});819assertFindState(820editor,821[6, 20, 6, 20],822null,823[824[6, 14, 6, 19],825[6, 27, 6, 32],826[7, 14, 7, 19],827[8, 14, 8, 19]828]829);830831findModel.moveToNextMatch();832assertFindState(833editor,834[6, 27, 6, 32],835[6, 27, 6, 32],836[837[6, 14, 6, 19],838[6, 27, 6, 32],839[7, 14, 7, 19],840[8, 14, 8, 19]841]842);843844findModel.dispose();845findState.dispose();846});847848findTest('find ^', (editor) => {849const findState = disposables.add(new FindReplaceState());850findState.change({ searchString: '^', isRegex: true }, false);851const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));852853assertFindState(854editor,855[1, 1, 1, 1],856null,857[858[1, 1, 1, 1],859[2, 1, 2, 1],860[3, 1, 3, 1],861[4, 1, 4, 1],862[5, 1, 5, 1],863[6, 1, 6, 1],864[7, 1, 7, 1],865[8, 1, 8, 1],866[9, 1, 9, 1],867[10, 1, 10, 1],868[11, 1, 11, 1],869[12, 1, 12, 1],870]871);872873findModel.moveToNextMatch();874assertFindState(875editor,876[2, 1, 2, 1],877[2, 1, 2, 1],878[879[1, 1, 1, 1],880[2, 1, 2, 1],881[3, 1, 3, 1],882[4, 1, 4, 1],883[5, 1, 5, 1],884[6, 1, 6, 1],885[7, 1, 7, 1],886[8, 1, 8, 1],887[9, 1, 9, 1],888[10, 1, 10, 1],889[11, 1, 11, 1],890[12, 1, 12, 1],891]892);893894findModel.moveToNextMatch();895assertFindState(896editor,897[3, 1, 3, 1],898[3, 1, 3, 1],899[900[1, 1, 1, 1],901[2, 1, 2, 1],902[3, 1, 3, 1],903[4, 1, 4, 1],904[5, 1, 5, 1],905[6, 1, 6, 1],906[7, 1, 7, 1],907[8, 1, 8, 1],908[9, 1, 9, 1],909[10, 1, 10, 1],910[11, 1, 11, 1],911[12, 1, 12, 1],912]913);914915findModel.dispose();916findState.dispose();917});918919findTest('find $', (editor) => {920const findState = disposables.add(new FindReplaceState());921findState.change({ searchString: '$', isRegex: true }, false);922const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));923924assertFindState(925editor,926[1, 1, 1, 1],927null,928[929[1, 18, 1, 18],930[2, 18, 2, 18],931[3, 20, 3, 20],932[4, 1, 4, 1],933[5, 13, 5, 13],934[6, 43, 6, 43],935[7, 41, 7, 41],936[8, 41, 8, 41],937[9, 40, 9, 40],938[10, 2, 10, 2],939[11, 17, 11, 17],940[12, 1, 12, 1],941]942);943944findModel.moveToNextMatch();945assertFindState(946editor,947[1, 18, 1, 18],948[1, 18, 1, 18],949[950[1, 18, 1, 18],951[2, 18, 2, 18],952[3, 20, 3, 20],953[4, 1, 4, 1],954[5, 13, 5, 13],955[6, 43, 6, 43],956[7, 41, 7, 41],957[8, 41, 8, 41],958[9, 40, 9, 40],959[10, 2, 10, 2],960[11, 17, 11, 17],961[12, 1, 12, 1],962]963);964965findModel.moveToNextMatch();966assertFindState(967editor,968[2, 18, 2, 18],969[2, 18, 2, 18],970[971[1, 18, 1, 18],972[2, 18, 2, 18],973[3, 20, 3, 20],974[4, 1, 4, 1],975[5, 13, 5, 13],976[6, 43, 6, 43],977[7, 41, 7, 41],978[8, 41, 8, 41],979[9, 40, 9, 40],980[10, 2, 10, 2],981[11, 17, 11, 17],982[12, 1, 12, 1],983]984);985986findModel.moveToNextMatch();987assertFindState(988editor,989[3, 20, 3, 20],990[3, 20, 3, 20],991[992[1, 18, 1, 18],993[2, 18, 2, 18],994[3, 20, 3, 20],995[4, 1, 4, 1],996[5, 13, 5, 13],997[6, 43, 6, 43],998[7, 41, 7, 41],999[8, 41, 8, 41],1000[9, 40, 9, 40],1001[10, 2, 10, 2],1002[11, 17, 11, 17],1003[12, 1, 12, 1],1004]1005);10061007findModel.dispose();1008findState.dispose();1009});10101011findTest('find next ^$', (editor) => {1012const findState = disposables.add(new FindReplaceState());1013findState.change({ searchString: '^$', isRegex: true }, false);1014const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));10151016assertFindState(1017editor,1018[1, 1, 1, 1],1019null,1020[1021[4, 1, 4, 1],1022[12, 1, 12, 1],1023]1024);10251026findModel.moveToNextMatch();1027assertFindState(1028editor,1029[4, 1, 4, 1],1030[4, 1, 4, 1],1031[1032[4, 1, 4, 1],1033[12, 1, 12, 1],1034]1035);10361037findModel.moveToNextMatch();1038assertFindState(1039editor,1040[12, 1, 12, 1],1041[12, 1, 12, 1],1042[1043[4, 1, 4, 1],1044[12, 1, 12, 1],1045]1046);10471048findModel.moveToNextMatch();1049assertFindState(1050editor,1051[4, 1, 4, 1],1052[4, 1, 4, 1],1053[1054[4, 1, 4, 1],1055[12, 1, 12, 1],1056]1057);10581059findModel.dispose();1060findState.dispose();1061});10621063findTest('find .*', (editor) => {1064const findState = disposables.add(new FindReplaceState());1065findState.change({ searchString: '.*', isRegex: true }, false);1066const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));10671068assertFindState(1069editor,1070[1, 1, 1, 1],1071null,1072[1073[1, 1, 1, 18],1074[2, 1, 2, 18],1075[3, 1, 3, 20],1076[4, 1, 4, 1],1077[5, 1, 5, 13],1078[6, 1, 6, 43],1079[7, 1, 7, 41],1080[8, 1, 8, 41],1081[9, 1, 9, 40],1082[10, 1, 10, 2],1083[11, 1, 11, 17],1084[12, 1, 12, 1],1085]1086);10871088findModel.dispose();1089findState.dispose();1090});10911092findTest('find next ^.*$', (editor) => {1093const findState = disposables.add(new FindReplaceState());1094findState.change({ searchString: '^.*$', isRegex: true }, false);1095const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));10961097assertFindState(1098editor,1099[1, 1, 1, 1],1100null,1101[1102[1, 1, 1, 18],1103[2, 1, 2, 18],1104[3, 1, 3, 20],1105[4, 1, 4, 1],1106[5, 1, 5, 13],1107[6, 1, 6, 43],1108[7, 1, 7, 41],1109[8, 1, 8, 41],1110[9, 1, 9, 40],1111[10, 1, 10, 2],1112[11, 1, 11, 17],1113[12, 1, 12, 1],1114]1115);11161117findModel.moveToNextMatch();1118assertFindState(1119editor,1120[1, 1, 1, 18],1121[1, 1, 1, 18],1122[1123[1, 1, 1, 18],1124[2, 1, 2, 18],1125[3, 1, 3, 20],1126[4, 1, 4, 1],1127[5, 1, 5, 13],1128[6, 1, 6, 43],1129[7, 1, 7, 41],1130[8, 1, 8, 41],1131[9, 1, 9, 40],1132[10, 1, 10, 2],1133[11, 1, 11, 17],1134[12, 1, 12, 1],1135]1136);11371138findModel.moveToNextMatch();1139assertFindState(1140editor,1141[2, 1, 2, 18],1142[2, 1, 2, 18],1143[1144[1, 1, 1, 18],1145[2, 1, 2, 18],1146[3, 1, 3, 20],1147[4, 1, 4, 1],1148[5, 1, 5, 13],1149[6, 1, 6, 43],1150[7, 1, 7, 41],1151[8, 1, 8, 41],1152[9, 1, 9, 40],1153[10, 1, 10, 2],1154[11, 1, 11, 17],1155[12, 1, 12, 1],1156]1157);11581159findModel.dispose();1160findState.dispose();1161});11621163findTest('find prev ^.*$', (editor) => {1164const findState = disposables.add(new FindReplaceState());1165findState.change({ searchString: '^.*$', isRegex: true }, false);1166const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));11671168assertFindState(1169editor,1170[1, 1, 1, 1],1171null,1172[1173[1, 1, 1, 18],1174[2, 1, 2, 18],1175[3, 1, 3, 20],1176[4, 1, 4, 1],1177[5, 1, 5, 13],1178[6, 1, 6, 43],1179[7, 1, 7, 41],1180[8, 1, 8, 41],1181[9, 1, 9, 40],1182[10, 1, 10, 2],1183[11, 1, 11, 17],1184[12, 1, 12, 1],1185]1186);11871188findModel.moveToPrevMatch();1189assertFindState(1190editor,1191[12, 1, 12, 1],1192[12, 1, 12, 1],1193[1194[1, 1, 1, 18],1195[2, 1, 2, 18],1196[3, 1, 3, 20],1197[4, 1, 4, 1],1198[5, 1, 5, 13],1199[6, 1, 6, 43],1200[7, 1, 7, 41],1201[8, 1, 8, 41],1202[9, 1, 9, 40],1203[10, 1, 10, 2],1204[11, 1, 11, 17],1205[12, 1, 12, 1],1206]1207);12081209findModel.moveToPrevMatch();1210assertFindState(1211editor,1212[11, 1, 11, 17],1213[11, 1, 11, 17],1214[1215[1, 1, 1, 18],1216[2, 1, 2, 18],1217[3, 1, 3, 20],1218[4, 1, 4, 1],1219[5, 1, 5, 13],1220[6, 1, 6, 43],1221[7, 1, 7, 41],1222[8, 1, 8, 41],1223[9, 1, 9, 40],1224[10, 1, 10, 2],1225[11, 1, 11, 17],1226[12, 1, 12, 1],1227]1228);12291230findModel.dispose();1231findState.dispose();1232});12331234findTest('find prev ^$', (editor) => {1235const findState = disposables.add(new FindReplaceState());1236findState.change({ searchString: '^$', isRegex: true }, false);1237const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));12381239assertFindState(1240editor,1241[1, 1, 1, 1],1242null,1243[1244[4, 1, 4, 1],1245[12, 1, 12, 1],1246]1247);12481249findModel.moveToPrevMatch();1250assertFindState(1251editor,1252[12, 1, 12, 1],1253[12, 1, 12, 1],1254[1255[4, 1, 4, 1],1256[12, 1, 12, 1],1257]1258);12591260findModel.moveToPrevMatch();1261assertFindState(1262editor,1263[4, 1, 4, 1],1264[4, 1, 4, 1],1265[1266[4, 1, 4, 1],1267[12, 1, 12, 1],1268]1269);12701271findModel.moveToPrevMatch();1272assertFindState(1273editor,1274[12, 1, 12, 1],1275[12, 1, 12, 1],1276[1277[4, 1, 4, 1],1278[12, 1, 12, 1],1279]1280);12811282findModel.dispose();1283findState.dispose();1284});12851286findTest('replace hello', (editor) => {1287const findState = disposables.add(new FindReplaceState());1288findState.change({ searchString: 'hello', replaceString: 'hi', wholeWord: true }, false);1289const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));12901291assertFindState(1292editor,1293[1, 1, 1, 1],1294null,1295[1296[6, 14, 6, 19],1297[6, 27, 6, 32],1298[7, 14, 7, 19],1299[8, 14, 8, 19]1300]1301);13021303editor.trigger('mouse', CoreNavigationCommands.MoveTo.id, {1304position: new Position(6, 20)1305});1306assertFindState(1307editor,1308[6, 20, 6, 20],1309null,1310[1311[6, 14, 6, 19],1312[6, 27, 6, 32],1313[7, 14, 7, 19],1314[8, 14, 8, 19]1315]1316);1317assert.strictEqual(editor.getModel()!.getLineContent(6), ' cout << "hello world, Hello!" << endl;');13181319findModel.replace();1320assertFindState(1321editor,1322[6, 27, 6, 32],1323[6, 27, 6, 32],1324[1325[6, 14, 6, 19],1326[6, 27, 6, 32],1327[7, 14, 7, 19],1328[8, 14, 8, 19]1329]1330);1331assert.strictEqual(editor.getModel()!.getLineContent(6), ' cout << "hello world, Hello!" << endl;');13321333findModel.replace();1334assertFindState(1335editor,1336[7, 14, 7, 19],1337[7, 14, 7, 19],1338[1339[6, 14, 6, 19],1340[7, 14, 7, 19],1341[8, 14, 8, 19]1342]1343);1344assert.strictEqual(editor.getModel()!.getLineContent(6), ' cout << "hello world, hi!" << endl;');13451346findModel.replace();1347assertFindState(1348editor,1349[8, 14, 8, 19],1350[8, 14, 8, 19],1351[1352[6, 14, 6, 19],1353[8, 14, 8, 19]1354]1355);1356assert.strictEqual(editor.getModel()!.getLineContent(7), ' cout << "hi world again" << endl;');13571358findModel.replace();1359assertFindState(1360editor,1361[6, 14, 6, 19],1362[6, 14, 6, 19],1363[1364[6, 14, 6, 19]1365]1366);1367assert.strictEqual(editor.getModel()!.getLineContent(8), ' cout << "hi world again" << endl;');13681369findModel.replace();1370assertFindState(1371editor,1372[6, 16, 6, 16],1373null,1374[]1375);1376assert.strictEqual(editor.getModel()!.getLineContent(6), ' cout << "hi world, hi!" << endl;');13771378findModel.dispose();1379findState.dispose();1380});13811382findTest('replace bla', (editor) => {1383const findState = disposables.add(new FindReplaceState());1384findState.change({ searchString: 'bla', replaceString: 'ciao' }, false);1385const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));13861387assertFindState(1388editor,1389[1, 1, 1, 1],1390null,1391[1392[11, 4, 11, 7],1393[11, 7, 11, 10],1394[11, 10, 11, 13]1395]1396);13971398findModel.replace();1399assertFindState(1400editor,1401[11, 4, 11, 7],1402[11, 4, 11, 7],1403[1404[11, 4, 11, 7],1405[11, 7, 11, 10],1406[11, 10, 11, 13]1407]1408);1409assert.strictEqual(editor.getModel()!.getLineContent(11), '// blablablaciao');14101411findModel.replace();1412assertFindState(1413editor,1414[11, 8, 11, 11],1415[11, 8, 11, 11],1416[1417[11, 8, 11, 11],1418[11, 11, 11, 14]1419]1420);1421assert.strictEqual(editor.getModel()!.getLineContent(11), '// ciaoblablaciao');14221423findModel.replace();1424assertFindState(1425editor,1426[11, 12, 11, 15],1427[11, 12, 11, 15],1428[1429[11, 12, 11, 15]1430]1431);1432assert.strictEqual(editor.getModel()!.getLineContent(11), '// ciaociaoblaciao');14331434findModel.replace();1435assertFindState(1436editor,1437[11, 16, 11, 16],1438null,1439[]1440);1441assert.strictEqual(editor.getModel()!.getLineContent(11), '// ciaociaociaociao');14421443findModel.dispose();1444findState.dispose();1445});14461447findTest('replaceAll hello', (editor) => {1448const findState = disposables.add(new FindReplaceState());1449findState.change({ searchString: 'hello', replaceString: 'hi', wholeWord: true }, false);1450const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));14511452assertFindState(1453editor,1454[1, 1, 1, 1],1455null,1456[1457[6, 14, 6, 19],1458[6, 27, 6, 32],1459[7, 14, 7, 19],1460[8, 14, 8, 19]1461]1462);14631464editor.trigger('mouse', CoreNavigationCommands.MoveTo.id, {1465position: new Position(6, 20)1466});1467assertFindState(1468editor,1469[6, 20, 6, 20],1470null,1471[1472[6, 14, 6, 19],1473[6, 27, 6, 32],1474[7, 14, 7, 19],1475[8, 14, 8, 19]1476]1477);1478assert.strictEqual(editor.getModel()!.getLineContent(6), ' cout << "hello world, Hello!" << endl;');14791480findModel.replaceAll();1481assertFindState(1482editor,1483[6, 17, 6, 17],1484null,1485[]1486);1487assert.strictEqual(editor.getModel()!.getLineContent(6), ' cout << "hi world, hi!" << endl;');1488assert.strictEqual(editor.getModel()!.getLineContent(7), ' cout << "hi world again" << endl;');1489assert.strictEqual(editor.getModel()!.getLineContent(8), ' cout << "hi world again" << endl;');14901491findModel.dispose();1492findState.dispose();1493});14941495findTest('replaceAll two spaces with one space', (editor) => {1496const findState = disposables.add(new FindReplaceState());1497findState.change({ searchString: ' ', replaceString: ' ' }, false);1498const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));14991500assertFindState(1501editor,1502[1, 1, 1, 1],1503null,1504[1505[6, 1, 6, 3],1506[6, 3, 6, 5],1507[7, 1, 7, 3],1508[7, 3, 7, 5],1509[8, 1, 8, 3],1510[8, 3, 8, 5],1511[9, 1, 9, 3],1512[9, 3, 9, 5]1513]1514);15151516findModel.replaceAll();1517assertFindState(1518editor,1519[1, 1, 1, 1],1520null,1521[1522[6, 1, 6, 3],1523[7, 1, 7, 3],1524[8, 1, 8, 3],1525[9, 1, 9, 3]1526]1527);1528assert.strictEqual(editor.getModel()!.getLineContent(6), ' cout << "hello world, Hello!" << endl;');1529assert.strictEqual(editor.getModel()!.getLineContent(7), ' cout << "hello world again" << endl;');1530assert.strictEqual(editor.getModel()!.getLineContent(8), ' cout << "Hello world again" << endl;');1531assert.strictEqual(editor.getModel()!.getLineContent(9), ' cout << "helloworld again" << endl;');15321533findModel.dispose();1534findState.dispose();1535});15361537findTest('replaceAll bla', (editor) => {1538const findState = disposables.add(new FindReplaceState());1539findState.change({ searchString: 'bla', replaceString: 'ciao' }, false);1540const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));15411542assertFindState(1543editor,1544[1, 1, 1, 1],1545null,1546[1547[11, 4, 11, 7],1548[11, 7, 11, 10],1549[11, 10, 11, 13]1550]1551);15521553findModel.replaceAll();1554assertFindState(1555editor,1556[1, 1, 1, 1],1557null,1558[]1559);1560assert.strictEqual(editor.getModel()!.getLineContent(11), '// ciaociaociaociao');15611562findModel.dispose();1563findState.dispose();1564});15651566findTest('replaceAll bla with \\t\\n', (editor) => {1567const findState = disposables.add(new FindReplaceState());1568findState.change({ searchString: 'bla', replaceString: '<\\n\\t>', isRegex: true }, false);1569const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));15701571assertFindState(1572editor,1573[1, 1, 1, 1],1574null,1575[1576[11, 4, 11, 7],1577[11, 7, 11, 10],1578[11, 10, 11, 13]1579]1580);15811582findModel.replaceAll();1583assertFindState(1584editor,1585[1, 1, 1, 1],1586null,1587[]1588);1589assert.strictEqual(editor.getModel()!.getLineContent(11), '// <');1590assert.strictEqual(editor.getModel()!.getLineContent(12), '\t><');1591assert.strictEqual(editor.getModel()!.getLineContent(13), '\t><');1592assert.strictEqual(editor.getModel()!.getLineContent(14), '\t>ciao');15931594findModel.dispose();1595findState.dispose();1596});15971598findTest('issue #3516: "replace all" moves page/cursor/focus/scroll to the place of the last replacement', (editor) => {1599const findState = disposables.add(new FindReplaceState());1600findState.change({ searchString: 'include', replaceString: 'bar' }, false);1601const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));16021603assertFindState(1604editor,1605[1, 1, 1, 1],1606null,1607[1608[2, 2, 2, 9],1609[3, 2, 3, 9]1610]1611);16121613findModel.replaceAll();1614assertFindState(1615editor,1616[1, 1, 1, 1],1617null,1618[]1619);16201621assert.strictEqual(editor.getModel()!.getLineContent(2), '#bar "cool.h"');1622assert.strictEqual(editor.getModel()!.getLineContent(3), '#bar <iostream>');16231624findModel.dispose();1625findState.dispose();1626});16271628findTest('listens to model content changes', (editor) => {1629const findState = disposables.add(new FindReplaceState());1630findState.change({ searchString: 'hello', replaceString: 'hi', wholeWord: true }, false);1631const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));16321633assertFindState(1634editor,1635[1, 1, 1, 1],1636null,1637[1638[6, 14, 6, 19],1639[6, 27, 6, 32],1640[7, 14, 7, 19],1641[8, 14, 8, 19]1642]1643);16441645editor.getModel()!.setValue('hello\nhi');1646assertFindState(1647editor,1648[1, 1, 1, 1],1649null,1650[]1651);16521653findModel.dispose();1654findState.dispose();1655});16561657findTest('selectAllMatches', (editor) => {1658const findState = disposables.add(new FindReplaceState());1659findState.change({ searchString: 'hello', replaceString: 'hi', wholeWord: true }, false);1660const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));16611662assertFindState(1663editor,1664[1, 1, 1, 1],1665null,1666[1667[6, 14, 6, 19],1668[6, 27, 6, 32],1669[7, 14, 7, 19],1670[8, 14, 8, 19]1671]1672);16731674findModel.selectAllMatches();16751676assert.deepStrictEqual(editor.getSelections()!.map(s => s.toString()), [1677new Selection(6, 14, 6, 19),1678new Selection(6, 27, 6, 32),1679new Selection(7, 14, 7, 19),1680new Selection(8, 14, 8, 19)1681].map(s => s.toString()));16821683assertFindState(1684editor,1685[6, 14, 6, 19],1686null,1687[1688[6, 14, 6, 19],1689[6, 27, 6, 32],1690[7, 14, 7, 19],1691[8, 14, 8, 19]1692]1693);16941695findModel.dispose();1696findState.dispose();1697});16981699findTest('issue #14143 selectAllMatches should maintain primary cursor if feasible', (editor) => {1700const findState = disposables.add(new FindReplaceState());1701findState.change({ searchString: 'hello', replaceString: 'hi', wholeWord: true }, false);1702const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));17031704assertFindState(1705editor,1706[1, 1, 1, 1],1707null,1708[1709[6, 14, 6, 19],1710[6, 27, 6, 32],1711[7, 14, 7, 19],1712[8, 14, 8, 19]1713]1714);17151716editor.setSelection(new Range(7, 14, 7, 19));17171718findModel.selectAllMatches();17191720assert.deepStrictEqual(editor.getSelections()!.map(s => s.toString()), [1721new Selection(7, 14, 7, 19),1722new Selection(6, 14, 6, 19),1723new Selection(6, 27, 6, 32),1724new Selection(8, 14, 8, 19)1725].map(s => s.toString()));17261727assert.deepStrictEqual(editor.getSelection()!.toString(), new Selection(7, 14, 7, 19).toString());17281729assertFindState(1730editor,1731[7, 14, 7, 19],1732null,1733[1734[6, 14, 6, 19],1735[6, 27, 6, 32],1736[7, 14, 7, 19],1737[8, 14, 8, 19]1738]1739);17401741findModel.dispose();1742findState.dispose();1743});17441745findTest('issue #1914: NPE when there is only one find match', (editor) => {1746const findState = disposables.add(new FindReplaceState());1747findState.change({ searchString: 'cool.h' }, false);1748const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));17491750assertFindState(1751editor,1752[1, 1, 1, 1],1753null,1754[1755[2, 11, 2, 17]1756]1757);17581759findModel.moveToNextMatch();1760assertFindState(1761editor,1762[2, 11, 2, 17],1763[2, 11, 2, 17],1764[1765[2, 11, 2, 17]1766]1767);17681769findModel.moveToNextMatch();1770assertFindState(1771editor,1772[2, 11, 2, 17],1773[2, 11, 2, 17],1774[1775[2, 11, 2, 17]1776]1777);17781779findModel.dispose();1780findState.dispose();1781});17821783findTest('replace when search string has look ahed regex', (editor) => {1784const findState = disposables.add(new FindReplaceState());1785findState.change({ searchString: 'hello(?=\\sworld)', replaceString: 'hi', isRegex: true }, false);1786const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));17871788assertFindState(1789editor,1790[1, 1, 1, 1],1791null,1792[1793[6, 14, 6, 19],1794[7, 14, 7, 19],1795[8, 14, 8, 19]1796]1797);17981799findModel.replace();18001801assertFindState(1802editor,1803[6, 14, 6, 19],1804[6, 14, 6, 19],1805[1806[6, 14, 6, 19],1807[7, 14, 7, 19],1808[8, 14, 8, 19]1809]1810);1811assert.strictEqual(editor.getModel()!.getLineContent(6), ' cout << "hello world, Hello!" << endl;');18121813findModel.replace();1814assertFindState(1815editor,1816[7, 14, 7, 19],1817[7, 14, 7, 19],1818[1819[7, 14, 7, 19],1820[8, 14, 8, 19]1821]1822);1823assert.strictEqual(editor.getModel()!.getLineContent(6), ' cout << "hi world, Hello!" << endl;');18241825findModel.replace();1826assertFindState(1827editor,1828[8, 14, 8, 19],1829[8, 14, 8, 19],1830[1831[8, 14, 8, 19]1832]1833);1834assert.strictEqual(editor.getModel()!.getLineContent(7), ' cout << "hi world again" << endl;');18351836findModel.replace();1837assertFindState(1838editor,1839[8, 16, 8, 16],1840null,1841[]1842);1843assert.strictEqual(editor.getModel()!.getLineContent(8), ' cout << "hi world again" << endl;');18441845findModel.dispose();1846findState.dispose();1847});18481849findTest('replace when search string has look ahed regex and cursor is at the last find match', (editor) => {1850const findState = disposables.add(new FindReplaceState());1851findState.change({ searchString: 'hello(?=\\sworld)', replaceString: 'hi', isRegex: true }, false);1852const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));18531854editor.trigger('mouse', CoreNavigationCommands.MoveTo.id, {1855position: new Position(8, 14)1856});18571858assertFindState(1859editor,1860[8, 14, 8, 14],1861null,1862[1863[6, 14, 6, 19],1864[7, 14, 7, 19],1865[8, 14, 8, 19]1866]1867);18681869findModel.replace();18701871assertFindState(1872editor,1873[8, 14, 8, 19],1874[8, 14, 8, 19],1875[1876[6, 14, 6, 19],1877[7, 14, 7, 19],1878[8, 14, 8, 19]1879]1880);18811882assert.strictEqual(editor.getModel()!.getLineContent(8), ' cout << "Hello world again" << endl;');18831884findModel.replace();1885assertFindState(1886editor,1887[6, 14, 6, 19],1888[6, 14, 6, 19],1889[1890[6, 14, 6, 19],1891[7, 14, 7, 19],1892]1893);1894assert.strictEqual(editor.getModel()!.getLineContent(8), ' cout << "hi world again" << endl;');18951896findModel.replace();1897assertFindState(1898editor,1899[7, 14, 7, 19],1900[7, 14, 7, 19],1901[1902[7, 14, 7, 19]1903]1904);1905assert.strictEqual(editor.getModel()!.getLineContent(6), ' cout << "hi world, Hello!" << endl;');19061907findModel.replace();1908assertFindState(1909editor,1910[7, 16, 7, 16],1911null,1912[]1913);1914assert.strictEqual(editor.getModel()!.getLineContent(7), ' cout << "hi world again" << endl;');19151916findModel.dispose();1917findState.dispose();1918});19191920findTest('replaceAll when search string has look ahed regex', (editor) => {1921const findState = disposables.add(new FindReplaceState());1922findState.change({ searchString: 'hello(?=\\sworld)', replaceString: 'hi', isRegex: true }, false);1923const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));19241925assertFindState(1926editor,1927[1, 1, 1, 1],1928null,1929[1930[6, 14, 6, 19],1931[7, 14, 7, 19],1932[8, 14, 8, 19]1933]1934);19351936findModel.replaceAll();19371938assert.strictEqual(editor.getModel()!.getLineContent(6), ' cout << "hi world, Hello!" << endl;');1939assert.strictEqual(editor.getModel()!.getLineContent(7), ' cout << "hi world again" << endl;');1940assert.strictEqual(editor.getModel()!.getLineContent(8), ' cout << "hi world again" << endl;');19411942assertFindState(1943editor,1944[1, 1, 1, 1],1945null,1946[]1947);19481949findModel.dispose();1950findState.dispose();1951});19521953findTest('replace when search string has look ahed regex and replace string has capturing groups', (editor) => {1954const findState = disposables.add(new FindReplaceState());1955findState.change({ searchString: 'hel(lo)(?=\\sworld)', replaceString: 'hi$1', isRegex: true }, false);1956const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));19571958assertFindState(1959editor,1960[1, 1, 1, 1],1961null,1962[1963[6, 14, 6, 19],1964[7, 14, 7, 19],1965[8, 14, 8, 19]1966]1967);19681969findModel.replace();19701971assertFindState(1972editor,1973[6, 14, 6, 19],1974[6, 14, 6, 19],1975[1976[6, 14, 6, 19],1977[7, 14, 7, 19],1978[8, 14, 8, 19]1979]1980);1981assert.strictEqual(editor.getModel()!.getLineContent(6), ' cout << "hello world, Hello!" << endl;');19821983findModel.replace();1984assertFindState(1985editor,1986[7, 14, 7, 19],1987[7, 14, 7, 19],1988[1989[7, 14, 7, 19],1990[8, 14, 8, 19]1991]1992);1993assert.strictEqual(editor.getModel()!.getLineContent(6), ' cout << "hilo world, Hello!" << endl;');19941995findModel.replace();1996assertFindState(1997editor,1998[8, 14, 8, 19],1999[8, 14, 8, 19],2000[2001[8, 14, 8, 19]2002]2003);2004assert.strictEqual(editor.getModel()!.getLineContent(7), ' cout << "hilo world again" << endl;');20052006findModel.replace();2007assertFindState(2008editor,2009[8, 18, 8, 18],2010null,2011[]2012);2013assert.strictEqual(editor.getModel()!.getLineContent(8), ' cout << "hilo world again" << endl;');20142015findModel.dispose();2016findState.dispose();2017});20182019findTest('replaceAll when search string has look ahed regex and replace string has capturing groups', (editor) => {2020const findState = disposables.add(new FindReplaceState());2021findState.change({ searchString: 'wo(rl)d(?=.*;$)', replaceString: 'gi$1', isRegex: true }, false);2022const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));20232024assertFindState(2025editor,2026[1, 1, 1, 1],2027null,2028[2029[6, 20, 6, 25],2030[7, 20, 7, 25],2031[8, 20, 8, 25],2032[9, 19, 9, 24]2033]2034);20352036findModel.replaceAll();20372038assert.strictEqual(editor.getModel()!.getLineContent(6), ' cout << "hello girl, Hello!" << endl;');2039assert.strictEqual(editor.getModel()!.getLineContent(7), ' cout << "hello girl again" << endl;');2040assert.strictEqual(editor.getModel()!.getLineContent(8), ' cout << "Hello girl again" << endl;');2041assert.strictEqual(editor.getModel()!.getLineContent(9), ' cout << "hellogirl again" << endl;');20422043assertFindState(2044editor,2045[1, 1, 1, 1],2046null,2047[]2048);20492050findModel.dispose();2051findState.dispose();2052});20532054findTest('replaceAll when search string is multiline and has look ahed regex and replace string has capturing groups', (editor) => {2055const findState = disposables.add(new FindReplaceState());2056findState.change({ searchString: 'wo(rl)d(.*;\\n)(?=.*hello)', replaceString: 'gi$1$2', isRegex: true, matchCase: true }, false);2057const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));20582059assertFindState(2060editor,2061[1, 1, 1, 1],2062null,2063[2064[6, 20, 7, 1],2065[8, 20, 9, 1]2066]2067);20682069findModel.replaceAll();20702071assert.strictEqual(editor.getModel()!.getLineContent(6), ' cout << "hello girl, Hello!" << endl;');2072assert.strictEqual(editor.getModel()!.getLineContent(8), ' cout << "Hello girl again" << endl;');20732074assertFindState(2075editor,2076[1, 1, 1, 1],2077null,2078[]2079);20802081findModel.dispose();2082findState.dispose();2083});20842085findTest('replaceAll preserving case', (editor) => {2086const findState = disposables.add(new FindReplaceState());2087findState.change({ searchString: 'hello', replaceString: 'goodbye', isRegex: false, matchCase: false, preserveCase: true }, false);2088const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));20892090assertFindState(2091editor,2092[1, 1, 1, 1],2093null,2094[2095[6, 14, 6, 19],2096[6, 27, 6, 32],2097[7, 14, 7, 19],2098[8, 14, 8, 19],2099[9, 14, 9, 19],2100]2101);21022103findModel.replaceAll();21042105assert.strictEqual(editor.getModel()!.getLineContent(6), ' cout << "goodbye world, Goodbye!" << endl;');2106assert.strictEqual(editor.getModel()!.getLineContent(7), ' cout << "goodbye world again" << endl;');2107assert.strictEqual(editor.getModel()!.getLineContent(8), ' cout << "Goodbye world again" << endl;');2108assert.strictEqual(editor.getModel()!.getLineContent(9), ' cout << "goodbyeworld again" << endl;');21092110assertFindState(2111editor,2112[1, 1, 1, 1],2113null,2114[]2115);21162117findModel.dispose();2118findState.dispose();2119});21202121findTest('issue #18711 replaceAll with empty string', (editor) => {2122const findState = disposables.add(new FindReplaceState());2123findState.change({ searchString: 'hello', replaceString: '', wholeWord: true }, false);2124const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));21252126assertFindState(2127editor,2128[1, 1, 1, 1],2129null,2130[2131[6, 14, 6, 19],2132[6, 27, 6, 32],2133[7, 14, 7, 19],2134[8, 14, 8, 19]2135]2136);21372138findModel.replaceAll();2139assertFindState(2140editor,2141[1, 1, 1, 1],2142null,2143[]2144);2145assert.strictEqual(editor.getModel()!.getLineContent(6), ' cout << " world, !" << endl;');2146assert.strictEqual(editor.getModel()!.getLineContent(7), ' cout << " world again" << endl;');2147assert.strictEqual(editor.getModel()!.getLineContent(8), ' cout << " world again" << endl;');21482149findModel.dispose();2150findState.dispose();2151});21522153findTest('issue #32522 replaceAll with ^ on more than 1000 matches', (editor) => {2154let initialText = '';2155for (let i = 0; i < 1100; i++) {2156initialText += 'line' + i + '\n';2157}2158editor.getModel()!.setValue(initialText);2159const findState = disposables.add(new FindReplaceState());2160findState.change({ searchString: '^', replaceString: 'a ', isRegex: true }, false);2161const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));21622163findModel.replaceAll();21642165let expectedText = '';2166for (let i = 0; i < 1100; i++) {2167expectedText += 'a line' + i + '\n';2168}2169expectedText += 'a ';2170assert.strictEqual(editor.getModel()!.getValue(), expectedText);21712172findModel.dispose();2173findState.dispose();2174});21752176findTest('issue #19740 Find and replace capture group/backreference inserts `undefined` instead of empty string', (editor) => {2177const findState = disposables.add(new FindReplaceState());2178findState.change({ searchString: 'hello(z)?', replaceString: 'hi$1', isRegex: true, matchCase: true }, false);2179const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));21802181assertFindState(2182editor,2183[1, 1, 1, 1],2184null,2185[2186[6, 14, 6, 19],2187[7, 14, 7, 19],2188[9, 14, 9, 19]2189]2190);21912192findModel.replaceAll();2193assertFindState(2194editor,2195[1, 1, 1, 1],2196null,2197[]2198);2199assert.strictEqual(editor.getModel()!.getLineContent(6), ' cout << "hi world, Hello!" << endl;');2200assert.strictEqual(editor.getModel()!.getLineContent(7), ' cout << "hi world again" << endl;');2201assert.strictEqual(editor.getModel()!.getLineContent(9), ' cout << "hiworld again" << endl;');22022203findModel.dispose();2204findState.dispose();2205});22062207findTest('issue #27083. search scope works even if it is a single line', (editor) => {2208const findState = disposables.add(new FindReplaceState());2209findState.change({ searchString: 'hello', wholeWord: true, searchScope: [new Range(7, 1, 8, 1)] }, false);2210const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));22112212assertFindState(2213editor,2214[1, 1, 1, 1],2215null,2216[2217[7, 14, 7, 19]2218]2219);22202221findModel.dispose();2222findState.dispose();2223});22242225findTest('issue #3516: Control behavior of "Next" operations (not looping back to beginning)', (editor) => {2226const findState = disposables.add(new FindReplaceState());2227findState.change({ searchString: 'hello', loop: false }, false);2228const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));22292230assert.strictEqual(findState.matchesCount, 5);22312232// Test next operations2233assert.strictEqual(findState.matchesPosition, 0);2234assert.strictEqual(findState.canNavigateForward(), true);2235assert.strictEqual(findState.canNavigateBack(), true);22362237findModel.moveToNextMatch();2238assert.strictEqual(findState.matchesPosition, 1);2239assert.strictEqual(findState.canNavigateForward(), true);2240assert.strictEqual(findState.canNavigateBack(), false);22412242findModel.moveToNextMatch();2243assert.strictEqual(findState.matchesPosition, 2);2244assert.strictEqual(findState.canNavigateForward(), true);2245assert.strictEqual(findState.canNavigateBack(), true);22462247findModel.moveToNextMatch();2248assert.strictEqual(findState.matchesPosition, 3);2249assert.strictEqual(findState.canNavigateForward(), true);2250assert.strictEqual(findState.canNavigateBack(), true);22512252findModel.moveToNextMatch();2253assert.strictEqual(findState.matchesPosition, 4);2254assert.strictEqual(findState.canNavigateForward(), true);2255assert.strictEqual(findState.canNavigateBack(), true);22562257findModel.moveToNextMatch();2258assert.strictEqual(findState.matchesPosition, 5);2259assert.strictEqual(findState.canNavigateForward(), false);2260assert.strictEqual(findState.canNavigateBack(), true);22612262findModel.moveToNextMatch();2263assert.strictEqual(findState.matchesPosition, 5);2264assert.strictEqual(findState.canNavigateForward(), false);2265assert.strictEqual(findState.canNavigateBack(), true);22662267findModel.moveToNextMatch();2268assert.strictEqual(findState.matchesPosition, 5);2269assert.strictEqual(findState.canNavigateForward(), false);2270assert.strictEqual(findState.canNavigateBack(), true);22712272// Test previous operations2273findModel.moveToPrevMatch();2274assert.strictEqual(findState.matchesPosition, 4);2275assert.strictEqual(findState.canNavigateForward(), true);2276assert.strictEqual(findState.canNavigateBack(), true);22772278findModel.moveToPrevMatch();2279assert.strictEqual(findState.matchesPosition, 3);2280assert.strictEqual(findState.canNavigateForward(), true);2281assert.strictEqual(findState.canNavigateBack(), true);22822283findModel.moveToPrevMatch();2284assert.strictEqual(findState.matchesPosition, 2);2285assert.strictEqual(findState.canNavigateForward(), true);2286assert.strictEqual(findState.canNavigateBack(), true);22872288findModel.moveToPrevMatch();2289assert.strictEqual(findState.matchesPosition, 1);2290assert.strictEqual(findState.canNavigateForward(), true);2291assert.strictEqual(findState.canNavigateBack(), false);22922293findModel.moveToPrevMatch();2294assert.strictEqual(findState.matchesPosition, 1);2295assert.strictEqual(findState.canNavigateForward(), true);2296assert.strictEqual(findState.canNavigateBack(), false);22972298findModel.moveToPrevMatch();2299assert.strictEqual(findState.matchesPosition, 1);2300assert.strictEqual(findState.canNavigateForward(), true);2301assert.strictEqual(findState.canNavigateBack(), false);23022303});23042305findTest('issue #3516: Control behavior of "Next" operations (looping back to beginning)', (editor) => {2306const findState = disposables.add(new FindReplaceState());2307findState.change({ searchString: 'hello' }, false);2308const findModel = disposables.add(new FindModelBoundToEditorModel(editor, findState));23092310assert.strictEqual(findState.matchesCount, 5);23112312// Test next operations2313assert.strictEqual(findState.matchesPosition, 0);2314assert.strictEqual(findState.canNavigateForward(), true);2315assert.strictEqual(findState.canNavigateBack(), true);23162317findModel.moveToNextMatch();2318assert.strictEqual(findState.matchesPosition, 1);2319assert.strictEqual(findState.canNavigateForward(), true);2320assert.strictEqual(findState.canNavigateBack(), true);23212322findModel.moveToNextMatch();2323assert.strictEqual(findState.matchesPosition, 2);2324assert.strictEqual(findState.canNavigateForward(), true);2325assert.strictEqual(findState.canNavigateBack(), true);23262327findModel.moveToNextMatch();2328assert.strictEqual(findState.matchesPosition, 3);2329assert.strictEqual(findState.canNavigateForward(), true);2330assert.strictEqual(findState.canNavigateBack(), true);23312332findModel.moveToNextMatch();2333assert.strictEqual(findState.matchesPosition, 4);2334assert.strictEqual(findState.canNavigateForward(), true);2335assert.strictEqual(findState.canNavigateBack(), true);23362337findModel.moveToNextMatch();2338assert.strictEqual(findState.matchesPosition, 5);2339assert.strictEqual(findState.canNavigateForward(), true);2340assert.strictEqual(findState.canNavigateBack(), true);23412342findModel.moveToNextMatch();2343assert.strictEqual(findState.matchesPosition, 1);2344assert.strictEqual(findState.canNavigateForward(), true);2345assert.strictEqual(findState.canNavigateBack(), true);23462347findModel.moveToNextMatch();2348assert.strictEqual(findState.matchesPosition, 2);2349assert.strictEqual(findState.canNavigateForward(), true);2350assert.strictEqual(findState.canNavigateBack(), true);23512352// Test previous operations2353findModel.moveToPrevMatch();2354assert.strictEqual(findState.matchesPosition, 1);2355assert.strictEqual(findState.canNavigateForward(), true);2356assert.strictEqual(findState.canNavigateBack(), true);23572358findModel.moveToPrevMatch();2359assert.strictEqual(findState.matchesPosition, 5);2360assert.strictEqual(findState.canNavigateForward(), true);2361assert.strictEqual(findState.canNavigateBack(), true);23622363findModel.moveToPrevMatch();2364assert.strictEqual(findState.matchesPosition, 4);2365assert.strictEqual(findState.canNavigateForward(), true);2366assert.strictEqual(findState.canNavigateBack(), true);23672368findModel.moveToPrevMatch();2369assert.strictEqual(findState.matchesPosition, 3);2370assert.strictEqual(findState.canNavigateForward(), true);2371assert.strictEqual(findState.canNavigateBack(), true);23722373findModel.moveToPrevMatch();2374assert.strictEqual(findState.matchesPosition, 2);2375assert.strictEqual(findState.canNavigateForward(), true);2376assert.strictEqual(findState.canNavigateBack(), true);23772378findModel.moveToPrevMatch();2379assert.strictEqual(findState.matchesPosition, 1);2380assert.strictEqual(findState.canNavigateForward(), true);2381assert.strictEqual(findState.canNavigateBack(), true);23822383});23842385});238623872388