@xterm/addon-search 0.16.0-beta.124 → 0.16.0-beta.126

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.16.0-beta.124",
3
+ "version": "0.16.0-beta.126",
4
4
  "author": {
5
5
  "name": "The xterm.js authors",
6
6
  "url": "https://xtermjs.org/"
@@ -22,7 +22,7 @@
22
22
  "start": "node ../../demo/start"
23
23
  },
24
24
  "peerDependencies": {
25
- "@xterm/xterm": "^5.6.0-beta.124"
25
+ "@xterm/xterm": "^5.6.0-beta.126"
26
26
  },
27
- "commit": "02b3704af0b1823ccb4ebb6c5fa4059a7934dbd8"
27
+ "commit": "b12a9393f1cbb994877404ae0ebf62d6250f83ba"
28
28
  }
@@ -6,7 +6,9 @@
6
6
  import type { Terminal, IDisposable, ITerminalAddon, IDecoration } from '@xterm/xterm';
7
7
  import type { SearchAddon as ISearchApi, ISearchOptions, ISearchDecorationOptions } from '@xterm/addon-search';
8
8
  import { Emitter, Event } from 'vs/base/common/event';
9
- import { combinedDisposable, Disposable, dispose, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle';
9
+ import { Disposable, dispose, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle';
10
+ import { disposableTimeout } from 'vs/base/common/async';
11
+ import { SearchLineCache } from './SearchLineCache';
10
12
 
11
13
  interface IInternalSearchOptions {
12
14
  noScroll?: boolean;
@@ -33,17 +35,6 @@ export interface ISearchResult {
33
35
  size: number;
34
36
  }
35
37
 
36
- type LineCacheEntry = [
37
- /**
38
- * The string representation of a line (as opposed to the buffer cell representation).
39
- */
40
- lineAsString: string,
41
- /**
42
- * The offsets where each line starts when the entry describes a wrapped line.
43
- */
44
- lineOffsets: number[]
45
- ];
46
-
47
38
  interface IHighlight extends IDisposable {
48
39
  decoration: IDecoration;
49
40
  match: ISearchResult;
@@ -65,12 +56,6 @@ const enum Constants {
65
56
  */
66
57
  NON_WORD_CHARACTERS = ' ~!@#$%^&*()+`-=[]{}|\\;:"\',./<>?',
67
58
 
68
- /**
69
- * Time-to-live for cached search results in milliseconds. After this duration, cached search
70
- * results will be invalidated to ensure they remain consistent with terminal content changes.
71
- */
72
- LINES_CACHE_TIME_TO_LIVE = 15000,
73
-
74
59
  /**
75
60
  * Default maximum number of search results to highlight simultaneously. This limit prevents
76
61
  * performance degradation when searching for very common terms that would result in excessive
@@ -85,18 +70,11 @@ export class SearchAddon extends Disposable implements ITerminalAddon, ISearchAp
85
70
  private _highlightedLines: Set<number> = new Set();
86
71
  private _highlightDecorations: IHighlight[] = [];
87
72
  private _searchResultsWithHighlight: ISearchResult[] = [];
88
- private _selectedDecoration: MutableDisposable<IMultiHighlight> = this._register(new MutableDisposable());
73
+ private _selectedDecoration = this._register(new MutableDisposable<IMultiHighlight>());
89
74
  private _highlightLimit: number;
90
75
  private _lastSearchOptions: ISearchOptions | undefined;
91
- private _highlightTimeout: number | undefined;
92
- /**
93
- * translateBufferLineToStringWithWrap is a fairly expensive call.
94
- * We memoize the calls into an array that has a time based ttl.
95
- * _linesCache is also invalidated when the terminal cursor moves.
96
- */
97
- private _linesCache: LineCacheEntry[] | undefined;
98
- private _linesCacheTimeoutId = 0;
99
- private _linesCacheDisposables = new MutableDisposable();
76
+ private _highlightTimeout = this._register(new MutableDisposable<IDisposable>());
77
+ private _lineCache = this._register(new MutableDisposable<SearchLineCache>());
100
78
 
101
79
  private readonly _onDidChangeResults = this._register(new Emitter<ISearchResultChangeEvent>());
102
80
  public get onDidChangeResults(): Event<ISearchResultChangeEvent> { return this._onDidChangeResults.event; }
@@ -109,17 +87,16 @@ export class SearchAddon extends Disposable implements ITerminalAddon, ISearchAp
109
87
 
110
88
  public activate(terminal: Terminal): void {
111
89
  this._terminal = terminal;
90
+ this._lineCache.value = new SearchLineCache(terminal);
112
91
  this._register(this._terminal.onWriteParsed(() => this._updateMatches()));
113
92
  this._register(this._terminal.onResize(() => this._updateMatches()));
114
93
  this._register(toDisposable(() => this.clearDecorations()));
115
94
  }
116
95
 
117
96
  private _updateMatches(): void {
118
- if (this._highlightTimeout) {
119
- window.clearTimeout(this._highlightTimeout);
120
- }
97
+ this._highlightTimeout.clear();
121
98
  if (this._cachedSearchTerm && this._lastSearchOptions?.decorations) {
122
- this._highlightTimeout = setTimeout(() => {
99
+ this._highlightTimeout.value = disposableTimeout(() => {
123
100
  const term = this._cachedSearchTerm;
124
101
  this._cachedSearchTerm = undefined;
125
102
  this.findPrevious(term!, { ...this._lastSearchOptions, incremental: true }, { noScroll: true });
@@ -223,7 +200,7 @@ export class SearchAddon extends Disposable implements ITerminalAddon, ISearchAp
223
200
 
224
201
  let result: ISearchResult | undefined = undefined;
225
202
 
226
- this._initLinesCache();
203
+ this._lineCache.value!.initLinesCache();
227
204
 
228
205
  const searchPosition: ISearchPosition = {
229
206
  startRow,
@@ -271,7 +248,7 @@ export class SearchAddon extends Disposable implements ITerminalAddon, ISearchAp
271
248
  }
272
249
  }
273
250
 
274
- this._initLinesCache();
251
+ this._lineCache.value!.initLinesCache();
275
252
 
276
253
  const searchPosition: ISearchPosition = {
277
254
  startRow,
@@ -392,7 +369,7 @@ export class SearchAddon extends Disposable implements ITerminalAddon, ISearchAp
392
369
  let startCol = this._terminal.cols;
393
370
  const isReverseSearch = true;
394
371
 
395
- this._initLinesCache();
372
+ this._lineCache.value!.initLinesCache();
396
373
  const searchPosition: ISearchPosition = {
397
374
  startRow,
398
375
  startCol
@@ -443,32 +420,7 @@ export class SearchAddon extends Disposable implements ITerminalAddon, ISearchAp
443
420
  return this._selectResult(result, searchOptions?.decorations, internalSearchOptions?.noScroll);
444
421
  }
445
422
 
446
- /**
447
- * Sets up a line cache with a ttl
448
- */
449
- private _initLinesCache(): void {
450
- const terminal = this._terminal!;
451
- if (!this._linesCache) {
452
- this._linesCache = new Array(terminal.buffer.active.length);
453
- this._linesCacheDisposables.value = combinedDisposable(
454
- terminal.onLineFeed(() => this._destroyLinesCache()),
455
- terminal.onCursorMove(() => this._destroyLinesCache()),
456
- terminal.onResize(() => this._destroyLinesCache())
457
- );
458
- }
459
-
460
- window.clearTimeout(this._linesCacheTimeoutId);
461
- this._linesCacheTimeoutId = window.setTimeout(() => this._destroyLinesCache(), Constants.LINES_CACHE_TIME_TO_LIVE);
462
- }
463
423
 
464
- private _destroyLinesCache(): void {
465
- this._linesCache = undefined;
466
- this._linesCacheDisposables.clear();
467
- if (this._linesCacheTimeoutId) {
468
- window.clearTimeout(this._linesCacheTimeoutId);
469
- this._linesCacheTimeoutId = 0;
470
- }
471
- }
472
424
 
473
425
  /**
474
426
  * A found substring is a whole word if it doesn't have an alphanumeric character directly
@@ -513,12 +465,10 @@ export class SearchAddon extends Disposable implements ITerminalAddon, ISearchAp
513
465
  searchPosition.startCol += terminal.cols;
514
466
  return this._findInLine(term, searchPosition, searchOptions);
515
467
  }
516
- let cache = this._linesCache?.[row];
468
+ let cache = this._lineCache.value!.getLineFromCache(row);
517
469
  if (!cache) {
518
- cache = this._translateBufferLineToStringWithWrap(row, true);
519
- if (this._linesCache) {
520
- this._linesCache[row] = cache;
521
- }
470
+ cache = this._lineCache.value!.translateBufferLineToStringWithWrap(row, true);
471
+ this._lineCache.value!.setLineInCache(row, cache);
522
472
  }
523
473
  const [stringLine, offsets] = cache;
524
474
 
@@ -639,42 +589,7 @@ export class SearchAddon extends Disposable implements ITerminalAddon, ISearchAp
639
589
  return offset;
640
590
  }
641
591
 
642
- /**
643
- * Translates a buffer line to a string, including subsequent lines if they are wraps.
644
- * Wide characters will count as two columns in the resulting string. This
645
- * function is useful for getting the actual text underneath the raw selection
646
- * position.
647
- * @param lineIndex The index of the line being translated.
648
- * @param trimRight Whether to trim whitespace to the right.
649
- */
650
- private _translateBufferLineToStringWithWrap(lineIndex: number, trimRight: boolean): LineCacheEntry {
651
- const terminal = this._terminal!;
652
- const strings = [];
653
- const lineOffsets = [0];
654
- let line = terminal.buffer.active.getLine(lineIndex);
655
- while (line) {
656
- const nextLine = terminal.buffer.active.getLine(lineIndex + 1);
657
- const lineWrapsToNext = nextLine ? nextLine.isWrapped : false;
658
- let string = line.translateToString(!lineWrapsToNext && trimRight);
659
- if (lineWrapsToNext && nextLine) {
660
- const lastCell = line.getCell(line.length - 1);
661
- const lastCellIsNull = lastCell && lastCell.getCode() === 0 && lastCell.getWidth() === 1;
662
- // a wide character wrapped to the next line
663
- if (lastCellIsNull && nextLine.getCell(0)?.getWidth() === 2) {
664
- string = string.slice(0, -1);
665
- }
666
- }
667
- strings.push(string);
668
- if (lineWrapsToNext) {
669
- lineOffsets.push(lineOffsets[lineOffsets.length - 1] + string.length);
670
- } else {
671
- break;
672
- }
673
- lineIndex++;
674
- line = nextLine;
675
- }
676
- return [strings.join(''), lineOffsets];
677
- }
592
+
678
593
 
679
594
  /**
680
595
  * Selects and scrolls to a result.
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Copyright (c) 2017 The xterm.js authors. All rights reserved.
3
+ * @license MIT
4
+ */
5
+
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';
9
+
10
+ export type LineCacheEntry = [
11
+ /**
12
+ * The string representation of a line (as opposed to the buffer cell representation).
13
+ */
14
+ lineAsString: string,
15
+ /**
16
+ * The offsets where each line starts when the entry describes a wrapped line.
17
+ */
18
+ lineOffsets: number[]
19
+ ];
20
+
21
+ /**
22
+ * Configuration constants for the search line cache functionality.
23
+ */
24
+ const enum Constants {
25
+ /**
26
+ * Time-to-live for cached search results in milliseconds. After this duration, cached search
27
+ * results will be invalidated to ensure they remain consistent with terminal content changes.
28
+ */
29
+ LINES_CACHE_TIME_TO_LIVE = 15000
30
+ }
31
+
32
+ export class SearchLineCache extends Disposable {
33
+ /**
34
+ * translateBufferLineToStringWithWrap is a fairly expensive call.
35
+ * We memoize the calls into an array that has a time based ttl.
36
+ * _linesCache is also invalidated when the terminal cursor moves.
37
+ */
38
+ private _linesCache: LineCacheEntry[] | undefined;
39
+ private _linesCacheTimeout = this._register(new MutableDisposable());
40
+ private _linesCacheDisposables = this._register(new MutableDisposable());
41
+
42
+ constructor(private _terminal: Terminal) {
43
+ super();
44
+ this._register(toDisposable(() => this._destroyLinesCache()));
45
+ }
46
+
47
+ /**
48
+ * Sets up a line cache with a ttl
49
+ */
50
+ public initLinesCache(): void {
51
+ if (!this._linesCache) {
52
+ this._linesCache = new Array(this._terminal.buffer.active.length);
53
+ this._linesCacheDisposables.value = combinedDisposable(
54
+ this._terminal.onLineFeed(() => this._destroyLinesCache()),
55
+ this._terminal.onCursorMove(() => this._destroyLinesCache()),
56
+ this._terminal.onResize(() => this._destroyLinesCache())
57
+ );
58
+ }
59
+
60
+ this._linesCacheTimeout.value = disposableTimeout(() => this._destroyLinesCache(), Constants.LINES_CACHE_TIME_TO_LIVE);
61
+ }
62
+
63
+ private _destroyLinesCache(): void {
64
+ this._linesCache = undefined;
65
+ this._linesCacheDisposables.clear();
66
+ this._linesCacheTimeout.clear();
67
+ }
68
+
69
+ public getLineFromCache(row: number): LineCacheEntry | undefined {
70
+ return this._linesCache?.[row];
71
+ }
72
+
73
+ public setLineInCache(row: number, entry: LineCacheEntry): void {
74
+ if (this._linesCache) {
75
+ this._linesCache[row] = entry;
76
+ }
77
+ }
78
+
79
+ /**
80
+ * Translates a buffer line to a string, including subsequent lines if they are wraps.
81
+ * Wide characters will count as two columns in the resulting string. This
82
+ * function is useful for getting the actual text underneath the raw selection
83
+ * position.
84
+ * @param lineIndex The index of the line being translated.
85
+ * @param trimRight Whether to trim whitespace to the right.
86
+ */
87
+ public translateBufferLineToStringWithWrap(lineIndex: number, trimRight: boolean): LineCacheEntry {
88
+ const strings = [];
89
+ const lineOffsets = [0];
90
+ let line = this._terminal.buffer.active.getLine(lineIndex);
91
+ while (line) {
92
+ const nextLine = this._terminal.buffer.active.getLine(lineIndex + 1);
93
+ const lineWrapsToNext = nextLine ? nextLine.isWrapped : false;
94
+ let string = line.translateToString(!lineWrapsToNext && trimRight);
95
+ if (lineWrapsToNext && nextLine) {
96
+ const lastCell = line.getCell(line.length - 1);
97
+ const lastCellIsNull = lastCell && lastCell.getCode() === 0 && lastCell.getWidth() === 1;
98
+ // a wide character wrapped to the next line
99
+ if (lastCellIsNull && nextLine.getCell(0)?.getWidth() === 2) {
100
+ string = string.slice(0, -1);
101
+ }
102
+ }
103
+ strings.push(string);
104
+ if (lineWrapsToNext) {
105
+ lineOffsets.push(lineOffsets[lineOffsets.length - 1] + string.length);
106
+ } else {
107
+ break;
108
+ }
109
+ lineIndex++;
110
+ line = nextLine;
111
+ }
112
+ return [strings.join(''), lineOffsets];
113
+ }
114
+ }