]> git.proxmox.com Git - mirror_xterm.js.git/blob - src/SelectionModel.ts
Fix select all with no start and include content below viewport
[mirror_xterm.js.git] / src / SelectionModel.ts
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 ) {
33 }
34
35 /**
36 * The final selection start, taking into consideration select all.
37 */
38 public get finalSelectionStart(): [number, number] {
39 if (this.isSelectAllActive) {
40 return [0, 0];
41 }
42
43 if (!this.selectionEnd) {
44 return this.selectionStart;
45 }
46
47 return this._areSelectionValuesReversed() ? this.selectionEnd : this.selectionStart;
48 }
49
50 /**
51 * The final selection end, taking into consideration select all, double click
52 * word selection and triple click line selection.
53 */
54 public get finalSelectionEnd(): [number, number] {
55 if (this.isSelectAllActive) {
56 return [this._terminal.cols - 1, this._terminal.ybase + this._terminal.rows - 1];
57 }
58
59 if (!this.selectionStart) {
60 return null;
61 }
62
63 // Use the selection start if the end doesn't exist or they're reversed
64 if (!this.selectionEnd || this._areSelectionValuesReversed()) {
65 return [this.selectionStart[0] + this.selectionStartLength, this.selectionStart[1]];
66 }
67
68 // Ensure the the word/line is selected after a double/triple click
69 if (this.selectionStartLength) {
70 // Select the larger of the two when start and end are on the same line
71 if (this.selectionEnd[1] === this.selectionStart[1]) {
72 return [Math.max(this.selectionStart[0] + this.selectionStartLength, this.selectionEnd[0]), this.selectionEnd[1]];
73 }
74 }
75 return this.selectionEnd;
76 }
77
78 /**
79 * Returns whether the selection start and end are reversed.
80 */
81 private _areSelectionValuesReversed(): boolean {
82 const start = this.selectionStart;
83 const end = this.selectionEnd;
84 return start[1] > end[1] || (start[1] === end[1] && start[0] > end[0]);
85 }
86
87 /**
88 * Handle the buffer being trimmed, adjust the selection position.
89 * @param amount The amount the buffer is being trimmed.
90 * @return Whether a refresh is necessary.
91 */
92 public onTrim(amount: number): boolean {
93 // Adjust the selection position based on the trimmed amount.
94 if (this.selectionStart) {
95 this.selectionStart[0] -= amount;
96 }
97 if (this.selectionEnd) {
98 this.selectionEnd[0] -= amount;
99 }
100
101 // The selection has moved off the buffer, clear it.
102 if (this.selectionEnd && this.selectionEnd[0] < 0) {
103 this.selectionStart = null;
104 this.selectionEnd = null;
105 return true;
106 }
107
108 // If the selection start is trimmed, ensure the start column is 0.
109 if (this.selectionStart && this.selectionStart[0] < 0) {
110 this.selectionStart[1] = 0;
111 }
112 return false;
113 }
114 }