]> git.proxmox.com Git - mirror_xterm.js.git/blame - src/Buffer.ts
Merge pull request #926 from ficristo/search-fix
[mirror_xterm.js.git] / src / Buffer.ts
CommitLineData
95cb6f30
PK
1/**
2 * @license MIT
3 */
4
f03d00a4 5import { ITerminal, IBuffer } from './Interfaces';
95cb6f30
PK
6import { 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
15export 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}