Skip to content

Commit aa3933c

Browse files
CopilotYoyokrazy
andauthored
Fix infinite looping in notebook addFindMatchToSelection (Cmd+D) (#251157)
* Initial plan for issue * Fix infinite looping in notebook addFindMatchToSelection Co-authored-by: Yoyokrazy <12552271+Yoyokrazy@users.noreply.github.com> * Optimize performance by caching total matches count instead of recalculating Co-authored-by: Yoyokrazy <12552271+Yoyokrazy@users.noreply.github.com> * idle state reset --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Yoyokrazy <12552271+Yoyokrazy@users.noreply.github.com> Co-authored-by: Michael Lively <milively@microsoft.com>
1 parent eea8d9e commit aa3933c

File tree

1 file changed

+18
-0
lines changed

1 file changed

+18
-0
lines changed

src/vs/workbench/contrib/notebook/browser/contrib/multicursor/notebookMulticursor.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ export class NotebookMultiCursorController extends Disposable implements INotebo
9696
position: Position;
9797
} | undefined;
9898
private trackedCells: TrackedCell[];
99+
private totalMatchesCount: number;
99100

100101
private readonly _onDidChangeAnchorCell;
101102
readonly onDidChangeAnchorCell: Event<void>;
@@ -125,6 +126,7 @@ export class NotebookMultiCursorController extends Disposable implements INotebo
125126
super();
126127
this.word = '';
127128
this.trackedCells = [];
129+
this.totalMatchesCount = 0;
128130
this._onDidChangeAnchorCell = this._register(new Emitter<void>());
129131
this.onDidChangeAnchorCell = this._onDidChangeAnchorCell.event;
130132
this.anchorDisposables = this._register(new DisposableStore());
@@ -478,6 +480,7 @@ export class NotebookMultiCursorController extends Disposable implements INotebo
478480
this.cursorsDisposables.clear();
479481
this.cursorsControllers.clear();
480482
this.trackedCells = [];
483+
this.totalMatchesCount = 0;
481484
this.startPosition = undefined;
482485
this.word = '';
483486
}
@@ -496,6 +499,13 @@ export class NotebookMultiCursorController extends Disposable implements INotebo
496499
}
497500
this.word = word.word;
498501

502+
// Record the total number of matches at the beginning of the selection process for performance
503+
const notebookTextModel = this.notebookEditor.textModel;
504+
if (notebookTextModel) {
505+
const allMatches = notebookTextModel.findMatches(this.word, false, true, USUAL_WORD_SEPARATORS);
506+
this.totalMatchesCount = allMatches.reduce((sum, cellMatch) => sum + cellMatch.matches.length, 0);
507+
}
508+
499509
const index = this.notebookEditor.getCellIndex(focusedCell);
500510
if (index === undefined) {
501511
return;
@@ -545,6 +555,14 @@ export class NotebookMultiCursorController extends Disposable implements INotebo
545555
return; // should not happen
546556
}
547557

558+
// Check if all matches are already covered by selections to avoid infinite looping
559+
const totalSelections = this.trackedCells.reduce((sum, trackedCell) => sum + trackedCell.matchSelections.length, 0);
560+
561+
if (totalSelections >= this.totalMatchesCount) {
562+
// All matches are already selected, make this a no-op like in regular editors
563+
return;
564+
}
565+
548566
const findResult = notebookTextModel.findNextMatch(
549567
this.word,
550568
{ cellIndex: index, position: focusedCell.getSelections()[focusedCell.getSelections().length - 1].getEndPosition() },

0 commit comments

Comments
 (0)