* - scroll position
*/
export class Buffer {
- public lines: CircularList<[number, string, number][]>;
+ public readonly lines: CircularList<[number, string, number][]>;
public savedY: number;
public savedX: number;
/**
* Create a new Buffer.
- * @param {Terminal} terminal - The terminal the Buffer will belong to
+ * @param {Terminal} _terminal - The terminal the Buffer will belong to
* @param {number} ydisp - The scroll position of the Buffer in the viewport
* @param {number} ybase - The scroll position of the y cursor (ybase + y = the y position within the Buffer)
* @param {number} y - The cursor's y position after ybase
* @param {number} x - The cursor's x position after ybase
*/
constructor(
- private terminal: ITerminal,
+ private _terminal: ITerminal,
public ydisp: number = 0,
public ybase: number = 0,
public y: number = 0,
public scrollTop: number = 0,
public tabs: any = {},
) {
- this.lines = new CircularList<[number, string, number][]>(this.terminal.scrollback);
- this.scrollBottom = this.terminal.rows - 1;
+ this.lines = new CircularList<[number, string, number][]>(this._terminal.scrollback);
+ this.scrollBottom = this._terminal.rows - 1;
+ }
+
+ public resize(newCols: number, newRows: number): void {
+ // Don't resize the buffer if it's empty and hasn't been used yet.
+ if (this.lines.length === 0) {
+ return;
+ }
+
+ // Deal with columns increasing (we don't do anything when columns reduce)
+ if (this._terminal.cols < newCols) {
+ const ch: [number, string, number] = [this._terminal.defAttr, ' ', 1]; // does xterm use the default attr?
+ for (let i = 0; i < this.lines.length; i++) {
+ if (this.lines.get(i) === undefined) {
+ this.lines.set(i, this._terminal.blankLine());
+ }
+ while (this.lines.get(i).length < newCols) {
+ this.lines.get(i).push(ch);
+ }
+ }
+ }
+
+ // Resize rows in both directions as needed
+ let addToY = 0;
+ if (this._terminal.rows < newRows) {
+ for (let y = this._terminal.rows; y < newRows; y++) {
+ if (this.lines.length < newRows + this.ybase) {
+ if (this.ybase > 0 && this.lines.length <= this.ybase + this.y + addToY + 1) {
+ // There is room above the buffer and there are no empty elements below the line,
+ // scroll up
+ this.ybase--;
+ addToY++;
+ if (this.ydisp > 0) {
+ // Viewport is at the top of the buffer, must increase downwards
+ this.ydisp--;
+ }
+ } else {
+ // Add a blank line if there is no buffer left at the top to scroll to, or if there
+ // are blank lines after the cursor
+ this.lines.push(this._terminal.blankLine());
+ }
+ }
+ }
+ } else { // (this._terminal.rows >= newRows)
+ for (let y = this._terminal.rows; y > newRows; y--) {
+ if (this.lines.length > newRows + this.ybase) {
+ if (this.lines.length > this.ybase + this.y + 1) {
+ // The line is a blank line below the cursor, remove it
+ this.lines.pop();
+ } else {
+ // The line is the cursor, scroll down
+ this.ybase++;
+ this.ydisp++;
+ }
+ }
+ }
+ }
+
+ // Make sure that the cursor stays on screen
+ if (this.y >= newRows) {
+ this.y = newRows - 1;
+ }
+ if (addToY) {
+ this.y += addToY;
+ }
+
+ if (this.x >= newCols) {
+ this.x = newCols - 1;
+ }
+
+ this.scrollTop = 0;
+ this.scrollBottom = newRows - 1;
}
}
this.surrogate_high = '';
// Create the terminal's buffers and set the current buffer
- this.buffers = new BufferSet(this);
+ this.buffers = this.buffers || new BufferSet(this);
this.buffer = this.buffers.active; // Convenience shortcut;
this.buffers.on('activate', function (buffer) {
this._terminal.buffer = buffer;
if (x < 1) x = 1;
if (y < 1) y = 1;
- // resize cols
- j = this.cols;
- if (j < x) {
- ch = [this.defAttr, ' ', 1]; // does xterm use the default attr?
- i = this.buffer.lines.length;
- while (i--) {
- if (this.buffer.lines.get(i) === undefined) {
- this.buffer.lines.set(i, this.blankLine());
- }
- while (this.buffer.lines.get(i).length < x) {
- this.buffer.lines.get(i).push(ch);
- }
- }
- }
-
- this.cols = x;
- this.setupStops(this.cols);
+ this.buffers.resize(x, y);
- // resize rows
- j = this.rows;
- addToY = 0;
- if (j < y) {
- el = this.element;
- while (j++ < y) {
- // y is rows, not this.buffer.y
- if (this.buffer.lines.length < y + this.buffer.ybase) {
- if (this.buffer.ybase > 0 && this.buffer.lines.length <= this.buffer.ybase + this.buffer.y + addToY + 1) {
- // There is room above the buffer and there are no empty elements below the line,
- // scroll up
- this.buffer.ybase--;
- addToY++;
- if (this.buffer.ydisp > 0) {
- // Viewport is at the top of the buffer, must increase downwards
- this.buffer.ydisp--;
- }
- } else {
- // Add a blank line if there is no buffer left at the top to scroll to, or if there
- // are blank lines after the cursor
- this.buffer.lines.push(this.blankLine());
- }
- }
- if (this.children.length < y) {
- this.insertRow();
- }
- }
- } else { // (j > y)
- while (j-- > y) {
- if (this.buffer.lines.length > y + this.buffer.ybase) {
- if (this.buffer.lines.length > this.buffer.ybase + this.buffer.y + 1) {
- // The line is a blank line below the cursor, remove it
- this.buffer.lines.pop();
- } else {
- // The line is the cursor, scroll down
- this.buffer.ybase++;
- this.buffer.ydisp++;
- }
- }
- if (this.children.length > y) {
- el = this.children.shift();
- if (!el) continue;
- el.parentNode.removeChild(el);
- }
- }
- }
- this.rows = y;
-
- // Make sure that the cursor stays on screen
- if (this.buffer.y >= y) {
- this.buffer.y = y - 1;
- }
- if (addToY) {
- this.buffer.y += addToY;
+ // Adjust rows in the DOM to accurately reflect the new dimensions
+ while (this.children.length < y) {
+ this.insertRow();
}
-
- if (this.buffer.x >= x) {
- this.buffer.x = x - 1;
+ while (this.children.length > y) {
+ el = this.children.shift();
+ if (!el) continue;
+ el.parentNode.removeChild(el);
}
- this.buffer.scrollTop = 0;
- this.buffer.scrollBottom = y - 1;
+ this.cols = x;
+ this.rows = y;
+ this.setupStops(this.cols);
this.charMeasure.measure();