]> git.proxmox.com Git - mirror_xterm.js.git/blame - src/SelectionModel.ts
Add more selection manager/model tests
[mirror_xterm.js.git] / src / SelectionModel.ts
CommitLineData
f7d6ab5f
DI
1/**
2 * @license MIT
3 */
4
5import { ITerminal } from './Interfaces';
6
7export 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}