486 lines
20 KiB
JavaScript
486 lines
20 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
var CircularList_1 = require("./common/CircularList");
|
|
var BufferLine_1 = require("./core/buffer/BufferLine");
|
|
var BufferReflow_1 = require("./core/buffer/BufferReflow");
|
|
var Marker_1 = require("./core/buffer/Marker");
|
|
exports.MAX_BUFFER_SIZE = 4294967295;
|
|
var Buffer = (function () {
|
|
function Buffer(_terminal, _hasScrollback) {
|
|
this._terminal = _terminal;
|
|
this._hasScrollback = _hasScrollback;
|
|
this.savedCurAttrData = BufferLine_1.DEFAULT_ATTR_DATA.clone();
|
|
this.markers = [];
|
|
this._nullCell = BufferLine_1.CellData.fromCharData([0, BufferLine_1.NULL_CELL_CHAR, BufferLine_1.NULL_CELL_WIDTH, BufferLine_1.NULL_CELL_CODE]);
|
|
this._whitespaceCell = BufferLine_1.CellData.fromCharData([0, BufferLine_1.WHITESPACE_CELL_CHAR, BufferLine_1.WHITESPACE_CELL_WIDTH, BufferLine_1.WHITESPACE_CELL_CODE]);
|
|
this._cols = this._terminal.cols;
|
|
this._rows = this._terminal.rows;
|
|
this.clear();
|
|
}
|
|
Buffer.prototype.getNullCell = function (attr) {
|
|
if (attr) {
|
|
this._nullCell.fg = attr.fg;
|
|
this._nullCell.bg = attr.bg;
|
|
}
|
|
else {
|
|
this._nullCell.fg = 0;
|
|
this._nullCell.bg = 0;
|
|
}
|
|
return this._nullCell;
|
|
};
|
|
Buffer.prototype.getWhitespaceCell = function (attr) {
|
|
if (attr) {
|
|
this._whitespaceCell.fg = attr.fg;
|
|
this._whitespaceCell.bg = attr.bg;
|
|
}
|
|
else {
|
|
this._whitespaceCell.fg = 0;
|
|
this._whitespaceCell.bg = 0;
|
|
}
|
|
return this._whitespaceCell;
|
|
};
|
|
Buffer.prototype.getBlankLine = function (attr, isWrapped) {
|
|
return new BufferLine_1.BufferLine(this._terminal.cols, this.getNullCell(attr), isWrapped);
|
|
};
|
|
Object.defineProperty(Buffer.prototype, "hasScrollback", {
|
|
get: function () {
|
|
return this._hasScrollback && this.lines.maxLength > this._rows;
|
|
},
|
|
enumerable: true,
|
|
configurable: true
|
|
});
|
|
Object.defineProperty(Buffer.prototype, "isCursorInViewport", {
|
|
get: function () {
|
|
var absoluteY = this.ybase + this.y;
|
|
var relativeY = absoluteY - this.ydisp;
|
|
return (relativeY >= 0 && relativeY < this._rows);
|
|
},
|
|
enumerable: true,
|
|
configurable: true
|
|
});
|
|
Buffer.prototype._getCorrectBufferLength = function (rows) {
|
|
if (!this._hasScrollback) {
|
|
return rows;
|
|
}
|
|
var correctBufferLength = rows + this._terminal.options.scrollback;
|
|
return correctBufferLength > exports.MAX_BUFFER_SIZE ? exports.MAX_BUFFER_SIZE : correctBufferLength;
|
|
};
|
|
Buffer.prototype.fillViewportRows = function (fillAttr) {
|
|
if (this.lines.length === 0) {
|
|
if (fillAttr === undefined) {
|
|
fillAttr = BufferLine_1.DEFAULT_ATTR_DATA;
|
|
}
|
|
var i = this._rows;
|
|
while (i--) {
|
|
this.lines.push(this.getBlankLine(fillAttr));
|
|
}
|
|
}
|
|
};
|
|
Buffer.prototype.clear = function () {
|
|
this.ydisp = 0;
|
|
this.ybase = 0;
|
|
this.y = 0;
|
|
this.x = 0;
|
|
this.lines = new CircularList_1.CircularList(this._getCorrectBufferLength(this._rows));
|
|
this.scrollTop = 0;
|
|
this.scrollBottom = this._rows - 1;
|
|
this.setupTabStops();
|
|
};
|
|
Buffer.prototype.resize = function (newCols, newRows) {
|
|
var nullCell = this.getNullCell(BufferLine_1.DEFAULT_ATTR_DATA);
|
|
var newMaxLength = this._getCorrectBufferLength(newRows);
|
|
if (newMaxLength > this.lines.maxLength) {
|
|
this.lines.maxLength = newMaxLength;
|
|
}
|
|
if (this.lines.length > 0) {
|
|
if (this._cols < newCols) {
|
|
for (var i = 0; i < this.lines.length; i++) {
|
|
this.lines.get(i).resize(newCols, nullCell);
|
|
}
|
|
}
|
|
var addToY = 0;
|
|
if (this._rows < newRows) {
|
|
for (var y = this._rows; y < newRows; y++) {
|
|
if (this.lines.length < newRows + this.ybase) {
|
|
if (this.ybase > 0 && this.lines.length <= this.ybase + this.y + addToY + 1) {
|
|
this.ybase--;
|
|
addToY++;
|
|
if (this.ydisp > 0) {
|
|
this.ydisp--;
|
|
}
|
|
}
|
|
else {
|
|
this.lines.push(new BufferLine_1.BufferLine(newCols, nullCell));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
for (var y = this._rows; y > newRows; y--) {
|
|
if (this.lines.length > newRows + this.ybase) {
|
|
if (this.lines.length > this.ybase + this.y + 1) {
|
|
this.lines.pop();
|
|
}
|
|
else {
|
|
this.ybase++;
|
|
this.ydisp++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (newMaxLength < this.lines.maxLength) {
|
|
var 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;
|
|
}
|
|
this.x = Math.min(this.x, newCols - 1);
|
|
this.y = Math.min(this.y, newRows - 1);
|
|
if (addToY) {
|
|
this.y += addToY;
|
|
}
|
|
this.savedY = Math.min(this.savedY, newRows - 1);
|
|
this.savedX = Math.min(this.savedX, newCols - 1);
|
|
this.scrollTop = 0;
|
|
}
|
|
this.scrollBottom = newRows - 1;
|
|
if (this._isReflowEnabled) {
|
|
this._reflow(newCols, newRows);
|
|
if (this._cols > newCols) {
|
|
for (var i = 0; i < this.lines.length; i++) {
|
|
this.lines.get(i).resize(newCols, nullCell);
|
|
}
|
|
}
|
|
}
|
|
this._cols = newCols;
|
|
this._rows = newRows;
|
|
};
|
|
Object.defineProperty(Buffer.prototype, "_isReflowEnabled", {
|
|
get: function () {
|
|
return this._hasScrollback && !this._terminal.options.windowsMode;
|
|
},
|
|
enumerable: true,
|
|
configurable: true
|
|
});
|
|
Buffer.prototype._reflow = function (newCols, newRows) {
|
|
if (this._cols === newCols) {
|
|
return;
|
|
}
|
|
if (newCols > this._cols) {
|
|
this._reflowLarger(newCols, newRows);
|
|
}
|
|
else {
|
|
this._reflowSmaller(newCols, newRows);
|
|
}
|
|
};
|
|
Buffer.prototype._reflowLarger = function (newCols, newRows) {
|
|
var toRemove = BufferReflow_1.reflowLargerGetLinesToRemove(this.lines, this._cols, newCols, this.ybase + this.y, this.getNullCell(BufferLine_1.DEFAULT_ATTR_DATA));
|
|
if (toRemove.length > 0) {
|
|
var newLayoutResult = BufferReflow_1.reflowLargerCreateNewLayout(this.lines, toRemove);
|
|
BufferReflow_1.reflowLargerApplyNewLayout(this.lines, newLayoutResult.layout);
|
|
this._reflowLargerAdjustViewport(newCols, newRows, newLayoutResult.countRemoved);
|
|
}
|
|
};
|
|
Buffer.prototype._reflowLargerAdjustViewport = function (newCols, newRows, countRemoved) {
|
|
var nullCell = this.getNullCell(BufferLine_1.DEFAULT_ATTR_DATA);
|
|
var viewportAdjustments = countRemoved;
|
|
while (viewportAdjustments-- > 0) {
|
|
if (this.ybase === 0) {
|
|
if (this.y > 0) {
|
|
this.y--;
|
|
}
|
|
if (this.lines.length < newRows) {
|
|
this.lines.push(new BufferLine_1.BufferLine(newCols, nullCell));
|
|
}
|
|
}
|
|
else {
|
|
if (this.ydisp === this.ybase) {
|
|
this.ydisp--;
|
|
}
|
|
this.ybase--;
|
|
}
|
|
}
|
|
};
|
|
Buffer.prototype._reflowSmaller = function (newCols, newRows) {
|
|
var nullCell = this.getNullCell(BufferLine_1.DEFAULT_ATTR_DATA);
|
|
var toInsert = [];
|
|
var countToInsert = 0;
|
|
for (var y = this.lines.length - 1; y >= 0; y--) {
|
|
var nextLine = this.lines.get(y);
|
|
if (!nextLine || !nextLine.isWrapped && nextLine.getTrimmedLength() <= newCols) {
|
|
continue;
|
|
}
|
|
var wrappedLines = [nextLine];
|
|
while (nextLine.isWrapped && y > 0) {
|
|
nextLine = this.lines.get(--y);
|
|
wrappedLines.unshift(nextLine);
|
|
}
|
|
var absoluteY = this.ybase + this.y;
|
|
if (absoluteY >= y && absoluteY < y + wrappedLines.length) {
|
|
continue;
|
|
}
|
|
var lastLineLength = wrappedLines[wrappedLines.length - 1].getTrimmedLength();
|
|
var destLineLengths = BufferReflow_1.reflowSmallerGetNewLineLengths(wrappedLines, this._cols, newCols);
|
|
var linesToAdd = destLineLengths.length - wrappedLines.length;
|
|
var trimmedLines = void 0;
|
|
if (this.ybase === 0 && this.y !== this.lines.length - 1) {
|
|
trimmedLines = Math.max(0, this.y - this.lines.maxLength + linesToAdd);
|
|
}
|
|
else {
|
|
trimmedLines = Math.max(0, this.lines.length - this.lines.maxLength + linesToAdd);
|
|
}
|
|
var newLines = [];
|
|
for (var i = 0; i < linesToAdd; i++) {
|
|
var newLine = this.getBlankLine(BufferLine_1.DEFAULT_ATTR_DATA, true);
|
|
newLines.push(newLine);
|
|
}
|
|
if (newLines.length > 0) {
|
|
toInsert.push({
|
|
start: y + wrappedLines.length + countToInsert,
|
|
newLines: newLines
|
|
});
|
|
countToInsert += newLines.length;
|
|
}
|
|
wrappedLines.push.apply(wrappedLines, newLines);
|
|
var destLineIndex = destLineLengths.length - 1;
|
|
var destCol = destLineLengths[destLineIndex];
|
|
if (destCol === 0) {
|
|
destLineIndex--;
|
|
destCol = destLineLengths[destLineIndex];
|
|
}
|
|
var srcLineIndex = wrappedLines.length - linesToAdd - 1;
|
|
var srcCol = lastLineLength;
|
|
while (srcLineIndex >= 0) {
|
|
var cellsToCopy = Math.min(srcCol, destCol);
|
|
wrappedLines[destLineIndex].copyCellsFrom(wrappedLines[srcLineIndex], srcCol - cellsToCopy, destCol - cellsToCopy, cellsToCopy, true);
|
|
destCol -= cellsToCopy;
|
|
if (destCol === 0) {
|
|
destLineIndex--;
|
|
destCol = destLineLengths[destLineIndex];
|
|
}
|
|
srcCol -= cellsToCopy;
|
|
if (srcCol === 0) {
|
|
srcLineIndex--;
|
|
var wrappedLinesIndex = Math.max(srcLineIndex, 0);
|
|
srcCol = BufferReflow_1.getWrappedLineTrimmedLength(wrappedLines, wrappedLinesIndex, this._cols);
|
|
}
|
|
}
|
|
for (var i = 0; i < wrappedLines.length; i++) {
|
|
if (destLineLengths[i] < newCols) {
|
|
wrappedLines[i].setCell(destLineLengths[i], nullCell);
|
|
}
|
|
}
|
|
var viewportAdjustments = linesToAdd - trimmedLines;
|
|
while (viewportAdjustments-- > 0) {
|
|
if (this.ybase === 0) {
|
|
if (this.y < newRows - 1) {
|
|
this.y++;
|
|
this.lines.pop();
|
|
}
|
|
else {
|
|
this.ybase++;
|
|
this.ydisp++;
|
|
}
|
|
}
|
|
else {
|
|
if (this.ybase < Math.min(this.lines.maxLength, this.lines.length + countToInsert) - newRows) {
|
|
if (this.ybase === this.ydisp) {
|
|
this.ydisp++;
|
|
}
|
|
this.ybase++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (toInsert.length > 0) {
|
|
var insertEvents = [];
|
|
var originalLines = [];
|
|
for (var i = 0; i < this.lines.length; i++) {
|
|
originalLines.push(this.lines.get(i));
|
|
}
|
|
var originalLinesLength = this.lines.length;
|
|
var originalLineIndex = originalLinesLength - 1;
|
|
var nextToInsertIndex = 0;
|
|
var nextToInsert = toInsert[nextToInsertIndex];
|
|
this.lines.length = Math.min(this.lines.maxLength, this.lines.length + countToInsert);
|
|
var countInsertedSoFar = 0;
|
|
for (var i = Math.min(this.lines.maxLength - 1, originalLinesLength + countToInsert - 1); i >= 0; i--) {
|
|
if (nextToInsert && nextToInsert.start > originalLineIndex + countInsertedSoFar) {
|
|
for (var nextI = nextToInsert.newLines.length - 1; nextI >= 0; nextI--) {
|
|
this.lines.set(i--, nextToInsert.newLines[nextI]);
|
|
}
|
|
i++;
|
|
insertEvents.push({
|
|
index: originalLineIndex + 1,
|
|
amount: nextToInsert.newLines.length
|
|
});
|
|
countInsertedSoFar += nextToInsert.newLines.length;
|
|
nextToInsert = toInsert[++nextToInsertIndex];
|
|
}
|
|
else {
|
|
this.lines.set(i, originalLines[originalLineIndex--]);
|
|
}
|
|
}
|
|
var insertCountEmitted = 0;
|
|
for (var i = insertEvents.length - 1; i >= 0; i--) {
|
|
insertEvents[i].index += insertCountEmitted;
|
|
this.lines.onInsertEmitter.fire(insertEvents[i]);
|
|
insertCountEmitted += insertEvents[i].amount;
|
|
}
|
|
var amountToTrim = Math.max(0, originalLinesLength + countToInsert - this.lines.maxLength);
|
|
if (amountToTrim > 0) {
|
|
this.lines.onTrimEmitter.fire(amountToTrim);
|
|
}
|
|
}
|
|
};
|
|
Buffer.prototype.stringIndexToBufferIndex = function (lineIndex, stringIndex, trimRight) {
|
|
if (trimRight === void 0) { trimRight = false; }
|
|
while (stringIndex) {
|
|
var line = this.lines.get(lineIndex);
|
|
if (!line) {
|
|
return [-1, -1];
|
|
}
|
|
var length_1 = (trimRight) ? line.getTrimmedLength() : line.length;
|
|
for (var i = 0; i < length_1; ++i) {
|
|
if (line.get(i)[BufferLine_1.CHAR_DATA_WIDTH_INDEX]) {
|
|
stringIndex -= line.get(i)[BufferLine_1.CHAR_DATA_CHAR_INDEX].length || 1;
|
|
}
|
|
if (stringIndex < 0) {
|
|
return [lineIndex, i];
|
|
}
|
|
}
|
|
lineIndex++;
|
|
}
|
|
return [lineIndex, 0];
|
|
};
|
|
Buffer.prototype.translateBufferLineToString = function (lineIndex, trimRight, startCol, endCol) {
|
|
if (startCol === void 0) { startCol = 0; }
|
|
var line = this.lines.get(lineIndex);
|
|
if (!line) {
|
|
return '';
|
|
}
|
|
return line.translateToString(trimRight, startCol, endCol);
|
|
};
|
|
Buffer.prototype.getWrappedRangeForLine = function (y) {
|
|
var first = y;
|
|
var last = y;
|
|
while (first > 0 && this.lines.get(first).isWrapped) {
|
|
first--;
|
|
}
|
|
while (last + 1 < this.lines.length && this.lines.get(last + 1).isWrapped) {
|
|
last++;
|
|
}
|
|
return { first: first, last: last };
|
|
};
|
|
Buffer.prototype.setupTabStops = function (i) {
|
|
if (i !== null && i !== undefined) {
|
|
if (!this.tabs[i]) {
|
|
i = this.prevStop(i);
|
|
}
|
|
}
|
|
else {
|
|
this.tabs = {};
|
|
i = 0;
|
|
}
|
|
for (; i < this._cols; i += this._terminal.options.tabStopWidth) {
|
|
this.tabs[i] = true;
|
|
}
|
|
};
|
|
Buffer.prototype.prevStop = function (x) {
|
|
if (x === null || x === undefined) {
|
|
x = this.x;
|
|
}
|
|
while (!this.tabs[--x] && x > 0)
|
|
;
|
|
return x >= this._cols ? this._cols - 1 : x < 0 ? 0 : x;
|
|
};
|
|
Buffer.prototype.nextStop = function (x) {
|
|
if (x === null || x === undefined) {
|
|
x = this.x;
|
|
}
|
|
while (!this.tabs[++x] && x < this._cols)
|
|
;
|
|
return x >= this._cols ? this._cols - 1 : x < 0 ? 0 : x;
|
|
};
|
|
Buffer.prototype.addMarker = function (y) {
|
|
var _this = this;
|
|
var marker = new Marker_1.Marker(y);
|
|
this.markers.push(marker);
|
|
marker.register(this.lines.onTrim(function (amount) {
|
|
marker.line -= amount;
|
|
if (marker.line < 0) {
|
|
marker.dispose();
|
|
}
|
|
}));
|
|
marker.register(this.lines.onInsert(function (event) {
|
|
if (marker.line >= event.index) {
|
|
marker.line += event.amount;
|
|
}
|
|
}));
|
|
marker.register(this.lines.onDelete(function (event) {
|
|
if (marker.line >= event.index && marker.line < event.index + event.amount) {
|
|
marker.dispose();
|
|
}
|
|
if (marker.line > event.index) {
|
|
marker.line -= event.amount;
|
|
}
|
|
}));
|
|
marker.register(marker.onDispose(function () { return _this._removeMarker(marker); }));
|
|
return marker;
|
|
};
|
|
Buffer.prototype._removeMarker = function (marker) {
|
|
this.markers.splice(this.markers.indexOf(marker), 1);
|
|
};
|
|
Buffer.prototype.iterator = function (trimRight, startIndex, endIndex, startOverscan, endOverscan) {
|
|
return new BufferStringIterator(this, trimRight, startIndex, endIndex, startOverscan, endOverscan);
|
|
};
|
|
return Buffer;
|
|
}());
|
|
exports.Buffer = Buffer;
|
|
var BufferStringIterator = (function () {
|
|
function BufferStringIterator(_buffer, _trimRight, _startIndex, _endIndex, _startOverscan, _endOverscan) {
|
|
if (_startIndex === void 0) { _startIndex = 0; }
|
|
if (_endIndex === void 0) { _endIndex = _buffer.lines.length; }
|
|
if (_startOverscan === void 0) { _startOverscan = 0; }
|
|
if (_endOverscan === void 0) { _endOverscan = 0; }
|
|
this._buffer = _buffer;
|
|
this._trimRight = _trimRight;
|
|
this._startIndex = _startIndex;
|
|
this._endIndex = _endIndex;
|
|
this._startOverscan = _startOverscan;
|
|
this._endOverscan = _endOverscan;
|
|
if (this._startIndex < 0) {
|
|
this._startIndex = 0;
|
|
}
|
|
if (this._endIndex > this._buffer.lines.length) {
|
|
this._endIndex = this._buffer.lines.length;
|
|
}
|
|
this._current = this._startIndex;
|
|
}
|
|
BufferStringIterator.prototype.hasNext = function () {
|
|
return this._current < this._endIndex;
|
|
};
|
|
BufferStringIterator.prototype.next = function () {
|
|
var range = this._buffer.getWrappedRangeForLine(this._current);
|
|
if (range.first < this._startIndex - this._startOverscan) {
|
|
range.first = this._startIndex - this._startOverscan;
|
|
}
|
|
if (range.last > this._endIndex + this._endOverscan) {
|
|
range.last = this._endIndex + this._endOverscan;
|
|
}
|
|
range.first = Math.max(range.first, 0);
|
|
range.last = Math.min(range.last, this._buffer.lines.length);
|
|
var result = '';
|
|
for (var i = range.first; i <= range.last; ++i) {
|
|
result += this._buffer.translateBufferLineToString(i, this._trimRight);
|
|
}
|
|
this._current = range.last + 1;
|
|
return { range: range, content: result };
|
|
};
|
|
return BufferStringIterator;
|
|
}());
|
|
exports.BufferStringIterator = BufferStringIterator;
|
|
//# sourceMappingURL=Buffer.js.map
|