@xterm/addon-search 0.17.0-beta.21 → 0.17.0-beta.211

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xterm/addon-search",
3
- "version": "0.17.0-beta.21",
3
+ "version": "0.17.0-beta.211",
4
4
  "author": {
5
5
  "name": "The xterm.js authors",
6
6
  "url": "https://xtermjs.org/"
@@ -16,13 +16,13 @@
16
16
  "xterm.js"
17
17
  ],
18
18
  "scripts": {
19
- "prepackage": "../../node_modules/.bin/tsc -p .",
19
+ "prepackage": "../../node_modules/.bin/tsgo -p .",
20
20
  "package": "../../node_modules/.bin/webpack",
21
21
  "prepublishOnly": "npm run package",
22
22
  "start": "node ../../demo/start"
23
23
  },
24
- "commit": "edf100a24ba540665083b24e2edcf4c3958deca3",
24
+ "commit": "605a7c6e3020b23155ad0544c3e56e88dd295c20",
25
25
  "peerDependencies": {
26
- "@xterm/xterm": "^6.1.0-beta.21"
26
+ "@xterm/xterm": "^6.1.0-beta.211"
27
27
  }
28
28
  }
@@ -5,7 +5,7 @@
5
5
 
6
6
  import type { Terminal, IDisposable, IDecoration } from '@xterm/xterm';
7
7
  import type { ISearchDecorationOptions } from '@xterm/addon-search';
8
- import { dispose, Disposable, toDisposable } from 'vs/base/common/lifecycle';
8
+ import { dispose, Disposable, toDisposable } from 'common/Lifecycle';
9
9
  import type { ISearchResult } from './SearchEngine';
10
10
 
11
11
  /**
@@ -135,6 +135,7 @@ export class DecorationManager extends Disposable {
135
135
  marker,
136
136
  x: range[1],
137
137
  width: range[2],
138
+ layer: isActiveResult ? 'top' : 'bottom',
138
139
  backgroundColor: isActiveResult ? options.activeMatchBackground : options.matchBackground,
139
140
  overviewRulerOptions: this._highlightedLines.has(marker.line) ? undefined : {
140
141
  color: isActiveResult ? options.activeMatchColorOverviewRuler : options.matchOverviewRuler,
@@ -4,10 +4,10 @@
4
4
  */
5
5
 
6
6
  import type { Terminal, IDisposable, ITerminalAddon } from '@xterm/xterm';
7
- import type { SearchAddon as ISearchApi, ISearchOptions, ISearchAddonOptions, ISearchResultChangeEvent } from '@xterm/addon-search';
8
- import { Event } from 'vs/base/common/event';
9
- import { Disposable, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle';
10
- import { disposableTimeout } from 'vs/base/common/async';
7
+ import type { SearchAddon as ISearchApi, ISearchOptions, ISearchAddonOptions, ISearchResultChangeEvent, ISearchDecorationOptions } from '@xterm/addon-search';
8
+ import { Emitter, type IEvent } from 'common/Event';
9
+ import { Disposable, MutableDisposable, toDisposable } from 'common/Lifecycle';
10
+ import { disposableTimeout } from 'common/Async';
11
11
  import { SearchLineCache } from './SearchLineCache';
12
12
  import { SearchState } from './SearchState';
13
13
  import { SearchEngine, type ISearchResult } from './SearchEngine';
@@ -42,7 +42,12 @@ export class SearchAddon extends Disposable implements ITerminalAddon, ISearchAp
42
42
  private _decorationManager: DecorationManager | undefined;
43
43
  private _resultTracker = this._register(new SearchResultTracker());
44
44
 
45
- public get onDidChangeResults(): Event<ISearchResultChangeEvent> {
45
+ private readonly _onAfterSearch = this._register(new Emitter<void>());
46
+ public readonly onAfterSearch = this._onAfterSearch.event;
47
+ private readonly _onBeforeSearch = this._register(new Emitter<void>());
48
+ public readonly onBeforeSearch = this._onBeforeSearch.event;
49
+
50
+ public get onDidChangeResults(): IEvent<ISearchResultChangeEvent> {
46
51
  return this._resultTracker.onDidChangeResults;
47
52
  }
48
53
 
@@ -98,6 +103,8 @@ export class SearchAddon extends Disposable implements ITerminalAddon, ISearchAp
98
103
  throw new Error('Cannot use addon until it has been loaded');
99
104
  }
100
105
 
106
+ this._onBeforeSearch.fire();
107
+
101
108
  this._state.lastSearchOptions = searchOptions;
102
109
 
103
110
  if (this._state.shouldUpdateHighlighting(term, searchOptions)) {
@@ -108,6 +115,8 @@ export class SearchAddon extends Disposable implements ITerminalAddon, ISearchAp
108
115
  this._fireResults(searchOptions);
109
116
  this._state.cachedSearchTerm = term;
110
117
 
118
+ this._onAfterSearch.fire();
119
+
111
120
  return found;
112
121
  }
113
122
 
@@ -173,6 +182,8 @@ export class SearchAddon extends Disposable implements ITerminalAddon, ISearchAp
173
182
  throw new Error('Cannot use addon until it has been loaded');
174
183
  }
175
184
 
185
+ this._onBeforeSearch.fire();
186
+
176
187
  this._state.lastSearchOptions = searchOptions;
177
188
 
178
189
  if (this._state.shouldUpdateHighlighting(term, searchOptions)) {
@@ -183,6 +194,8 @@ export class SearchAddon extends Disposable implements ITerminalAddon, ISearchAp
183
194
  this._fireResults(searchOptions);
184
195
  this._state.cachedSearchTerm = term;
185
196
 
197
+ this._onAfterSearch.fire();
198
+
186
199
  return found;
187
200
  }
188
201
 
@@ -209,7 +222,7 @@ export class SearchAddon extends Disposable implements ITerminalAddon, ISearchAp
209
222
  * @param result The result to select.
210
223
  * @returns Whether a result was selected.
211
224
  */
212
- private _selectResult(result: ISearchResult | undefined, options?: any, noScroll?: boolean): boolean {
225
+ private _selectResult(result: ISearchResult | undefined, options?: ISearchDecorationOptions, noScroll?: boolean): boolean {
213
226
  if (!this._terminal || !this._decorationManager) {
214
227
  return false;
215
228
  }
@@ -198,9 +198,7 @@ export class SearchEngine {
198
198
  }
199
199
  }
200
200
 
201
- if (!result) {
202
- result = this._findInLine(term, searchPosition, searchOptions, isReverseSearch);
203
- }
201
+ result ??= this._findInLine(term, searchPosition, searchOptions, isReverseSearch);
204
202
 
205
203
  // Search from startRow - 1 to top
206
204
  if (!result) {
@@ -4,8 +4,8 @@
4
4
  */
5
5
 
6
6
  import type { Terminal } from '@xterm/xterm';
7
- import { combinedDisposable, Disposable, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle';
8
- import { disposableTimeout } from 'vs/base/common/async';
7
+ import { combinedDisposable, Disposable, MutableDisposable, toDisposable } from 'common/Lifecycle';
8
+ import { disposableTimeout } from 'common/Async';
9
9
 
10
10
  export type LineCacheEntry = [
11
11
  /**
@@ -38,6 +38,9 @@ export class SearchLineCache extends Disposable {
38
38
  private _linesCache: LineCacheEntry[] | undefined;
39
39
  private _linesCacheTimeout = this._register(new MutableDisposable());
40
40
  private _linesCacheDisposables = this._register(new MutableDisposable());
41
+ // Track access to avoid recreating a timeout on every init call which occurs once per search
42
+ // result (findNext/findPrevious -> _highlightAllMatches -> find loop).
43
+ private _lastAccessTimestamp = 0;
41
44
 
42
45
  constructor(private readonly _terminal: Terminal) {
43
46
  super();
@@ -57,15 +60,34 @@ export class SearchLineCache extends Disposable {
57
60
  );
58
61
  }
59
62
 
60
- this._linesCacheTimeout.value = disposableTimeout(() => this._destroyLinesCache(), Constants.LINES_CACHE_TIME_TO_LIVE);
63
+ this._lastAccessTimestamp = Date.now();
64
+ if (!this._linesCacheTimeout.value) {
65
+ this._scheduleLinesCacheTimeout(Constants.LINES_CACHE_TIME_TO_LIVE);
66
+ }
61
67
  }
62
68
 
63
69
  private _destroyLinesCache(): void {
64
70
  this._linesCache = undefined;
71
+ this._lastAccessTimestamp = 0;
65
72
  this._linesCacheDisposables.clear();
66
73
  this._linesCacheTimeout.clear();
67
74
  }
68
75
 
76
+ private _scheduleLinesCacheTimeout(delay: number): void {
77
+ this._linesCacheTimeout.value = disposableTimeout(() => {
78
+ if (!this._linesCache) {
79
+ return;
80
+ }
81
+ const now = Date.now();
82
+ const elapsed = now - this._lastAccessTimestamp;
83
+ if (elapsed >= Constants.LINES_CACHE_TIME_TO_LIVE) {
84
+ this._destroyLinesCache();
85
+ return;
86
+ }
87
+ this._scheduleLinesCacheTimeout(Constants.LINES_CACHE_TIME_TO_LIVE - elapsed);
88
+ }, delay);
89
+ }
90
+
69
91
  public getLineFromCache(row: number): LineCacheEntry | undefined {
70
92
  return this._linesCache?.[row];
71
93
  }
@@ -5,8 +5,8 @@
5
5
 
6
6
  import type { ISearchResultChangeEvent } from '@xterm/addon-search';
7
7
  import type { IDisposable } from '@xterm/xterm';
8
- import { Emitter, Event } from 'vs/base/common/event';
9
- import { Disposable } from 'vs/base/common/lifecycle';
8
+ import { Emitter, type IEvent } from 'common/Event';
9
+ import { Disposable } from 'common/Lifecycle';
10
10
  import type { ISearchResult } from './SearchEngine';
11
11
 
12
12
  /**
@@ -25,7 +25,7 @@ export class SearchResultTracker extends Disposable {
25
25
  private _selectedDecoration: ISelectedDecoration | undefined;
26
26
 
27
27
  private readonly _onDidChangeResults = this._register(new Emitter<ISearchResultChangeEvent>());
28
- public get onDidChangeResults(): Event<ISearchResultChangeEvent> { return this._onDidChangeResults.event; }
28
+ public get onDidChangeResults(): IEvent<ISearchResultChangeEvent> { return this._onDidChangeResults.event; }
29
29
 
30
30
  /**
31
31
  * Gets the current search results.
@@ -152,8 +152,17 @@ declare module '@xterm/addon-search' {
152
152
  public clearActiveDecoration(): void;
153
153
 
154
154
  /**
155
- * When decorations are enabled, fires when
156
- * the search results change.
155
+ * Fires after a search is performed.
156
+ */
157
+ readonly onAfterSearch: IEvent<void>;
158
+
159
+ /**
160
+ * Fires before a search is performed.
161
+ */
162
+ readonly onBeforeSearch: IEvent<void>;
163
+
164
+ /**
165
+ * When decorations are enabled, fires when the search results change.
157
166
  */
158
167
  readonly onDidChangeResults: IEvent<ISearchResultChangeEvent>;
159
168
  }