src/vs/workbench/contrib/notebook/browser/contrib/find/findModel.ts/FindModel/_research
class FindModel:	async _research() {
		this._computePromise?.cancel();

		if (!this._state.isRevealed || !this._notebookEditor.hasModel()) {
			this.set([], false);
			return;
		}

		this._computePromise = createCancelablePromise(token => this._compute(token));

		const findMatches = await this._computePromise;
		if (!findMatches) {
			this.set([], false);
			return;
		}

		if (findMatches.length === 0) {
			this.set([], false);
			return;
		}

		if (this._currentMatch === -1) {
			// no active current match
			this.set(findMatches, false);
			return;
		}

		const oldCurrIndex = this._findMatchesStarts!.getIndexOf(this._currentMatch);
		const oldCurrCell = this._findMatches[oldCurrIndex.index].cell;
		const oldCurrMatchCellIndex = this._notebookEditor.getCellIndex(oldCurrCell);

		const findFirstMatchAfterCellIndex = (cellIndex: number) => {
			const matchAfterSelection = findFirstInSorted(findMatches.map(match => match.index), index => index >= cellIndex);
			this._updateCurrentMatch(findMatches, this._matchesCountBeforeIndex(findMatches, matchAfterSelection));
		};

		if (oldCurrMatchCellIndex < 0) {
			// the cell containing the active match is deleted
			if (this._notebookEditor.getLength() === 0) {
				this.set(findMatches, false);
				return;
			}

			findFirstMatchAfterCellIndex(oldCurrMatchCellIndex);
			return;
		}

		// the cell still exist
		const cell = this._notebookEditor.cellAt(oldCurrMatchCellIndex);
		// we will try restore the active find match in this cell, if it contains any find match

		if (cell.cellKind === CellKind.Markup && cell.getEditState() === CellEditState.Preview) {
			// find first match in this cell or below
			findFirstMatchAfterCellIndex(oldCurrMatchCellIndex);
			return;
		}

		// the cell is a markdown cell in editing mode or a code cell, both should have monaco editor rendered

		if (!this._currentMatchDecorations) {
			// no current highlight decoration
			findFirstMatchAfterCellIndex(oldCurrMatchCellIndex);
			return;
		}

		// check if there is monaco editor selection and find the first match, otherwise find the first match above current cell
		// this._findMatches[cellIndex].matches[matchIndex].range
		if (this._currentMatchDecorations.kind === 'input') {
			const currentMatchDecorationId = this._currentMatchDecorations.decorations.find(decoration => decoration.ownerId === cell.handle);

			if (!currentMatchDecorationId) {
				// current match decoration is no longer valid
				findFirstMatchAfterCellIndex(oldCurrMatchCellIndex);
				return;
			}

			const matchAfterSelection = findFirstInSorted(findMatches, match => match.index >= oldCurrMatchCellIndex) % findMatches.length;
			if (findMatches[matchAfterSelection].index > oldCurrMatchCellIndex) {
				// there is no search result in curr cell anymore, find the nearest one (from top to bottom)
				this._updateCurrentMatch(findMatches, this._matchesCountBeforeIndex(findMatches, matchAfterSelection));
				return;
			} else {
				// there are still some search results in current cell
				let currMatchRangeInEditor = cell.editorAttached && currentMatchDecorationId.decorations[0] ? cell.getCellDecorationRange(currentMatchDecorationId.decorations[0]) : null;

				if (currMatchRangeInEditor === null && oldCurrIndex.remainder < this._findMatches[oldCurrIndex.index].modelMatchCount) {
					currMatchRangeInEditor = (this._findMatches[oldCurrIndex.index].matches[oldCurrIndex.remainder] as FindMatch).range;
				}

				if (currMatchRangeInEditor !== null) {
					// we find a range for the previous current match, let's find the nearest one after it (can overlap)
					const cellMatch = findMatches[matchAfterSelection];
					const matchAfterOldSelection = findFirstInSorted(cellMatch.matches.slice(0, cellMatch.modelMatchCount), match => Range.compareRangesUsingStarts((match as FindMatch).range, currMatchRangeInEditor) >= 0);
					this._updateCurrentMatch(findMatches, this._matchesCountBeforeIndex(findMatches, matchAfterSelection) + matchAfterOldSelection);
				} else {
					// no range found, let's fall back to finding the nearest match
					this._updateCurrentMatch(findMatches, this._matchesCountBeforeIndex(findMatches, matchAfterSelection));
					return;
				}
			}
		} else {
			// output now has the highlight
			const matchAfterSelection = findFirstInSorted(findMatches.map(match => match.index), index => index >= oldCurrMatchCellIndex) % findMatches.length;
			this._updateCurrentMatch(findMatches, this._matchesCountBeforeIndex(findMatches, matchAfterSelection));
		}
	}