Skip to content

Commit e969832

Browse files
authored
Merge pull request #5385 from anthonykim1/anthonykim1/fixWrappedTerminalFind
Fix terminal find when wrapped
2 parents 7637a2d + 95a9531 commit e969832

File tree

2 files changed

+59
-7
lines changed

2 files changed

+59
-7
lines changed

addons/addon-search/src/SearchAddon.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ export class SearchAddon extends Disposable implements ITerminalAddon , ISearchA
7272
private _cachedSearchTerm: string | undefined;
7373
private _highlightedLines: Set<number> = new Set();
7474
private _highlightDecorations: IHighlight[] = [];
75+
private _searchResultsWithHighlight: ISearchResult[] = [];
7576
private _selectedDecoration: MutableDisposable<IMultiHighlight> = this._register(new MutableDisposable());
7677
private _highlightLimit: number;
7778
private _lastSearchOptions: ISearchOptions | undefined;
@@ -118,6 +119,7 @@ export class SearchAddon extends Disposable implements ITerminalAddon , ISearchA
118119
this._selectedDecoration.clear();
119120
dispose(this._highlightDecorations);
120121
this._highlightDecorations = [];
122+
this._searchResultsWithHighlight = [];
121123
this._highlightedLines.clear();
122124
if (!retainCachedSearchTerm) {
123125
this._cachedSearchTerm = undefined;
@@ -167,23 +169,22 @@ export class SearchAddon extends Disposable implements ITerminalAddon , ISearchA
167169
// new search, clear out the old decorations
168170
this.clearDecorations(true);
169171

170-
const searchResultsWithHighlight: ISearchResult[] = [];
171172
let prevResult: ISearchResult | undefined = undefined;
172173
let result = this._find(term, 0, 0, searchOptions);
173174
while (result && (prevResult?.row !== result.row || prevResult?.col !== result.col)) {
174-
if (searchResultsWithHighlight.length >= this._highlightLimit) {
175+
if (this._searchResultsWithHighlight.length >= this._highlightLimit) {
175176
break;
176177
}
177178
prevResult = result;
178-
searchResultsWithHighlight.push(prevResult);
179+
this._searchResultsWithHighlight.push(prevResult);
179180
result = this._find(
180181
term,
181182
prevResult.col + prevResult.term.length >= this._terminal.cols ? prevResult.row + 1 : prevResult.row,
182183
prevResult.col + prevResult.term.length >= this._terminal.cols ? 0 : prevResult.col + 1,
183184
searchOptions
184185
);
185186
}
186-
for (const match of searchResultsWithHighlight) {
187+
for (const match of this._searchResultsWithHighlight) {
187188
const decorations = this._createResultDecorations(match, searchOptions.decorations!, false);
188189
if (decorations) {
189190
for (const decoration of decorations) {
@@ -350,15 +351,15 @@ export class SearchAddon extends Disposable implements ITerminalAddon , ISearchA
350351
let resultIndex = -1;
351352
if (this._selectedDecoration.value) {
352353
const selectedMatch = this._selectedDecoration.value.match;
353-
for (let i = 0; i < this._highlightDecorations.length; i++) {
354-
const match = this._highlightDecorations[i].match;
354+
for (let i = 0; i < this._searchResultsWithHighlight.length; i++) {
355+
const match = this._searchResultsWithHighlight[i];
355356
if (match.row === selectedMatch.row && match.col === selectedMatch.col && match.size === selectedMatch.size) {
356357
resultIndex = i;
357358
break;
358359
}
359360
}
360361
}
361-
this._onDidChangeResults.fire({ resultIndex, resultCount: this._highlightDecorations.length });
362+
this._onDidChangeResults.fire({ resultIndex, resultCount: this._searchResultsWithHighlight.length });
362363
}
363364
}
364365

addons/addon-search/test/SearchAddon.test.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,57 @@ test.describe('Search Tests', () => {
480480
]);
481481
});
482482
});
483+
484+
test.describe('Wrapped line search functionality', () => {
485+
test('should correctly count matches across multiple wrapped lines', async () => {
486+
await ctx.page.evaluate(`
487+
window.calls = [];
488+
window.search.onDidChangeResults(e => window.calls.push(e));
489+
`);
490+
491+
const content = 'a'.repeat(300);
492+
await ctx.proxy.write(content);
493+
strictEqual(await ctx.page.evaluate(`window.search.findNext('${content}', { decorations: { activeMatchColorOverviewRuler: '#ff0000', matchOverviewRuler: '#ffff00' } })`), true);
494+
deepStrictEqual(await ctx.page.evaluate('window.calls'), [
495+
{ resultCount: 1, resultIndex: 0 }
496+
]);
497+
});
498+
499+
test('should handle reverse search across wrapped lines', async () => {
500+
await ctx.page.evaluate(`
501+
window.calls = [];
502+
window.search.onDidChangeResults(e => window.calls.push(e));
503+
`);
504+
505+
const content = 'x'.repeat(300);
506+
await ctx.proxy.write(content);
507+
strictEqual(await ctx.page.evaluate(`window.search.findPrevious('${content}', { decorations: { activeMatchColorOverviewRuler: '#ff0000', matchOverviewRuler: '#ffff00' } })`), true);
508+
deepStrictEqual(await ctx.page.evaluate('window.calls'), [
509+
{ resultCount: 1, resultIndex: 0 }
510+
]);
511+
});
512+
513+
test('should update counts when content changes across wrapped lines', async () => {
514+
await ctx.page.evaluate(`
515+
window.calls = [];
516+
window.search.onDidChangeResults(e => window.calls.push(e));
517+
`);
518+
519+
const content = 'z'.repeat(300);
520+
await ctx.proxy.write(content);
521+
strictEqual(await ctx.page.evaluate(`window.search.findNext('${content}', { decorations: { activeMatchColorOverviewRuler: '#ff0000', matchOverviewRuler: '#ffff00' } })`), true);
522+
deepStrictEqual(await ctx.page.evaluate('window.calls'), [
523+
{ resultCount: 1, resultIndex: 0 }
524+
]);
525+
526+
await ctx.proxy.write('\\n\\r' + content);
527+
await timeout(300);
528+
deepStrictEqual(await ctx.page.evaluate('window.calls'), [
529+
{ resultCount: 1, resultIndex: 0 },
530+
{ resultCount: 2, resultIndex: 0 }
531+
]);
532+
});
533+
});
483534
});
484535

485536
function makeData(length: number): string {

0 commit comments

Comments
 (0)