+17
-1
@@ -20,7 +20,7 @@ describe('Buffer', () => {
|
|||||||
terminal.cols = INIT_COLS;
|
terminal.cols = INIT_COLS;
|
||||||
terminal.rows = INIT_ROWS;
|
terminal.rows = INIT_ROWS;
|
||||||
terminal.options.scrollback = 1000;
|
terminal.options.scrollback = 1000;
|
||||||
buffer = new Buffer(terminal);
|
buffer = new Buffer(terminal, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('constructor', () => {
|
describe('constructor', () => {
|
||||||
@@ -145,4 +145,20 @@ describe('Buffer', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('alt buffer', () => {
|
||||||
|
it('should always have a scrollback of 0', () => {
|
||||||
|
assert.equal(terminal.options.scrollback, 1000);
|
||||||
|
// Test size on initialization
|
||||||
|
buffer = new Buffer(terminal, true);
|
||||||
|
buffer.fillViewportRows();
|
||||||
|
assert.equal(buffer.lines.maxLength, INIT_ROWS);
|
||||||
|
// Test size on buffer increase
|
||||||
|
buffer.resize(INIT_COLS, INIT_ROWS * 2);
|
||||||
|
assert.equal(buffer.lines.maxLength, INIT_ROWS * 2);
|
||||||
|
// Test size on buffer decrease
|
||||||
|
buffer.resize(INIT_COLS, INIT_ROWS / 2);
|
||||||
|
assert.equal(buffer.lines.maxLength, INIT_ROWS / 2);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
+39
-7
@@ -28,14 +28,12 @@ export class Buffer implements IBuffer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new Buffer.
|
* Create a new Buffer.
|
||||||
* @param {Terminal} _terminal - The terminal the Buffer will belong to
|
* @param _terminal The terminal the Buffer will belong to.
|
||||||
* @param {number} ydisp - The scroll position of the Buffer in the viewport
|
* @param _isAltBuffer Whether the buffer is the alt buffer.
|
||||||
* @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(
|
constructor(
|
||||||
private _terminal: ITerminal
|
private _terminal: ITerminal,
|
||||||
|
private _isAltBuffer: boolean
|
||||||
) {
|
) {
|
||||||
this.clear();
|
this.clear();
|
||||||
}
|
}
|
||||||
@@ -44,6 +42,20 @@ export class Buffer implements IBuffer {
|
|||||||
return this._lines;
|
return this._lines;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the correct buffer length based on the rows provided, the terminal's
|
||||||
|
* scrollback and whether this is an alt buffer.
|
||||||
|
* @param rows The terminal rows to use in the calculation.
|
||||||
|
*/
|
||||||
|
private _getCorrectBufferLength(rows: number): number {
|
||||||
|
// The alt buffer should never have scrollback.
|
||||||
|
// See http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-The-Alternate-Screen-Buffer
|
||||||
|
if (this._isAltBuffer) {
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
return rows + this._terminal.options.scrollback;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fills the buffer's viewport with blank lines.
|
* Fills the buffer's viewport with blank lines.
|
||||||
*/
|
*/
|
||||||
@@ -67,7 +79,7 @@ export class Buffer implements IBuffer {
|
|||||||
this.scrollBottom = 0;
|
this.scrollBottom = 0;
|
||||||
this.scrollTop = 0;
|
this.scrollTop = 0;
|
||||||
this.tabs = {};
|
this.tabs = {};
|
||||||
this._lines = new CircularList<LineData>(this._terminal.rows + this._terminal.options.scrollback);
|
this._lines = new CircularList<LineData>(this._getCorrectBufferLength(this._terminal.rows));
|
||||||
this.scrollBottom = this._terminal.rows - 1;
|
this.scrollBottom = this._terminal.rows - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,6 +94,13 @@ export class Buffer implements IBuffer {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Increase max length if needed before adjustments to allow space to fill
|
||||||
|
// as required.
|
||||||
|
const newMaxLength = this._getCorrectBufferLength(newRows);
|
||||||
|
if (newMaxLength > this._lines.maxLength) {
|
||||||
|
this._lines.maxLength = newMaxLength;
|
||||||
|
}
|
||||||
|
|
||||||
// Deal with columns increasing (we don't do anything when columns reduce)
|
// Deal with columns increasing (we don't do anything when columns reduce)
|
||||||
if (this._terminal.cols < newCols) {
|
if (this._terminal.cols < newCols) {
|
||||||
const ch: CharData = [this._terminal.defAttr, ' ', 1]; // does xterm use the default attr?
|
const ch: CharData = [this._terminal.defAttr, ' ', 1]; // does xterm use the default attr?
|
||||||
@@ -131,6 +150,19 @@ export class Buffer implements IBuffer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reduce max length if needed after adjustments, this is done after as it
|
||||||
|
// would otherwise cut data from the bottom of the buffer.
|
||||||
|
if (newMaxLength < this._lines.maxLength) {
|
||||||
|
// Trim from the top of the buffer and adjust ybase and ydisp.
|
||||||
|
// const amountToTrim = this._lines.length - newMaxLength;
|
||||||
|
// if (amountToTrim > 0) {
|
||||||
|
// this._lines.trimStart(amountToTrim);
|
||||||
|
// this.ybase = Math.max(this.ybase - amountToTrim, 0);
|
||||||
|
// this.ydisp = Math.max(this.ydisp - amountToTrim, 0);
|
||||||
|
// }
|
||||||
|
this._lines.maxLength = newMaxLength;
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure that the cursor stays on screen
|
// Make sure that the cursor stays on screen
|
||||||
if (this.y >= newRows) {
|
if (this.y >= newRows) {
|
||||||
this.y = newRows - 1;
|
this.y = newRows - 1;
|
||||||
|
|||||||
+2
-15
@@ -21,9 +21,9 @@ export class BufferSet extends EventEmitter implements IBufferSet {
|
|||||||
*/
|
*/
|
||||||
constructor(private _terminal: ITerminal) {
|
constructor(private _terminal: ITerminal) {
|
||||||
super();
|
super();
|
||||||
this._normal = new Buffer(this._terminal);
|
this._normal = new Buffer(this._terminal, false);
|
||||||
this._normal.fillViewportRows();
|
this._normal.fillViewportRows();
|
||||||
this._alt = new Buffer(this._terminal);
|
this._alt = new Buffer(this._terminal, true);
|
||||||
this._activeBuffer = this._normal;
|
this._activeBuffer = this._normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,22 +71,10 @@ export class BufferSet extends EventEmitter implements IBufferSet {
|
|||||||
// Since the alt buffer is always cleared when the normal buffer is
|
// Since the alt buffer is always cleared when the normal buffer is
|
||||||
// activated, we want to fill it when switching to it.
|
// activated, we want to fill it when switching to it.
|
||||||
this._alt.fillViewportRows();
|
this._alt.fillViewportRows();
|
||||||
|
|
||||||
this._activeBuffer = this._alt;
|
this._activeBuffer = this._alt;
|
||||||
this.emit('activate', this._alt);
|
this.emit('activate', this._alt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Refreshes the max length of the buffer set, this should be called whenever
|
|
||||||
* terminal rows or scrollback changes.
|
|
||||||
* @param rows The number of terminal rows.
|
|
||||||
*/
|
|
||||||
public refreshMaxLength(rows: number): void {
|
|
||||||
this._normal.lines.maxLength = rows + this._terminal.options.scrollback;
|
|
||||||
// TODO: The alt buffer should never have scrollback, see https://github.com/sourcelair/xterm.js/issues/802
|
|
||||||
this._alt.lines.maxLength = rows + this._terminal.options.scrollback;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resizes both normal and alt buffers, adjusting their data accordingly.
|
* Resizes both normal and alt buffers, adjusting their data accordingly.
|
||||||
* @param newCols The new number of columns.
|
* @param newCols The new number of columns.
|
||||||
@@ -95,6 +83,5 @@ export class BufferSet extends EventEmitter implements IBufferSet {
|
|||||||
public resize(newCols: number, newRows: number): void {
|
public resize(newCols: number, newRows: number): void {
|
||||||
this._normal.resize(newCols, newRows);
|
this._normal.resize(newCols, newRows);
|
||||||
this._alt.resize(newCols, newRows);
|
this._alt.resize(newCols, newRows);
|
||||||
this.refreshMaxLength(newRows);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-22
@@ -442,23 +442,13 @@ export class InputHandler implements IInputHandler {
|
|||||||
}
|
}
|
||||||
let row: number = this._terminal.buffer.y + this._terminal.buffer.ybase;
|
let row: number = this._terminal.buffer.y + this._terminal.buffer.ybase;
|
||||||
|
|
||||||
let j: number;
|
let scrollBottomRowsOffset = this._terminal.rows - 1 - this._terminal.buffer.scrollBottom;
|
||||||
j = this._terminal.rows - 1 - this._terminal.buffer.scrollBottom;
|
let scrollBottomAbsolute = this._terminal.rows - 1 + this._terminal.buffer.ybase - scrollBottomRowsOffset + 1;
|
||||||
j = this._terminal.rows - 1 + this._terminal.buffer.ybase - j + 1;
|
|
||||||
|
|
||||||
while (param--) {
|
while (param--) {
|
||||||
if (this._terminal.buffer.lines.length === this._terminal.buffer.lines.maxLength) {
|
|
||||||
// Trim the start of lines to make room for the new line
|
|
||||||
this._terminal.buffer.lines.trimStart(1);
|
|
||||||
this._terminal.buffer.ybase--;
|
|
||||||
this._terminal.buffer.ydisp--;
|
|
||||||
row--;
|
|
||||||
j--;
|
|
||||||
}
|
|
||||||
// test: echo -e '\e[44m\e[1L\e[0m'
|
// test: echo -e '\e[44m\e[1L\e[0m'
|
||||||
// blankLine(true) - xterm/linux behavior
|
// blankLine(true) - xterm/linux behavior
|
||||||
|
this._terminal.buffer.lines.splice(scrollBottomAbsolute - 1, 1);
|
||||||
this._terminal.buffer.lines.splice(row, 0, this._terminal.blankLine(true));
|
this._terminal.buffer.lines.splice(row, 0, this._terminal.blankLine(true));
|
||||||
this._terminal.buffer.lines.splice(j, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// this.maxRange();
|
// this.maxRange();
|
||||||
@@ -480,18 +470,11 @@ export class InputHandler implements IInputHandler {
|
|||||||
let j: number;
|
let j: number;
|
||||||
j = this._terminal.rows - 1 - this._terminal.buffer.scrollBottom;
|
j = this._terminal.rows - 1 - this._terminal.buffer.scrollBottom;
|
||||||
j = this._terminal.rows - 1 + this._terminal.buffer.ybase - j;
|
j = this._terminal.rows - 1 + this._terminal.buffer.ybase - j;
|
||||||
|
|
||||||
while (param--) {
|
while (param--) {
|
||||||
if (this._terminal.buffer.lines.length === this._terminal.buffer.lines.maxLength) {
|
|
||||||
// Trim the start of lines to make room for the new line
|
|
||||||
this._terminal.buffer.lines.trimStart(1);
|
|
||||||
this._terminal.buffer.ybase -= 1;
|
|
||||||
this._terminal.buffer.ydisp -= 1;
|
|
||||||
}
|
|
||||||
// test: echo -e '\e[44m\e[1M\e[0m'
|
// test: echo -e '\e[44m\e[1M\e[0m'
|
||||||
// blankLine(true) - xterm/linux behavior
|
// blankLine(true) - xterm/linux behavior
|
||||||
this._terminal.buffer.lines.splice(j + 1, 0, this._terminal.blankLine(true));
|
this._terminal.buffer.lines.splice(row - 1, 1);
|
||||||
this._terminal.buffer.lines.splice(row, 1);
|
this._terminal.buffer.lines.splice(j, 0, this._terminal.blankLine(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
// this.maxRange();
|
// this.maxRange();
|
||||||
|
|||||||
+5
-6
@@ -464,7 +464,7 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT
|
|||||||
this.element.classList.toggle(`xterm-cursor-style-bar`, value === 'bar');
|
this.element.classList.toggle(`xterm-cursor-style-bar`, value === 'bar');
|
||||||
break;
|
break;
|
||||||
case 'scrollback':
|
case 'scrollback':
|
||||||
this.buffers.refreshMaxLength(this.rows);
|
this.buffers.resize(this.cols, this.rows);
|
||||||
this.viewport.syncScrollArea();
|
this.viewport.syncScrollArea();
|
||||||
break;
|
break;
|
||||||
case 'tabStopWidth': this.setupStops(); break;
|
case 'tabStopWidth': this.setupStops(); break;
|
||||||
@@ -1177,17 +1177,16 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT
|
|||||||
let row;
|
let row;
|
||||||
|
|
||||||
// Make room for the new row in lines
|
// Make room for the new row in lines
|
||||||
if (this.buffer.lines.length === this.buffer.lines.maxLength) {
|
const bufferNeedsTrimming = this.buffer.lines.length === this.buffer.lines.maxLength;
|
||||||
|
if (bufferNeedsTrimming) {
|
||||||
this.buffer.lines.trimStart(1);
|
this.buffer.lines.trimStart(1);
|
||||||
this.buffer.ybase--;
|
this.buffer.ybase--;
|
||||||
if (this.buffer.ydisp !== 0) {
|
this.buffer.ydisp = Math.max(this.buffer.ydisp - 1, 0);
|
||||||
this.buffer.ydisp--;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.buffer.ybase++;
|
this.buffer.ybase++;
|
||||||
|
|
||||||
// TODO: Why is this done twice?
|
// Scroll the viewport down to the bottom if the user is not scrolling
|
||||||
if (!this.userScrolling) {
|
if (!this.userScrolling) {
|
||||||
this.buffer.ydisp = this.buffer.ybase;
|
this.buffer.ydisp = this.buffer.ybase;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user