@xterm/addon-search 0.16.0-beta.98 → 0.16.0

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.98",
3
+ "version": "0.16.0",
4
4
  "author": {
5
5
  "name": "The xterm.js authors",
6
6
  "url": "https://xtermjs.org/"
@@ -21,8 +21,5 @@
21
21
  "prepublishOnly": "npm run package",
22
22
  "start": "node ../../demo/start"
23
23
  },
24
- "peerDependencies": {
25
- "@xterm/xterm": "^5.6.0-beta.98"
26
- },
27
- "commit": "2042bb85023714e55c0c2e986b5000e33b17c414"
24
+ "commit": "f447274f430fd22513f6adbf9862d19524471c04"
28
25
  }
@@ -0,0 +1,157 @@
1
+ /**
2
+ * Copyright (c) 2017 The xterm.js authors. All rights reserved.
3
+ * @license MIT
4
+ */
5
+
6
+ import type { Terminal, IDisposable, IDecoration } from '@xterm/xterm';
7
+ import type { ISearchDecorationOptions } from '@xterm/addon-search';
8
+ import { dispose, Disposable, toDisposable } from 'vs/base/common/lifecycle';
9
+ import type { ISearchResult } from './SearchEngine';
10
+
11
+ /**
12
+ * Interface for managing a highlight decoration.
13
+ */
14
+ interface IHighlight extends IDisposable {
15
+ decoration: IDecoration;
16
+ match: ISearchResult;
17
+ }
18
+
19
+ /**
20
+ * Interface for managing multiple decorations for a single match.
21
+ */
22
+ interface IMultiHighlight extends IDisposable {
23
+ decorations: IDecoration[];
24
+ match: ISearchResult;
25
+ }
26
+
27
+ /**
28
+ * Manages visual decorations for search results including highlighting and active selection
29
+ * indicators. This class handles the creation, styling, and disposal of search-related decorations.
30
+ */
31
+ export class DecorationManager extends Disposable {
32
+ private _highlightDecorations: IHighlight[] = [];
33
+ private _highlightedLines: Set<number> = new Set();
34
+
35
+ constructor(private readonly _terminal: Terminal) {
36
+ super();
37
+ this._register(toDisposable(() => this.clearHighlightDecorations()));
38
+ }
39
+
40
+ /**
41
+ * Creates decorations for all provided search results.
42
+ * @param results The search results to create decorations for.
43
+ * @param options The decoration options.
44
+ */
45
+ public createHighlightDecorations(results: ISearchResult[], options: ISearchDecorationOptions): void {
46
+ this.clearHighlightDecorations();
47
+
48
+ for (const match of results) {
49
+ const decorations = this._createResultDecorations(match, options, false);
50
+ if (decorations) {
51
+ for (const decoration of decorations) {
52
+ this._storeDecoration(decoration, match);
53
+ }
54
+ }
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Creates decorations for the currently active search result.
60
+ * @param result The active search result.
61
+ * @param options The decoration options.
62
+ * @returns The multi-highlight decoration or undefined if creation failed.
63
+ */
64
+ public createActiveDecoration(result: ISearchResult, options: ISearchDecorationOptions): IMultiHighlight | undefined {
65
+ const decorations = this._createResultDecorations(result, options, true);
66
+ if (decorations) {
67
+ return { decorations, match: result, dispose() { dispose(decorations); } };
68
+ }
69
+ return undefined;
70
+ }
71
+
72
+ /**
73
+ * Clears all highlight decorations.
74
+ */
75
+ public clearHighlightDecorations(): void {
76
+ dispose(this._highlightDecorations);
77
+ this._highlightDecorations = [];
78
+ this._highlightedLines.clear();
79
+ }
80
+
81
+ /**
82
+ * Stores a decoration and tracks it for management.
83
+ * @param decoration The decoration to store.
84
+ * @param match The search result this decoration represents.
85
+ */
86
+ private _storeDecoration(decoration: IDecoration, match: ISearchResult): void {
87
+ this._highlightedLines.add(decoration.marker.line);
88
+ this._highlightDecorations.push({ decoration, match, dispose() { decoration.dispose(); } });
89
+ }
90
+
91
+ /**
92
+ * Applies styles to the decoration when it is rendered.
93
+ * @param element The decoration's element.
94
+ * @param borderColor The border color to apply.
95
+ * @param isActiveResult Whether the element is part of the active search result.
96
+ */
97
+ private _applyStyles(element: HTMLElement, borderColor: string | undefined, isActiveResult: boolean): void {
98
+ if (!element.classList.contains('xterm-find-result-decoration')) {
99
+ element.classList.add('xterm-find-result-decoration');
100
+ if (borderColor) {
101
+ element.style.outline = `1px solid ${borderColor}`;
102
+ }
103
+ }
104
+ if (isActiveResult) {
105
+ element.classList.add('xterm-find-active-result-decoration');
106
+ }
107
+ }
108
+
109
+ /**
110
+ * Creates a decoration for the result and applies styles
111
+ * @param result the search result for which to create the decoration
112
+ * @param options the options for the decoration
113
+ * @param isActiveResult whether this is the currently active result
114
+ * @returns the decorations or undefined if the marker has already been disposed of
115
+ */
116
+ private _createResultDecorations(result: ISearchResult, options: ISearchDecorationOptions, isActiveResult: boolean): IDecoration[] | undefined {
117
+ // Gather decoration ranges for this match as it could wrap
118
+ const decorationRanges: [number, number, number][] = [];
119
+ let currentCol = result.col;
120
+ let remainingSize = result.size;
121
+ let markerOffset = -this._terminal.buffer.active.baseY - this._terminal.buffer.active.cursorY + result.row;
122
+ while (remainingSize > 0) {
123
+ const amountThisRow = Math.min(this._terminal.cols - currentCol, remainingSize);
124
+ decorationRanges.push([markerOffset, currentCol, amountThisRow]);
125
+ currentCol = 0;
126
+ remainingSize -= amountThisRow;
127
+ markerOffset++;
128
+ }
129
+
130
+ // Create the decorations
131
+ const decorations: IDecoration[] = [];
132
+ for (const range of decorationRanges) {
133
+ const marker = this._terminal.registerMarker(range[0]);
134
+ const decoration = this._terminal.registerDecoration({
135
+ marker,
136
+ x: range[1],
137
+ width: range[2],
138
+ backgroundColor: isActiveResult ? options.activeMatchBackground : options.matchBackground,
139
+ overviewRulerOptions: this._highlightedLines.has(marker.line) ? undefined : {
140
+ color: isActiveResult ? options.activeMatchColorOverviewRuler : options.matchOverviewRuler,
141
+ position: 'center'
142
+ }
143
+ });
144
+ if (decoration) {
145
+ const disposables: IDisposable[] = [];
146
+ disposables.push(marker);
147
+ disposables.push(decoration.onRender((e) => this._applyStyles(e, isActiveResult ? options.activeMatchBorder : options.matchBorder, false)));
148
+ disposables.push(decoration.onDispose(() => dispose(disposables)));
149
+ decorations.push(decoration);
150
+ }
151
+ }
152
+
153
+ return decorations.length === 0 ? undefined : decorations;
154
+ }
155
+ }
156
+
157
+