]>
Commit | Line | Data |
---|---|---|
f7d6ab5f DI |
1 | /** |
2 | * @license MIT | |
3 | */ | |
4 | ||
5 | import { ITerminal } from './Interfaces'; | |
6 | ||
7 | export class SelectionModel { | |
8 | /** | |
9 | * Whether select all is currently active. | |
10 | */ | |
11 | public isSelectAllActive: boolean; | |
12 | ||
13 | /** | |
14 | * The [x, y] position the selection starts at. | |
15 | */ | |
16 | public selectionStart: [number, number]; | |
17 | ||
18 | /** | |
19 | * The minimal length of the selection from the start position. When double | |
20 | * clicking on a word, the word will be selected which makes the selection | |
21 | * start at the start of the word and makes this variable the length. | |
22 | */ | |
23 | public selectionStartLength: number; | |
24 | ||
25 | /** | |
26 | * The [x, y] position the selection ends at. | |
27 | */ | |
28 | public selectionEnd: [number, number]; | |
29 | ||
30 | constructor( | |
31 | private _terminal: ITerminal | |
32 | ) { | |
a047359f | 33 | this.clearSelection(); |
f7d6ab5f DI |
34 | } |
35 | ||
4405f5e1 DI |
36 | /** |
37 | * Clears the current selection. | |
38 | */ | |
39 | public clearSelection(): void { | |
40 | this.selectionStart = null; | |
41 | this.selectionEnd = null; | |
42 | this.isSelectAllActive = false; | |
a047359f | 43 | this.selectionStartLength = 0; |
4405f5e1 DI |
44 | } |
45 | ||
f7d6ab5f DI |
46 | /** |
47 | * The final selection start, taking into consideration select all. | |
48 | */ | |
49 | public get finalSelectionStart(): [number, number] { | |
50 | if (this.isSelectAllActive) { | |
51 | return [0, 0]; | |
52 | } | |
53 | ||
a047359f | 54 | if (!this.selectionEnd || !this.selectionStart) { |
f7d6ab5f DI |
55 | return this.selectionStart; |
56 | } | |
57 | ||
58 | return this._areSelectionValuesReversed() ? this.selectionEnd : this.selectionStart; | |
59 | } | |
60 | ||
61 | /** | |
62 | * The final selection end, taking into consideration select all, double click | |
63 | * word selection and triple click line selection. | |
64 | */ | |
65 | public get finalSelectionEnd(): [number, number] { | |
2b243182 DI |
66 | if (this.isSelectAllActive) { |
67 | return [this._terminal.cols - 1, this._terminal.ybase + this._terminal.rows - 1]; | |
24bed01f DI |
68 | } |
69 | ||
2b243182 DI |
70 | if (!this.selectionStart) { |
71 | return null; | |
f7d6ab5f DI |
72 | } |
73 | ||
74 | // Use the selection start if the end doesn't exist or they're reversed | |
75 | if (!this.selectionEnd || this._areSelectionValuesReversed()) { | |
a047359f DI |
76 | if (this.selectionStartLength === 0) { |
77 | return null; | |
78 | } | |
f7d6ab5f DI |
79 | return [this.selectionStart[0] + this.selectionStartLength, this.selectionStart[1]]; |
80 | } | |
81 | ||
82 | // Ensure the the word/line is selected after a double/triple click | |
83 | if (this.selectionStartLength) { | |
84 | // Select the larger of the two when start and end are on the same line | |
85 | if (this.selectionEnd[1] === this.selectionStart[1]) { | |
86 | return [Math.max(this.selectionStart[0] + this.selectionStartLength, this.selectionEnd[0]), this.selectionEnd[1]]; | |
87 | } | |
88 | } | |
89 | return this.selectionEnd; | |
90 | } | |
91 | ||
92 | /** | |
93 | * Returns whether the selection start and end are reversed. | |
94 | */ | |
b81c165b | 95 | protected _areSelectionValuesReversed(): boolean { |
f7d6ab5f DI |
96 | const start = this.selectionStart; |
97 | const end = this.selectionEnd; | |
98 | return start[1] > end[1] || (start[1] === end[1] && start[0] > end[0]); | |
99 | } | |
100 | ||
101 | /** | |
102 | * Handle the buffer being trimmed, adjust the selection position. | |
103 | * @param amount The amount the buffer is being trimmed. | |
104 | * @return Whether a refresh is necessary. | |
105 | */ | |
106 | public onTrim(amount: number): boolean { | |
107 | // Adjust the selection position based on the trimmed amount. | |
108 | if (this.selectionStart) { | |
b81c165b | 109 | this.selectionStart[1] -= amount; |
f7d6ab5f DI |
110 | } |
111 | if (this.selectionEnd) { | |
b81c165b | 112 | this.selectionEnd[1] -= amount; |
f7d6ab5f DI |
113 | } |
114 | ||
115 | // The selection has moved off the buffer, clear it. | |
b81c165b DI |
116 | if (this.selectionEnd && this.selectionEnd[1] < 0) { |
117 | this.clearSelection(); | |
f7d6ab5f DI |
118 | return true; |
119 | } | |
120 | ||
121 | // If the selection start is trimmed, ensure the start column is 0. | |
b81c165b | 122 | if (this.selectionStart && this.selectionStart[1] < 0) { |
f7d6ab5f DI |
123 | this.selectionStart[1] = 0; |
124 | } | |
125 | return false; | |
126 | } | |
127 | } |