Merge pull request #5519 from Tyriar/5444

Add onBeforeSearch and onAfterSearch APIs
This commit is contained in:
Daniel Imms
2025-12-27 14:38:30 -08:00
committed by GitHub
3 changed files with 53 additions and 3 deletions
+14 -1
View File
@@ -5,7 +5,7 @@
import type { Terminal, IDisposable, ITerminalAddon } from '@xterm/xterm';
import type { SearchAddon as ISearchApi, ISearchOptions, ISearchAddonOptions, ISearchResultChangeEvent } from '@xterm/addon-search';
import { Event } from 'vs/base/common/event';
import { Emitter, Event } from 'vs/base/common/event';
import { Disposable, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { disposableTimeout } from 'vs/base/common/async';
import { SearchLineCache } from './SearchLineCache';
@@ -42,6 +42,11 @@ export class SearchAddon extends Disposable implements ITerminalAddon, ISearchAp
private _decorationManager: DecorationManager | undefined;
private _resultTracker = this._register(new SearchResultTracker());
private readonly _onAfterSearch = this._register(new Emitter<void>());
public readonly onAfterSearch = this._onAfterSearch.event;
private readonly _onBeforeSearch = this._register(new Emitter<void>());
public readonly onBeforeSearch = this._onBeforeSearch.event;
public get onDidChangeResults(): Event<ISearchResultChangeEvent> {
return this._resultTracker.onDidChangeResults;
}
@@ -98,6 +103,8 @@ export class SearchAddon extends Disposable implements ITerminalAddon, ISearchAp
throw new Error('Cannot use addon until it has been loaded');
}
this._onBeforeSearch.fire();
this._state.lastSearchOptions = searchOptions;
if (this._state.shouldUpdateHighlighting(term, searchOptions)) {
@@ -108,6 +115,8 @@ export class SearchAddon extends Disposable implements ITerminalAddon, ISearchAp
this._fireResults(searchOptions);
this._state.cachedSearchTerm = term;
this._onAfterSearch.fire();
return found;
}
@@ -173,6 +182,8 @@ export class SearchAddon extends Disposable implements ITerminalAddon, ISearchAp
throw new Error('Cannot use addon until it has been loaded');
}
this._onBeforeSearch.fire();
this._state.lastSearchOptions = searchOptions;
if (this._state.shouldUpdateHighlighting(term, searchOptions)) {
@@ -183,6 +194,8 @@ export class SearchAddon extends Disposable implements ITerminalAddon, ISearchAp
this._fireResults(searchOptions);
this._state.cachedSearchTerm = term;
this._onAfterSearch.fire();
return found;
}
@@ -385,6 +385,34 @@ test.describe('Search Tests', () => {
});
});
test.describe('onBeforeSearch and onAfterSearch', () => {
test.beforeEach(async () => {
await ctx.page.evaluate(`
window.events = [];
window.search.onBeforeSearch(() => window.events.push('before'));
window.search.onAfterSearch(() => window.events.push('after'));
`);
});
test('should fire before and after findNext', async () => {
await ctx.proxy.write('abc');
await ctx.page.evaluate(`window.search.findNext('a')`);
deepStrictEqual(await ctx.page.evaluate('window.events'), ['before', 'after']);
});
test('should fire before and after findPrevious', async () => {
await ctx.proxy.write('abc');
await ctx.page.evaluate(`window.search.findPrevious('a')`);
deepStrictEqual(await ctx.page.evaluate('window.events'), ['before', 'after']);
});
test('should fire for each search call', async () => {
await ctx.proxy.write('abc abc');
await ctx.page.evaluate(`window.search.findNext('abc')`);
await ctx.page.evaluate(`window.search.findNext('abc')`);
deepStrictEqual(await ctx.page.evaluate('window.events'), ['before', 'after', 'before', 'after']);
});
});
test.describe('Regression tests', () => {
test.describe('#2444 wrapped line content not being found', () => {
let fixture: string;
+11 -2
View File
@@ -152,8 +152,17 @@ declare module '@xterm/addon-search' {
public clearActiveDecoration(): void;
/**
* When decorations are enabled, fires when
* the search results change.
* Fires after a search is performed.
*/
readonly onAfterSearch: IEvent<void>;
/**
* Fires before a search is performed.
*/
readonly onBeforeSearch: IEvent<void>;
/**
* When decorations are enabled, fires when the search results change.
*/
readonly onDidChangeResults: IEvent<ISearchResultChangeEvent>;
}