Skip to content

Commit f730160

Browse files
authored
Notebook Find Match content/webview polish. (microsoft#166913)
* Notebook Find Match content/webview polish. * 💄 * remove irrelevant file
1 parent 0319eed commit f730160

File tree

10 files changed

+141
-83
lines changed

10 files changed

+141
-83
lines changed

src/vs/workbench/contrib/notebook/browser/contrib/find/findModel.ts

Lines changed: 63 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import { CancelablePromise, createCancelablePromise, Delayer } from 'vs/base/common/async';
7-
import { INotebookEditor, CellFindMatch, CellEditState, CellFindMatchWithIndex, OutputFindMatch, ICellModelDecorations, ICellModelDeltaDecorations, INotebookDeltaDecoration, ICellViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
7+
import { INotebookEditor, CellEditState, CellFindMatchWithIndex, CellWebviewFindMatch, ICellModelDecorations, ICellModelDeltaDecorations, INotebookDeltaDecoration, ICellViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
88
import { Range } from 'vs/editor/common/core/range';
99
import { FindDecorations } from 'vs/editor/contrib/find/browser/findDecorations';
1010
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
@@ -20,9 +20,45 @@ import { CancellationToken } from 'vs/base/common/cancellation';
2020
import { NotebookFindFilters } from 'vs/workbench/contrib/notebook/browser/contrib/find/findFilters';
2121
import { overviewRulerFindMatchForeground, overviewRulerSelectionHighlightForeground } from 'vs/platform/theme/common/colorRegistry';
2222

23+
export class CellFindMatchModel implements CellFindMatchWithIndex {
24+
readonly cell: ICellViewModel;
25+
readonly index: number;
26+
private _contentMatches: FindMatch[];
27+
private _webviewMatches: CellWebviewFindMatch[];
28+
get length() {
29+
return this._contentMatches.length + this._webviewMatches.length;
30+
}
31+
32+
get contentMatches(): FindMatch[] {
33+
return this._contentMatches;
34+
}
35+
36+
get webviewMatches(): CellWebviewFindMatch[] {
37+
return this._webviewMatches;
38+
}
39+
40+
constructor(cell: ICellViewModel, index: number, contentMatches: FindMatch[], webviewMatches: CellWebviewFindMatch[]) {
41+
this.cell = cell;
42+
this.index = index;
43+
this._contentMatches = contentMatches;
44+
this._webviewMatches = webviewMatches;
45+
}
46+
47+
getMatch(index: number) {
48+
if (index >= this.length) {
49+
throw new Error('NotebookCellFindMatch: index out of range');
50+
}
51+
52+
if (index < this._contentMatches.length) {
53+
return this._contentMatches[index];
54+
}
55+
56+
return this._webviewMatches[index - this._contentMatches.length];
57+
}
58+
}
2359

2460
export class FindModel extends Disposable {
25-
private _findMatches: CellFindMatch[] = [];
61+
private _findMatches: CellFindMatchWithIndex[] = [];
2662
protected _findMatchesStarts: PrefixSumComputer | null = null;
2763
private _currentMatch: number = -1;
2864
private _allMatchesDecorations: ICellModelDecorations[] = [];
@@ -79,12 +115,12 @@ export class FindModel extends Disposable {
79115
getCurrentMatch() {
80116
const nextIndex = this._findMatchesStarts!.getIndexOf(this._currentMatch);
81117
const cell = this._findMatches[nextIndex.index].cell;
82-
const match = this._findMatches[nextIndex.index].matches[nextIndex.remainder];
118+
const match = this._findMatches[nextIndex.index].getMatch(nextIndex.remainder);
83119

84120
return {
85121
cell,
86122
match,
87-
isModelMatch: nextIndex.remainder < this._findMatches[nextIndex.index].modelMatchCount
123+
isModelMatch: nextIndex.remainder < this._findMatches[nextIndex.index].contentMatches.length
88124
};
89125
}
90126

@@ -96,7 +132,7 @@ export class FindModel extends Disposable {
96132
}
97133

98134
const findMatch = this.findMatches[findMatchIndex];
99-
const index = findMatch.matches.slice(0, findMatch.modelMatchCount).findIndex(match => (match as FindMatch).range.intersectRanges(focus.range) !== null);
135+
const index = findMatch.contentMatches.findIndex(match => match.range.intersectRanges(focus.range) !== null);
100136

101137
if (index === undefined) {
102138
return;
@@ -110,7 +146,7 @@ export class FindModel extends Disposable {
110146

111147
this._state.changeMatchInfo(
112148
this._currentMatch,
113-
this._findMatches.reduce((p, c) => p + c.matches.length, 0),
149+
this._findMatches.reduce((p, c) => p + c.length, 0),
114150
undefined
115151
);
116152
});
@@ -149,15 +185,15 @@ export class FindModel extends Disposable {
149185

150186
this._state.changeMatchInfo(
151187
this._currentMatch,
152-
this._findMatches.reduce((p, c) => p + c.matches.length, 0),
188+
this._findMatches.reduce((p, c) => p + c.length, 0),
153189
undefined
154190
);
155191
});
156192
}
157193

158194
private revealCellRange(cellIndex: number, matchIndex: number, outputOffset: number | null) {
159195
const findMatch = this._findMatches[cellIndex];
160-
if (matchIndex >= findMatch.modelMatchCount) {
196+
if (matchIndex >= findMatch.contentMatches.length) {
161197
// reveal output range
162198
this._notebookEditor.focusElement(findMatch.cell);
163199
const index = this._notebookEditor.getCellIndex(findMatch.cell);
@@ -166,7 +202,7 @@ export class FindModel extends Disposable {
166202
this._notebookEditor.revealCellOffsetInCenterAsync(findMatch.cell, outputOffset ?? 0);
167203
}
168204
} else {
169-
const match = findMatch.matches[matchIndex] as FindMatch;
205+
const match = findMatch.getMatch(matchIndex) as FindMatch;
170206
findMatch.cell.updateEditState(CellEditState.Editing, 'find');
171207
findMatch.cell.isInputCollapsed = false;
172208
this._notebookEditor.focusElement(findMatch.cell);
@@ -290,14 +326,14 @@ export class FindModel extends Disposable {
290326
// there are still some search results in current cell
291327
let currMatchRangeInEditor = cell.editorAttached && currentMatchDecorationId.decorations[0] ? cell.getCellDecorationRange(currentMatchDecorationId.decorations[0]) : null;
292328

293-
if (currMatchRangeInEditor === null && oldCurrIndex.remainder < this._findMatches[oldCurrIndex.index].modelMatchCount) {
294-
currMatchRangeInEditor = (this._findMatches[oldCurrIndex.index].matches[oldCurrIndex.remainder] as FindMatch).range;
329+
if (currMatchRangeInEditor === null && oldCurrIndex.remainder < this._findMatches[oldCurrIndex.index].contentMatches.length) {
330+
currMatchRangeInEditor = (this._findMatches[oldCurrIndex.index].getMatch(oldCurrIndex.remainder) as FindMatch).range;
295331
}
296332

297333
if (currMatchRangeInEditor !== null) {
298334
// we find a range for the previous current match, let's find the nearest one after it (can overlap)
299335
const cellMatch = findMatches[matchAfterSelection];
300-
const matchAfterOldSelection = findFirstInSorted(cellMatch.matches.slice(0, cellMatch.modelMatchCount), match => Range.compareRangesUsingStarts((match as FindMatch).range, currMatchRangeInEditor) >= 0);
336+
const matchAfterOldSelection = findFirstInSorted(cellMatch.contentMatches, match => Range.compareRangesUsingStarts((match as FindMatch).range, currMatchRangeInEditor) >= 0);
301337
this._updateCurrentMatch(findMatches, this._matchesCountBeforeIndex(findMatches, matchAfterSelection) + matchAfterOldSelection);
302338
} else {
303339
// no range found, let's fall back to finding the nearest match
@@ -312,7 +348,7 @@ export class FindModel extends Disposable {
312348
}
313349
}
314350

315-
private set(cellFindMatches: CellFindMatch[] | null, autoStart: boolean): void {
351+
private set(cellFindMatches: CellFindMatchWithIndex[] | null, autoStart: boolean): void {
316352
if (!cellFindMatches || !cellFindMatches.length) {
317353
this._findMatches = [];
318354
this.setAllFindMatchesDecorations([]);
@@ -323,7 +359,7 @@ export class FindModel extends Disposable {
323359

324360
this._state.changeMatchInfo(
325361
this._currentMatch,
326-
this._findMatches.reduce((p, c) => p + c.matches.length, 0),
362+
this._findMatches.reduce((p, c) => p + c.length, 0),
327363
undefined
328364
);
329365
return;
@@ -343,7 +379,7 @@ export class FindModel extends Disposable {
343379

344380
this._state.changeMatchInfo(
345381
this._currentMatch,
346-
this._findMatches.reduce((p, c) => p + c.matches.length, 0),
382+
this._findMatches.reduce((p, c) => p + c.length, 0),
347383
undefined
348384
);
349385
}
@@ -385,15 +421,15 @@ export class FindModel extends Disposable {
385421

386422
this._state.changeMatchInfo(
387423
this._currentMatch,
388-
this._findMatches.reduce((p, c) => p + c.matches.length, 0),
424+
this._findMatches.reduce((p, c) => p + c.length, 0),
389425
undefined
390426
);
391427
}
392428

393429
private _matchesCountBeforeIndex(findMatches: CellFindMatchWithIndex[], index: number) {
394430
let prevMatchesCount = 0;
395431
for (let i = 0; i < index; i++) {
396-
prevMatchesCount += findMatches[i].matches.length;
432+
prevMatchesCount += findMatches[i].length;
397433
}
398434

399435
return prevMatchesCount;
@@ -403,7 +439,7 @@ export class FindModel extends Disposable {
403439
if (this._findMatches && this._findMatches.length) {
404440
const values = new Uint32Array(this._findMatches.length);
405441
for (let i = 0; i < this._findMatches.length; i++) {
406-
values[i] = this._findMatches[i].matches.length;
442+
values[i] = this._findMatches[i].length;
407443
}
408444

409445
this._findMatchesStarts = new PrefixSumComputer(values);
@@ -415,10 +451,10 @@ export class FindModel extends Disposable {
415451
private async highlightCurrentFindMatchDecoration(cellIndex: number, matchIndex: number): Promise<number | null> {
416452
const cell = this._findMatches[cellIndex].cell;
417453

418-
if (matchIndex < this._findMatches[cellIndex].modelMatchCount) {
454+
if (matchIndex < this._findMatches[cellIndex].contentMatches.length) {
419455
this.clearCurrentFindMatchDecoration();
420456

421-
const match = this._findMatches[cellIndex].matches[matchIndex] as FindMatch;
457+
const match = this._findMatches[cellIndex].getMatch(matchIndex) as FindMatch;
422458
// match is an editor FindMatch, we update find match decoration in the editor
423459
// we will highlight the match in the webview
424460
this._notebookEditor.changeModelDecorations(accessor => {
@@ -454,7 +490,7 @@ export class FindModel extends Disposable {
454490
} else {
455491
this.clearCurrentFindMatchDecoration();
456492

457-
const match = this._findMatches[cellIndex].matches[matchIndex] as OutputFindMatch;
493+
const match = this._findMatches[cellIndex].getMatch(matchIndex) as CellWebviewFindMatch;
458494
const offset = await this._notebookEditor.highlightFind(cell, match.index);
459495
this._currentMatchDecorations = { kind: 'output', index: match.index };
460496

@@ -487,19 +523,17 @@ export class FindModel extends Disposable {
487523
this._currentMatchCellDecorations = this._notebookEditor.deltaCellDecorations(this._currentMatchCellDecorations, []);
488524
}
489525

490-
private setAllFindMatchesDecorations(cellFindMatches: CellFindMatch[]) {
526+
private setAllFindMatchesDecorations(cellFindMatches: CellFindMatchWithIndex[]) {
491527
this._notebookEditor.changeModelDecorations((accessor) => {
492528

493529
const findMatchesOptions: ModelDecorationOptions = FindDecorations._FIND_MATCH_DECORATION;
494530

495531
const deltaDecorations: ICellModelDeltaDecorations[] = cellFindMatches.map(cellFindMatch => {
496-
const findMatches = cellFindMatch.matches;
497-
498532
// Find matches
499-
const newFindMatchesDecorations: IModelDeltaDecoration[] = new Array<IModelDeltaDecoration>(findMatches.length);
500-
for (let i = 0, len = Math.min(findMatches.length, cellFindMatch.modelMatchCount); i < len; i++) {
533+
const newFindMatchesDecorations: IModelDeltaDecoration[] = new Array<IModelDeltaDecoration>(cellFindMatch.length);
534+
for (let i = 0; i < cellFindMatch.contentMatches.length; i++) {
501535
newFindMatchesDecorations[i] = {
502-
range: (findMatches[i] as FindMatch).range,
536+
range: cellFindMatch.contentMatches[i].range,
503537
options: findMatchesOptions
504538
};
505539
}
@@ -517,8 +551,8 @@ export class FindModel extends Disposable {
517551
options: {
518552
overviewRuler: {
519553
color: overviewRulerFindMatchForeground,
520-
modelRanges: cellFindMatch.matches.slice(0, cellFindMatch.modelMatchCount).map(match => (match as FindMatch).range),
521-
includeOutput: cellFindMatch.modelMatchCount < cellFindMatch.matches.length
554+
modelRanges: cellFindMatch.contentMatches.map(match => match.range),
555+
includeOutput: cellFindMatch.webviewMatches.length > 0
522556
}
523557
}
524558
};

src/vs/workbench/contrib/notebook/browser/contrib/find/notebookFindWidget.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ class NotebookFindWidget extends SimpleFindReplaceWidget implements INotebookEdi
109109
}
110110

111111
const matches = this._findModel.findMatches;
112-
this._replaceAllBtn.setEnabled(matches.length > 0 && matches.find(match => match.modelMatchCount < match.matches.length) === undefined);
112+
this._replaceAllBtn.setEnabled(matches.length > 0 && matches.find(match => match.webviewMatches.length > 0) === undefined);
113113

114114
if (e.filters) {
115115
this._findInput.updateFilterState((this._state.filters?.markupPreview ?? false) || (this._state.filters?.codeOutput ?? false));
@@ -200,13 +200,9 @@ class NotebookFindWidget extends SimpleFindReplaceWidget implements INotebookEdi
200200
const cellFindMatches = this._findModel.findMatches;
201201
const replaceStrings: string[] = [];
202202
cellFindMatches.forEach(cellFindMatch => {
203-
const findMatches = cellFindMatch.matches;
204-
findMatches.forEach((findMatch, index) => {
205-
if (index < cellFindMatch.modelMatchCount) {
206-
const match = findMatch as FindMatch;
207-
const matches = match.matches;
208-
replaceStrings.push(replacePattern.buildReplaceString(matches, this._state.preserveCase));
209-
}
203+
cellFindMatch.contentMatches.forEach(match => {
204+
const matches = match.matches;
205+
replaceStrings.push(replacePattern.buildReplaceString(matches, this._state.preserveCase));
210206
});
211207
});
212208

src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,7 @@ export interface INotebookViewModel {
397397
deltaCellStatusBarItems(oldItems: string[], newItems: INotebookDeltaCellStatusBarItems[]): string[];
398398
getFoldedLength(index: number): number;
399399
replaceOne(cell: ICellViewModel, range: Range, text: string): Promise<void>;
400-
replaceAll(matches: CellFindMatch[], texts: string[]): Promise<void>;
400+
replaceAll(matches: CellFindMatchWithIndex[], texts: string[]): Promise<void>;
401401
}
402402
//#endregion
403403

@@ -701,21 +701,24 @@ export interface IActiveNotebookEditorDelegate extends INotebookEditorDelegate {
701701
getNextVisibleCellIndex(index: number): number;
702702
}
703703

704-
export interface OutputFindMatch {
704+
export interface CellWebviewFindMatch {
705705
readonly index: number;
706706
}
707707

708+
export type CellContentFindMatch = FindMatch;
709+
708710
export interface CellFindMatch {
709711
cell: ICellViewModel;
710-
matches: (FindMatch | OutputFindMatch)[];
711-
modelMatchCount: number;
712+
contentMatches: CellContentFindMatch[];
712713
}
713714

714715
export interface CellFindMatchWithIndex {
715716
cell: ICellViewModel;
716717
index: number;
717-
matches: (FindMatch | OutputFindMatch)[];
718-
modelMatchCount: number;
718+
length: number;
719+
getMatch(index: number): FindMatch | CellWebviewFindMatch;
720+
contentMatches: FindMatch[];
721+
webviewMatches: CellWebviewFindMatch[];
719722
}
720723

721724
export enum CellEditState {

src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ import { BaseCellEditorOptions } from 'vs/workbench/contrib/notebook/browser/vie
8484
import { ILogService } from 'vs/platform/log/common/log';
8585
import { FloatingClickMenu } from 'vs/workbench/browser/codeeditor';
8686
import { IDimension } from 'vs/editor/common/core/dimension';
87+
import { CellFindMatchModel } from 'vs/workbench/contrib/notebook/browser/contrib/find/findModel';
8788

8889
const $ = DOM.$;
8990

@@ -2395,7 +2396,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD
23952396
return [];
23962397
}
23972398

2398-
const findMatches = this._notebookViewModel.find(query, options).filter(match => match.matches.length > 0);
2399+
const findMatches = this._notebookViewModel.find(query, options).filter(match => match.length > 0);
23992400

24002401
if (!options.includeMarkupPreview && !options.includeOutput) {
24012402
this._webview?.findStop();
@@ -2436,27 +2437,23 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD
24362437
const exisitingMatch = matchMap[match.cellId];
24372438

24382439
if (exisitingMatch) {
2439-
exisitingMatch.matches.push(match);
2440+
exisitingMatch.webviewMatches.push(match);
24402441
} else {
2441-
matchMap[match.cellId] = {
2442-
cell: this._notebookViewModel!.viewCells.find(cell => cell.id === match.cellId)! as CellViewModel,
2443-
index: this._notebookViewModel!.viewCells.findIndex(cell => cell.id === match.cellId)!,
2444-
matches: [match],
2445-
modelMatchCount: 0
2446-
};
2442+
2443+
matchMap[match.cellId] = new CellFindMatchModel(
2444+
this._notebookViewModel!.viewCells.find(cell => cell.id === match.cellId)!,
2445+
this._notebookViewModel!.viewCells.findIndex(cell => cell.id === match.cellId)!,
2446+
[],
2447+
[match]
2448+
);
24472449
}
24482450
});
24492451
}
24502452

24512453
const ret: CellFindMatchWithIndex[] = [];
24522454
this._notebookViewModel.viewCells.forEach((cell, index) => {
24532455
if (matchMap[cell.id]) {
2454-
ret.push({
2455-
cell: cell as CellViewModel,
2456-
index: index,
2457-
matches: matchMap[cell.id].matches,
2458-
modelMatchCount: matchMap[cell.id].modelMatchCount
2459-
});
2456+
ret.push(new CellFindMatchModel(cell, index, matchMap[cell.id].contentMatches, matchMap[cell.id].webviewMatches));
24602457
}
24612458
});
24622459

0 commit comments

Comments
 (0)