]>
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 | ||
46 | public fillViewportRows(): void { | |
47 | if (this._lines.length === 0) { | |
48 | let i = this._terminal.rows; | |
49 | while (i--) { | |
50 | this.lines.push(this._terminal.blankLine()); | |
51 | } | |
52 | } | |
53 | } | |
54 | ||
55 | public clear(): void { | |
56 | this.ydisp = 0; | |
57 | this.ybase = 0; | |
58 | this.y = 0; | |
59 | this.x = 0; | |
60 | this.scrollBottom = 0; | |
61 | this.scrollTop = 0; | |
62 | this.tabs = {}; | |
63 | this._lines = new CircularList<[number, string, number][]>(this._terminal.scrollback); | |
3d20c2f2 DI |
64 | this.scrollBottom = this._terminal.rows - 1; |
65 | } | |
66 | ||
67 | public resize(newCols: number, newRows: number): void { | |
68 | // Don't resize the buffer if it's empty and hasn't been used yet. | |
f03d00a4 | 69 | if (this._lines.length === 0) { |
3d20c2f2 DI |
70 | return; |
71 | } | |
72 | ||
73 | // Deal with columns increasing (we don't do anything when columns reduce) | |
74 | if (this._terminal.cols < newCols) { | |
75 | const ch: [number, string, number] = [this._terminal.defAttr, ' ', 1]; // does xterm use the default attr? | |
f03d00a4 DI |
76 | for (let i = 0; i < this._lines.length; i++) { |
77 | if (this._lines.get(i) === undefined) { | |
78 | this._lines.set(i, this._terminal.blankLine()); | |
3d20c2f2 | 79 | } |
f03d00a4 DI |
80 | while (this._lines.get(i).length < newCols) { |
81 | this._lines.get(i).push(ch); | |
3d20c2f2 DI |
82 | } |
83 | } | |
84 | } | |
85 | ||
86 | // Resize rows in both directions as needed | |
87 | let addToY = 0; | |
88 | if (this._terminal.rows < newRows) { | |
89 | for (let y = this._terminal.rows; y < newRows; y++) { | |
f03d00a4 DI |
90 | if (this._lines.length < newRows + this.ybase) { |
91 | if (this.ybase > 0 && this._lines.length <= this.ybase + this.y + addToY + 1) { | |
3d20c2f2 DI |
92 | // There is room above the buffer and there are no empty elements below the line, |
93 | // scroll up | |
94 | this.ybase--; | |
95 | addToY++; | |
96 | if (this.ydisp > 0) { | |
97 | // Viewport is at the top of the buffer, must increase downwards | |
98 | this.ydisp--; | |
99 | } | |
100 | } else { | |
101 | // Add a blank line if there is no buffer left at the top to scroll to, or if there | |
102 | // are blank lines after the cursor | |
f03d00a4 | 103 | this._lines.push(this._terminal.blankLine()); |
3d20c2f2 DI |
104 | } |
105 | } | |
106 | } | |
107 | } else { // (this._terminal.rows >= newRows) | |
108 | for (let y = this._terminal.rows; y > newRows; y--) { | |
f03d00a4 DI |
109 | if (this._lines.length > newRows + this.ybase) { |
110 | if (this._lines.length > this.ybase + this.y + 1) { | |
3d20c2f2 | 111 | // The line is a blank line below the cursor, remove it |
f03d00a4 | 112 | this._lines.pop(); |
3d20c2f2 DI |
113 | } else { |
114 | // The line is the cursor, scroll down | |
115 | this.ybase++; | |
116 | this.ydisp++; | |
117 | } | |
118 | } | |
119 | } | |
120 | } | |
121 | ||
122 | // Make sure that the cursor stays on screen | |
123 | if (this.y >= newRows) { | |
124 | this.y = newRows - 1; | |
125 | } | |
126 | if (addToY) { | |
127 | this.y += addToY; | |
128 | } | |
129 | ||
130 | if (this.x >= newCols) { | |
131 | this.x = newCols - 1; | |
132 | } | |
133 | ||
134 | this.scrollTop = 0; | |
135 | this.scrollBottom = newRows - 1; | |
95cb6f30 PK |
136 | } |
137 | } |