From 3cdbc77386af12e6812171cc3c525b569d076835 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sat, 6 Jun 2026 11:12:04 -0700 Subject: [PATCH] fix(addon-search): advance highlight scan by buffer match size (#5994) * fix(addon-search): advance highlight scan by buffer match size _highlightAllMatches() stepped to the next find() using term.length and col + 1 when staying on the same row. Search results expose size in buffer columns (wide glyphs, wrapped matches), which select() and decorations already use. Advance with col + size and wrap row/col when crossing the terminal width so highlight-all does not skip, duplicate, or stop early on non-ASCII matches. Co-authored-by: Cursor * test(addon-search): regression for highlight-all wide char advance by size Co-authored-by: Daniel Imms * test(addon-search): move highlight-all regression to integration tests Co-authored-by: Daniel Imms --------- Co-authored-by: Cursor Co-authored-by: Daniel Imms --- addons/addon-search/src/SearchAddon.ts | 14 ++++++++------ addons/addon-search/test/SearchAddon.test.ts | 14 ++++++++++++++ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/addons/addon-search/src/SearchAddon.ts b/addons/addon-search/src/SearchAddon.ts index cb4094743..e5fd31cfb 100644 --- a/addons/addon-search/src/SearchAddon.ts +++ b/addons/addon-search/src/SearchAddon.ts @@ -142,12 +142,14 @@ export class SearchAddon extends Disposable implements ITerminalAddon, ISearchAp } prevResult = result; results.push(prevResult); - result = this._engine.find( - term, - prevResult.col + prevResult.term.length >= this._terminal.cols ? prevResult.row + 1 : prevResult.row, - prevResult.col + prevResult.term.length >= this._terminal.cols ? 0 : prevResult.col + 1, - searchOptions - ); + const cols = this._terminal.cols; + let nextCol = prevResult.col + prevResult.size; + let nextRow = prevResult.row; + if (nextCol >= cols) { + nextRow += Math.floor(nextCol / cols); + nextCol = nextCol % cols; + } + result = this._engine.find(term, nextRow, nextCol, searchOptions); } this._resultTracker.updateResults(results, this._highlightLimit); diff --git a/addons/addon-search/test/SearchAddon.test.ts b/addons/addon-search/test/SearchAddon.test.ts index 3438772a8..4a62aca7f 100644 --- a/addons/addon-search/test/SearchAddon.test.ts +++ b/addons/addon-search/test/SearchAddon.test.ts @@ -414,6 +414,20 @@ test.describe('Search Tests', () => { }); test.describe('Regression tests', () => { + test('should advance highlight-all scan by buffer match size for wide characters', async () => { + await ctx.page.evaluate(` + window.calls = []; + window.search.onDidChangeResults(e => window.calls.push(e)); + `); + await ctx.proxy.resize(3, 5); + await ctx.proxy.write('𝄞𝄞𝄞'); + strictEqual(await ctx.page.evaluate(`window.search.findNext('𝄞', { decorations: { activeMatchColorOverviewRuler: '#ff0000', matchOverviewRuler: '#ffff00' } })`), true); + deepStrictEqual(await ctx.page.evaluate('window.calls'), [ + { resultCount: 3, resultIndex: 0 } + ]); + await ctx.proxy.resize(80, 24); + }); + test.describe('#2444 wrapped line content not being found', () => { let fixture: string; test.beforeAll(async () => {