]>
Commit | Line | Data |
---|---|---|
95cb6f30 PK |
1 | /** |
2 | * @license MIT | |
3 | */ | |
4 | ||
f03d00a4 | 5 | import { ITerminal, IBuffer } from './Interfaces'; |
95cb6f30 PK |
6 | import { CircularList } from './utils/CircularList'; |
7 | ||
bbafdd3d | 8 | /** |
58b9f712 PK |
9 | * This class represents a terminal buffer (an internal state of the terminal), where the |
10 | * following information is stored (in high-level): | |
11 | * - text content of this particular buffer | |
12 | * - cursor position | |
13 | * - scroll position | |
bbafdd3d | 14 | */ |
f03d00a4 DI |
15 | export class Buffer implements IBuffer { |
16 | private _lines: CircularList<[number, string, number][]>; | |
95cb6f30 | 17 | |
f03d00a4 DI |
18 | public ydisp: number; |
19 | public ybase: number; | |
20 | public y: number; | |
21 | public x: number; | |
22 | public scrollBottom: number; | |
23 | public scrollTop: number; | |
24 | public tabs: any; | |
604959a3 DI |
25 | public savedY: number; |
26 | public savedX: number; | |
27 | ||
bbafdd3d PK |
28 | /** |
29 | * Create a new Buffer. | |
3d20c2f2 | 30 | * @param {Terminal} _terminal - The terminal the Buffer will belong to |
58b9f712 PK |
31 | * @param {number} ydisp - The scroll position of the Buffer in the viewport |
32 | * @param {number} ybase - The scroll position of the y cursor (ybase + y = the y position within the Buffer) | |
bbafdd3d PK |
33 | * @param {number} y - The cursor's y position after ybase |
34 | * @param {number} x - The cursor's x position after ybase | |
35 | */ | |
36 | constructor( | |
f03d00a4 | 37 | private _terminal: ITerminal |
bbafdd3d | 38 | ) { |
f03d00a4 DI |
39 | this.clear(); |
40 | } | |
41 | ||
42 | public get lines(): CircularList<[number, string, number][]> { | |
43 | return this._lines; | |
44 | } | |
45 | ||
0731f286 DI |
46 | /** |
47 | * Fills the buffer's viewport with blank lines. | |
48 | */ | |
f03d00a4 DI |
49 | public fillViewportRows(): void { |
50 | if (this._lines.length === 0) { | |
51 | let i = this._terminal.rows; | |
52 | while (i--) { | |
53 | this.lines.push(this._terminal.blankLine()); | |
54 | } | |
55 | } | |
56 | } | |
57 | ||
0731f286 DI |
58 | /** |
59 | * Clears the buffer to it's initial state, discarding all previous data. | |
60 | */ | |
f03d00a4 DI |
61 | public clear(): void { |
62 | this.ydisp = 0; | |
63 | this.ybase = 0; | |
64 | this.y = 0; | |
65 | this.x = 0; | |
66 | this.scrollBottom = 0; | |
67 | this.scrollTop = 0; | |
68 | this.tabs = {}; | |
69 | this._lines = new CircularList<[number, string, number][]>(this._terminal.scrollback); | |
3d20c2f2 DI |
70 | this.scrollBottom = this._terminal.rows - 1; |
71 | } | |
72 | ||
0731f286 DI |
73 | /** |
74 | * Resizes the buffer, adjusting its data accordingly. | |
75 | * @param newCols The new number of columns. | |
76 | * @param newRows The new number of rows. | |
77 | */ | |
3d20c2f2 DI |
78 | public resize(newCols: number, newRows: number): void { |
79 | // Don't resize the buffer if it's empty and hasn't been used yet. | |
f03d00a4 | 80 | if (this._lines.length === 0) { |
3d20c2f2 DI |
81 | return; |
82 | } | |
83 | ||
84 | // Deal with columns increasing (we don't do anything when columns reduce) | |
85 | if (this._terminal.cols < newCols) { | |
86 | const ch: [number, string, number] = [this._terminal.defAttr, ' ', 1]; // does xterm use the default attr? | |
f03d00a4 | 87 | for (let i = 0; i < this._lines.length; i++) { |
bb526aaa DI |
88 | // TODO: This should be removed, with tests setup for the case that was |
89 | // causing the underlying bug, see https://github.com/sourcelair/xterm.js/issues/824 | |
f03d00a4 | 90 | if (this._lines.get(i) === undefined) { |
bb526aaa | 91 | this._lines.set(i, this._terminal.blankLine(undefined, undefined, newCols)); |
3d20c2f2 | 92 | } |
f03d00a4 DI |
93 | while (this._lines.get(i).length < newCols) { |
94 | this._lines.get(i).push(ch); | |
3d20c2f2 DI |
95 | } |
96 | } | |
97 | } | |
98 | ||
99 | // Resize rows in both directions as needed | |
100 | let addToY = 0; | |
101 | if (this._terminal.rows < newRows) { | |
102 | for (let y = this._terminal.rows; y < newRows; y++) { | |
f03d00a4 DI |
103 | if (this._lines.length < newRows + this.ybase) { |
104 | if (this.ybase > 0 && this._lines.length <= this.ybase + this.y + addToY + 1) { | |
3d20c2f2 DI |
105 | // There is room above the buffer and there are no empty elements below the line, |
106 | // scroll up | |
107 | this.ybase--; | |
108 | addToY++; | |
109 | if (this.ydisp > 0) { | |
110 | // Viewport is at the top of the buffer, must increase downwards | |
111 | this.ydisp--; | |
112 | } | |
113 | } else { | |
114 | // Add a blank line if there is no buffer left at the top to scroll to, or if there | |
115 | // are blank lines after the cursor | |
bb526aaa | 116 | this._lines.push(this._terminal.blankLine(undefined, undefined, newCols)); |
3d20c2f2 DI |
117 | } |
118 | } | |
119 | } | |
120 | } else { // (this._terminal.rows >= newRows) | |
121 | for (let y = this._terminal.rows; y > newRows; y--) { | |
f03d00a4 DI |
122 | if (this._lines.length > newRows + this.ybase) { |
123 | if (this._lines.length > this.ybase + this.y + 1) { | |
3d20c2f2 | 124 | // The line is a blank line below the cursor, remove it |
f03d00a4 | 125 | this._lines.pop(); |
3d20c2f2 DI |
126 | } else { |
127 | // The line is the cursor, scroll down | |
128 | this.ybase++; | |
129 | this.ydisp++; | |
130 | } | |
131 | } | |
132 | } | |
133 | } | |
134 | ||
135 | // Make sure that the cursor stays on screen | |
136 | if (this.y >= newRows) { | |
137 | this.y = newRows - 1; | |
138 | } | |
139 | if (addToY) { | |
140 | this.y += addToY; | |
141 | } | |
142 | ||
143 | if (this.x >= newCols) { | |
144 | this.x = newCols - 1; | |
145 | } | |
146 | ||
147 | this.scrollTop = 0; | |
148 | this.scrollBottom = newRows - 1; | |
95cb6f30 PK |
149 | } |
150 | } |