]> git.proxmox.com Git - mirror_xterm.js.git/blob - src/addons/search/searchHelper.ts
Get find working as an addon
[mirror_xterm.js.git] / src / addons / search / searchHelper.ts
1 /**
2 * @license MIT
3 */
4
5 // import { ITerminal } from '../../Interfaces';
6 // import { translateBufferLineToString } from '../../utils/BufferLine';
7
8 interface ISearchResult {
9 term: string;
10 col: number;
11 row: number;
12 }
13
14 export class SearchHelper {
15 constructor(private _terminal: any, private _translateBufferLineToString: any) {
16 // TODO: Search for multiple instances on 1 line
17 // TODO: Don't use the actual selection, instead use a "find selection" so multiple instances can be highlighted
18 // TODO: Highlight other instances in the viewport
19 // TODO: Support regex, case sensitivity, etc.
20 }
21
22 /**
23 * Find the next instance of the term, then scroll to and select it. If it
24 * doesn't exist, do nothing.
25 * @param term The term to search for.
26 * @return Whether a result was found.
27 */
28 public findNext(term: string): boolean {
29 if (!term || term.length === 0) {
30 return false;
31 }
32
33 let result: ISearchResult;
34
35 let startRow = this._terminal.ydisp;
36 if (this._terminal.selectionManager.selectionEnd) {
37 // Start from the selection end if there is a selection
38 startRow = this._terminal.selectionManager.selectionEnd[1];
39 }
40
41 // Search from ydisp + 1 to end
42 for (let y = startRow + 1; y < this._terminal.ybase + this._terminal.rows; y++) {
43 result = this._findInLine(term, y);
44 if (result) {
45 break;
46 }
47 }
48
49 // Search from the top to the current ydisp
50 if (!result) {
51 for (let y = 0; y < startRow; y++) {
52 result = this._findInLine(term, y);
53 if (result) {
54 break;
55 }
56 }
57 }
58
59 // Set selection and scroll if a result was found
60 return this._selectResult(result);
61 }
62
63 /**
64 * Find the previous instance of the term, then scroll to and select it. If it
65 * doesn't exist, do nothing.
66 * @param term The term to search for.
67 * @return Whether a result was found.
68 */
69 public findPrevious(term: string): boolean {
70 if (!term || term.length === 0) {
71 return false;
72 }
73
74 let result: ISearchResult;
75
76 let startRow = this._terminal.ydisp;
77 if (this._terminal.selectionManager.selectionStart) {
78 // Start from the selection end if there is a selection
79 startRow = this._terminal.selectionManager.selectionStart[1];
80 }
81
82 // Search from ydisp + 1 to end
83 for (let y = startRow - 1; y >= 0; y--) {
84 result = this._findInLine(term, y);
85 if (result) {
86 break;
87 }
88 }
89
90 // Search from the top to the current ydisp
91 if (!result) {
92 for (let y = this._terminal.ybase + this._terminal.rows - 1; y > startRow; y--) {
93 result = this._findInLine(term, y);
94 if (result) {
95 break;
96 }
97 }
98 }
99
100 // Set selection and scroll if a result was found
101 return this._selectResult(result);
102 }
103
104 private _findInLine(term: string, y: number): ISearchResult {
105 const bufferLine = this._terminal.lines.get(y);
106 const lowerStringLine = this._translateBufferLineToString(bufferLine, true).toLowerCase();
107 const lowerTerm = term.toLowerCase();
108 const searchIndex = lowerStringLine.indexOf(lowerTerm);
109 if (searchIndex >= 0) {
110 return {
111 term,
112 col: searchIndex,
113 row: y
114 };
115 }
116 }
117
118 private _selectResult(result: ISearchResult): boolean {
119 if (!result) {
120 return false;
121 }
122 this._terminal.selectionManager.setSelection(result.col, result.row, result.term.length);
123 this._terminal.scrollDisp(result.row - this._terminal.ydisp, false);
124 return true;
125 }
126 }