Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4b7279146a | ||
|
|
c4a2f7911d | ||
|
|
db9fe53af3 | ||
|
|
42724c7f42 | ||
|
|
616f069538 | ||
|
|
2c3d98abc8 | ||
|
|
35b32b721e | ||
|
|
ccf1a047d3 | ||
|
|
db0338cbcf | ||
|
|
06742eb507 | ||
|
|
0fab4ff5d1 | ||
|
|
d2b0d514f8 | ||
|
|
70e35de56b | ||
|
|
c323e0ad4a | ||
|
|
4d32826891 | ||
|
|
13088f55a0 | ||
|
|
ea008411e4 | ||
|
|
a95ac990ff | ||
|
|
aad8439542 | ||
|
|
1a777edffe | ||
|
|
537018f71f | ||
|
|
67ca3a9334 | ||
|
|
5fb30979c1 | ||
|
|
cf863d4849 | ||
|
|
47814847f9 | ||
|
|
9ec8974545 | ||
|
|
c887c6e0f6 | ||
|
|
6c8949bba1 | ||
|
|
508d3ab68c | ||
|
|
6dad013783 | ||
|
|
0532e5cbf0 | ||
|
|
abcdf3e252 | ||
|
|
3baa6b9237 | ||
|
|
23e6a475ee | ||
|
|
6b5ced0078 | ||
|
|
c7e8498166 | ||
|
|
2b4c019f13 | ||
|
|
335850380e |
@@ -30,6 +30,7 @@ Ian Lewis <ianlewis@google.com>
|
||||
imoses <ido@twiggle.com>
|
||||
InDieTasten <indietasten@gmail.com>
|
||||
Jean Bruenn <himself@jeanbruenn.info>
|
||||
Jeremy Danyow <jedanyow@microsoft.com>
|
||||
Jörg Breitbart <jerch@rockborn.de>
|
||||
Justin Mecham <justin@mecham.me>
|
||||
Lucian Buzzo <lucian.buzzo@gmail.com>
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "xterm.js",
|
||||
"version": "2.6.0",
|
||||
"version": "2.7.0",
|
||||
"ignore": ["demo", "test", ".gitignore"],
|
||||
"main": [
|
||||
"dist/xterm.js",
|
||||
|
||||
Vendored
+2
-1
@@ -153,7 +153,8 @@
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.terminal .xterm-wide-char {
|
||||
.terminal .xterm-wide-char,
|
||||
.terminal .xterm-normal-char {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
|
||||
Vendored
+209
-110
@@ -372,10 +372,13 @@ var EventEmitter = (function () {
|
||||
return this.on(type, on);
|
||||
};
|
||||
EventEmitter.prototype.emit = function (type) {
|
||||
var args = [];
|
||||
for (var _i = 1; _i < arguments.length; _i++) {
|
||||
args[_i - 1] = arguments[_i];
|
||||
}
|
||||
if (!this._events[type]) {
|
||||
return;
|
||||
}
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
var obj = this._events[type];
|
||||
for (var i = 0; i < obj.length; i++) {
|
||||
obj[i].apply(this, args);
|
||||
@@ -1928,11 +1931,14 @@ var Parser = (function () {
|
||||
if (ch === EscapeSequences_1.C0.ESC || ch === EscapeSequences_1.C0.BEL) {
|
||||
if (ch === EscapeSequences_1.C0.ESC)
|
||||
this._position++;
|
||||
var pt = void 0;
|
||||
var valid = void 0;
|
||||
switch (this._terminal.prefix) {
|
||||
case '':
|
||||
break;
|
||||
case '$q':
|
||||
var pt = this._terminal.currentParam, valid = false;
|
||||
pt = this._terminal.currentParam;
|
||||
valid = false;
|
||||
switch (pt) {
|
||||
case '"q':
|
||||
pt = '0"q';
|
||||
@@ -1960,8 +1966,8 @@ var Parser = (function () {
|
||||
case '+p':
|
||||
break;
|
||||
case '+q':
|
||||
pt = this._terminal.currentParam
|
||||
, valid = false;
|
||||
pt = this._terminal.currentParam;
|
||||
valid = false;
|
||||
this._terminal.send(EscapeSequences_1.C0.ESC + 'P' + +valid + '+r' + pt + EscapeSequences_1.C0.ESC + '\\');
|
||||
break;
|
||||
default:
|
||||
@@ -1996,6 +2002,7 @@ var Parser = (function () {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return this._state;
|
||||
};
|
||||
Parser.prototype.setState = function (state) {
|
||||
this._state = state;
|
||||
@@ -2028,6 +2035,7 @@ exports.Parser = Parser;
|
||||
},{"./Charsets":1,"./EscapeSequences":3}],8:[function(require,module,exports){
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
var DomElementObjectPool_1 = require("./utils/DomElementObjectPool");
|
||||
var MAX_REFRESH_FRAME_SKIP = 5;
|
||||
var FLAGS;
|
||||
(function (FLAGS) {
|
||||
@@ -2045,9 +2053,11 @@ var Renderer = (function () {
|
||||
this._refreshRowsQueue = [];
|
||||
this._refreshFramesSkipped = 0;
|
||||
this._refreshAnimationFrame = null;
|
||||
this._spanElementObjectPool = new DomElementObjectPool_1.DomElementObjectPool('span');
|
||||
if (brokenBold === null) {
|
||||
brokenBold = checkBoldBroken(this._terminal.element);
|
||||
}
|
||||
this._spanElementObjectPool = new DomElementObjectPool_1.DomElementObjectPool('span');
|
||||
}
|
||||
Renderer.prototype.queueRefresh = function (start, end) {
|
||||
this._refreshRowsQueue.push({ start: start, end: end });
|
||||
@@ -2085,80 +2095,102 @@ var Renderer = (function () {
|
||||
this._refresh(start, end);
|
||||
};
|
||||
Renderer.prototype._refresh = function (start, end) {
|
||||
var x, y, i, line, out, ch, ch_width, width, data, attr, bg, fg, flags, row, parent, focused = document.activeElement;
|
||||
var parent;
|
||||
if (end - start >= this._terminal.rows / 2) {
|
||||
parent = this._terminal.element.parentNode;
|
||||
if (parent) {
|
||||
this._terminal.element.removeChild(this._terminal.rowContainer);
|
||||
}
|
||||
}
|
||||
width = this._terminal.cols;
|
||||
y = start;
|
||||
var width = this._terminal.cols;
|
||||
var y = start;
|
||||
if (end >= this._terminal.rows) {
|
||||
this._terminal.log('`end` is too large. Most likely a bad CSR.');
|
||||
end = this._terminal.rows - 1;
|
||||
}
|
||||
for (; y <= end; y++) {
|
||||
row = y + this._terminal.ydisp;
|
||||
line = this._terminal.lines.get(row);
|
||||
if (!line || !this._terminal.children[y]) {
|
||||
continue;
|
||||
}
|
||||
out = '';
|
||||
if (this._terminal.y === y - (this._terminal.ybase - this._terminal.ydisp)
|
||||
&& this._terminal.cursorState
|
||||
&& !this._terminal.cursorHidden) {
|
||||
var row = y + this._terminal.ydisp;
|
||||
var line = this._terminal.lines.get(row);
|
||||
var x = void 0;
|
||||
if (this._terminal.y === y - (this._terminal.ybase - this._terminal.ydisp) &&
|
||||
this._terminal.cursorState &&
|
||||
!this._terminal.cursorHidden) {
|
||||
x = this._terminal.x;
|
||||
}
|
||||
else {
|
||||
x = -1;
|
||||
}
|
||||
attr = this._terminal.defAttr;
|
||||
i = 0;
|
||||
for (; i < width; i++) {
|
||||
if (!line[i]) {
|
||||
var attr = this._terminal.defAttr;
|
||||
var documentFragment = document.createDocumentFragment();
|
||||
var innerHTML = '';
|
||||
var currentElement = void 0;
|
||||
while (this._terminal.children[y].children.length) {
|
||||
var child = this._terminal.children[y].children[0];
|
||||
this._terminal.children[y].removeChild(child);
|
||||
this._spanElementObjectPool.release(child);
|
||||
}
|
||||
for (var i = 0; i < width; i++) {
|
||||
var data = line[i][0];
|
||||
var ch = line[i][1];
|
||||
var ch_width = line[i][2];
|
||||
if (!ch_width) {
|
||||
continue;
|
||||
}
|
||||
data = line[i][0];
|
||||
ch = line[i][1];
|
||||
ch_width = line[i][2];
|
||||
if (!ch_width)
|
||||
continue;
|
||||
if (i === x)
|
||||
if (i === x) {
|
||||
data = -1;
|
||||
}
|
||||
if (data !== attr) {
|
||||
if (attr !== this._terminal.defAttr) {
|
||||
out += '</span>';
|
||||
if (innerHTML) {
|
||||
currentElement.innerHTML = innerHTML;
|
||||
innerHTML = '';
|
||||
}
|
||||
documentFragment.appendChild(currentElement);
|
||||
currentElement = null;
|
||||
}
|
||||
if (data !== this._terminal.defAttr) {
|
||||
if (innerHTML && !currentElement) {
|
||||
currentElement = this._spanElementObjectPool.acquire();
|
||||
}
|
||||
if (currentElement) {
|
||||
if (innerHTML) {
|
||||
currentElement.innerHTML = innerHTML;
|
||||
innerHTML = '';
|
||||
}
|
||||
documentFragment.appendChild(currentElement);
|
||||
}
|
||||
currentElement = this._spanElementObjectPool.acquire();
|
||||
if (data === -1) {
|
||||
out += '<span class="reverse-video terminal-cursor">';
|
||||
currentElement.classList.add('reverse-video', 'terminal-cursor');
|
||||
}
|
||||
else {
|
||||
var classNames = [];
|
||||
bg = data & 0x1ff;
|
||||
fg = (data >> 9) & 0x1ff;
|
||||
flags = data >> 18;
|
||||
var bg = data & 0x1ff;
|
||||
var fg = (data >> 9) & 0x1ff;
|
||||
var flags = data >> 18;
|
||||
if (flags & FLAGS.BOLD) {
|
||||
if (!brokenBold) {
|
||||
classNames.push('xterm-bold');
|
||||
currentElement.classList.add('xterm-bold');
|
||||
}
|
||||
if (fg < 8)
|
||||
if (fg < 8) {
|
||||
fg += 8;
|
||||
}
|
||||
}
|
||||
if (flags & FLAGS.UNDERLINE) {
|
||||
classNames.push('xterm-underline');
|
||||
currentElement.classList.add('xterm-underline');
|
||||
}
|
||||
if (flags & FLAGS.BLINK) {
|
||||
classNames.push('xterm-blink');
|
||||
currentElement.classList.add('xterm-blink');
|
||||
}
|
||||
if (flags & FLAGS.INVERSE) {
|
||||
bg = [fg, fg = bg][0];
|
||||
if ((flags & 1) && fg < 8)
|
||||
var temp = bg;
|
||||
bg = fg;
|
||||
fg = temp;
|
||||
if ((flags & 1) && fg < 8) {
|
||||
fg += 8;
|
||||
}
|
||||
}
|
||||
if (flags & FLAGS.INVISIBLE) {
|
||||
classNames.push('xterm-hidden');
|
||||
currentElement.classList.add('xterm-hidden');
|
||||
}
|
||||
if (flags & FLAGS.INVERSE) {
|
||||
if (bg === 257) {
|
||||
@@ -2169,50 +2201,55 @@ var Renderer = (function () {
|
||||
}
|
||||
}
|
||||
if (bg < 256) {
|
||||
classNames.push('xterm-bg-color-' + bg);
|
||||
currentElement.classList.add("xterm-bg-color-" + bg);
|
||||
}
|
||||
if (fg < 256) {
|
||||
classNames.push('xterm-color-' + fg);
|
||||
currentElement.classList.add("xterm-color-" + fg);
|
||||
}
|
||||
out += '<span';
|
||||
if (classNames.length) {
|
||||
out += ' class="' + classNames.join(' ') + '"';
|
||||
}
|
||||
out += '>';
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ch_width === 2) {
|
||||
out += '<span class="xterm-wide-char">';
|
||||
innerHTML += "<span class=\"xterm-wide-char\">" + ch + "</span>";
|
||||
}
|
||||
switch (ch) {
|
||||
case '&':
|
||||
out += '&';
|
||||
break;
|
||||
case '<':
|
||||
out += '<';
|
||||
break;
|
||||
case '>':
|
||||
out += '>';
|
||||
break;
|
||||
default:
|
||||
if (ch <= ' ') {
|
||||
out += ' ';
|
||||
}
|
||||
else {
|
||||
out += ch;
|
||||
}
|
||||
break;
|
||||
else if (ch.charCodeAt(0) > 255) {
|
||||
innerHTML += "<span class=\"xterm-normal-char\">" + ch + "</span>";
|
||||
}
|
||||
if (ch_width === 2) {
|
||||
out += '</span>';
|
||||
else {
|
||||
switch (ch) {
|
||||
case '&':
|
||||
innerHTML += '&';
|
||||
break;
|
||||
case '<':
|
||||
innerHTML += '<';
|
||||
break;
|
||||
case '>':
|
||||
innerHTML += '>';
|
||||
break;
|
||||
default:
|
||||
if (ch <= ' ') {
|
||||
innerHTML += ' ';
|
||||
}
|
||||
else {
|
||||
innerHTML += ch;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
attr = data;
|
||||
}
|
||||
if (attr !== this._terminal.defAttr) {
|
||||
out += '</span>';
|
||||
if (innerHTML && !currentElement) {
|
||||
currentElement = this._spanElementObjectPool.acquire();
|
||||
}
|
||||
this._terminal.children[y].innerHTML = out;
|
||||
if (currentElement) {
|
||||
if (innerHTML) {
|
||||
currentElement.innerHTML = innerHTML;
|
||||
innerHTML = '';
|
||||
}
|
||||
documentFragment.appendChild(currentElement);
|
||||
currentElement = null;
|
||||
}
|
||||
this._terminal.children[y].appendChild(documentFragment);
|
||||
}
|
||||
if (parent) {
|
||||
this._terminal.element.appendChild(this._terminal.rowContainer);
|
||||
@@ -2239,7 +2276,7 @@ function checkBoldBroken(terminal) {
|
||||
|
||||
|
||||
|
||||
},{}],9:[function(require,module,exports){
|
||||
},{"./utils/DomElementObjectPool":14}],9:[function(require,module,exports){
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
var Viewport = (function () {
|
||||
@@ -2328,6 +2365,13 @@ function prepareTextForClipboard(text) {
|
||||
return processedText;
|
||||
}
|
||||
exports.prepareTextForClipboard = prepareTextForClipboard;
|
||||
function prepareTextForTerminal(text, isMSWindows) {
|
||||
if (isMSWindows) {
|
||||
return text.replace(/\r?\n/g, '\n');
|
||||
}
|
||||
return text;
|
||||
}
|
||||
exports.prepareTextForTerminal = prepareTextForTerminal;
|
||||
function copyHandler(ev, term) {
|
||||
var copiedText = window.getSelection().toString(), text = prepareTextForClipboard(copiedText);
|
||||
if (term.browser.isMSIE) {
|
||||
@@ -2343,8 +2387,10 @@ function pasteHandler(ev, term) {
|
||||
ev.stopPropagation();
|
||||
var text;
|
||||
var dispatchPaste = function (text) {
|
||||
text = prepareTextForTerminal(text, term.browser.isMSWindows);
|
||||
term.handler(text);
|
||||
term.textarea.value = '';
|
||||
term.emit('paste', text);
|
||||
return term.cancel(ev);
|
||||
};
|
||||
if (term.browser.isMSIE) {
|
||||
@@ -2415,7 +2461,7 @@ exports.isMSWindows = Generic_1.contains(['Windows', 'Win16', 'Win32', 'WinCE'],
|
||||
|
||||
|
||||
|
||||
},{"./Generic":14}],12:[function(require,module,exports){
|
||||
},{"./Generic":15}],12:[function(require,module,exports){
|
||||
"use strict";
|
||||
var __extends = (this && this.__extends) || (function () {
|
||||
var extendStatics = Object.setPrototypeOf ||
|
||||
@@ -2626,6 +2672,53 @@ exports.CircularList = CircularList;
|
||||
},{}],14:[function(require,module,exports){
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
var DomElementObjectPool = (function () {
|
||||
function DomElementObjectPool(type) {
|
||||
this.type = type;
|
||||
this._type = type;
|
||||
this._pool = [];
|
||||
this._inUse = {};
|
||||
}
|
||||
DomElementObjectPool.prototype.acquire = function () {
|
||||
var element;
|
||||
if (this._pool.length === 0) {
|
||||
element = this._createNew();
|
||||
}
|
||||
else {
|
||||
element = this._pool.pop();
|
||||
}
|
||||
this._inUse[element.getAttribute(DomElementObjectPool.OBJECT_ID_ATTRIBUTE)] = element;
|
||||
return element;
|
||||
};
|
||||
DomElementObjectPool.prototype.release = function (element) {
|
||||
if (!this._inUse[element.getAttribute(DomElementObjectPool.OBJECT_ID_ATTRIBUTE)]) {
|
||||
throw new Error('Could not release an element not yet acquired');
|
||||
}
|
||||
delete this._inUse[element.getAttribute(DomElementObjectPool.OBJECT_ID_ATTRIBUTE)];
|
||||
this._cleanElement(element);
|
||||
this._pool.push(element);
|
||||
};
|
||||
DomElementObjectPool.prototype._createNew = function () {
|
||||
var element = document.createElement(this._type);
|
||||
var id = DomElementObjectPool._objectCount++;
|
||||
element.setAttribute(DomElementObjectPool.OBJECT_ID_ATTRIBUTE, id.toString(10));
|
||||
return element;
|
||||
};
|
||||
DomElementObjectPool.prototype._cleanElement = function (element) {
|
||||
element.className = '';
|
||||
element.innerHTML = '';
|
||||
};
|
||||
return DomElementObjectPool;
|
||||
}());
|
||||
DomElementObjectPool.OBJECT_ID_ATTRIBUTE = 'data-obj-id';
|
||||
DomElementObjectPool._objectCount = 0;
|
||||
exports.DomElementObjectPool = DomElementObjectPool;
|
||||
|
||||
|
||||
|
||||
},{}],15:[function(require,module,exports){
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
function contains(arr, el) {
|
||||
return arr.indexOf(el) >= 0;
|
||||
}
|
||||
@@ -2634,7 +2727,41 @@ exports.contains = contains;
|
||||
|
||||
|
||||
|
||||
},{}],15:[function(require,module,exports){
|
||||
},{}],16:[function(require,module,exports){
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
function getCoords(event, rowContainer, charMeasure) {
|
||||
if (event.pageX == null) {
|
||||
return null;
|
||||
}
|
||||
var x = event.pageX;
|
||||
var y = event.pageY;
|
||||
var el = rowContainer;
|
||||
while (el && el !== self.document.documentElement) {
|
||||
x -= el.offsetLeft;
|
||||
y -= el.offsetTop;
|
||||
el = 'offsetParent' in el ? el.offsetParent : el.parentElement;
|
||||
}
|
||||
x = Math.ceil(x / charMeasure.width);
|
||||
y = Math.ceil(y / charMeasure.height);
|
||||
return [x, y];
|
||||
}
|
||||
exports.getCoords = getCoords;
|
||||
function getRawByteCoords(event, rowContainer, charMeasure, colCount, rowCount) {
|
||||
var coords = getCoords(event, rowContainer, charMeasure);
|
||||
var x = coords[0];
|
||||
var y = coords[1];
|
||||
x = Math.min(Math.max(x, 0), colCount);
|
||||
y = Math.min(Math.max(y, 0), rowCount);
|
||||
x += 32;
|
||||
y += 32;
|
||||
return { x: x, y: y };
|
||||
}
|
||||
exports.getRawByteCoords = getRawByteCoords;
|
||||
|
||||
|
||||
|
||||
},{}],17:[function(require,module,exports){
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
var CompositionHelper_1 = require("./CompositionHelper");
|
||||
@@ -2649,6 +2776,7 @@ var Renderer_1 = require("./Renderer");
|
||||
var Linkifier_1 = require("./Linkifier");
|
||||
var CharMeasure_1 = require("./utils/CharMeasure");
|
||||
var Browser = require("./utils/Browser");
|
||||
var Mouse_1 = require("./utils/Mouse");
|
||||
var document = (typeof window != 'undefined') ? window.document : null;
|
||||
var WRITE_BUFFER_PAUSE_THRESHOLD = 5;
|
||||
var WRITE_BATCH_SIZE = 300;
|
||||
@@ -3102,14 +3230,16 @@ Terminal.loadAddon = function (addon, callback) {
|
||||
}
|
||||
};
|
||||
Terminal.prototype.updateCharSizeCSS = function () {
|
||||
this.charSizeStyleElement.textContent = '.xterm-wide-char{width:' + (this.charMeasure.width * 2) + 'px;}';
|
||||
this.charSizeStyleElement.textContent =
|
||||
".xterm-wide-char{width:" + this.charMeasure.width * 2 + "px;}" +
|
||||
(".xterm-normal-char{width:" + this.charMeasure.width + "px;}");
|
||||
};
|
||||
Terminal.prototype.bindMouse = function () {
|
||||
var el = this.element, self = this, pressed = 32;
|
||||
function sendButton(ev) {
|
||||
var button, pos;
|
||||
button = getButton(ev);
|
||||
pos = getCoords(ev);
|
||||
pos = Mouse_1.getRawByteCoords(ev, self.rowContainer, self.charMeasure, self.cols, self.rows);
|
||||
if (!pos)
|
||||
return;
|
||||
sendEvent(button, pos);
|
||||
@@ -3126,7 +3256,7 @@ Terminal.prototype.bindMouse = function () {
|
||||
}
|
||||
function sendMove(ev) {
|
||||
var button = pressed, pos;
|
||||
pos = getCoords(ev);
|
||||
pos = Mouse_1.getRawByteCoords(ev, self.rowContainer, self.charMeasure, self.cols, self.rows);
|
||||
if (!pos)
|
||||
return;
|
||||
button += 32;
|
||||
@@ -3265,38 +3395,6 @@ Terminal.prototype.bindMouse = function () {
|
||||
button = (32 + (mod << 2)) + button;
|
||||
return button;
|
||||
}
|
||||
function getCoords(ev) {
|
||||
var x, y, w, h, el;
|
||||
if (ev.pageX == null)
|
||||
return;
|
||||
x = ev.pageX;
|
||||
y = ev.pageY;
|
||||
el = self.element;
|
||||
while (el && el !== self.document.documentElement) {
|
||||
x -= el.offsetLeft;
|
||||
y -= el.offsetTop;
|
||||
el = 'offsetParent' in el
|
||||
? el.offsetParent
|
||||
: el.parentNode;
|
||||
}
|
||||
x = Math.ceil(x / self.charMeasure.width);
|
||||
y = Math.ceil(y / self.charMeasure.height);
|
||||
if (x < 0)
|
||||
x = 0;
|
||||
if (x > self.cols)
|
||||
x = self.cols;
|
||||
if (y < 0)
|
||||
y = 0;
|
||||
if (y > self.rows)
|
||||
y = self.rows;
|
||||
x += 32;
|
||||
y += 32;
|
||||
return {
|
||||
x: x,
|
||||
y: y,
|
||||
type: 'wheel'
|
||||
};
|
||||
}
|
||||
on(el, 'mousedown', function (ev) {
|
||||
if (!self.mouseEvents)
|
||||
return;
|
||||
@@ -3452,7 +3550,8 @@ Terminal.prototype.innerWrite = function () {
|
||||
}
|
||||
this.refreshStart = this.y;
|
||||
this.refreshEnd = this.y;
|
||||
this.parser.parse(data);
|
||||
var state = this.parser.parse(data);
|
||||
this.parser.setState(state);
|
||||
this.updateRange(this.y);
|
||||
this.refresh(this.refreshStart, this.refreshEnd);
|
||||
}
|
||||
@@ -4214,6 +4313,6 @@ module.exports = Terminal;
|
||||
|
||||
|
||||
|
||||
},{"./CompositionHelper":2,"./EscapeSequences":3,"./EventEmitter":4,"./InputHandler":5,"./Linkifier":6,"./Parser":7,"./Renderer":8,"./Viewport":9,"./handlers/Clipboard":10,"./utils/Browser":11,"./utils/CharMeasure":12,"./utils/CircularList":13}]},{},[15])(15)
|
||||
},{"./CompositionHelper":2,"./EscapeSequences":3,"./EventEmitter":4,"./InputHandler":5,"./Linkifier":6,"./Parser":7,"./Renderer":8,"./Viewport":9,"./handlers/Clipboard":10,"./utils/Browser":11,"./utils/CharMeasure":12,"./utils/CircularList":13,"./utils/Mouse":16}]},{},[17])(17)
|
||||
});
|
||||
//# sourceMappingURL=xterm.js.map
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "xterm",
|
||||
"description": "Full xterm terminal, in your browser",
|
||||
"version": "2.6.0",
|
||||
"version": "2.7.0",
|
||||
"ignore": [
|
||||
"demo",
|
||||
"test",
|
||||
|
||||
+1
-4
@@ -53,14 +53,11 @@ export class EventEmitter {
|
||||
return this.on(type, on);
|
||||
}
|
||||
|
||||
public emit(type): void {
|
||||
public emit(type: string, ...args: any[]): void {
|
||||
if (!this._events[type]) {
|
||||
return;
|
||||
}
|
||||
|
||||
let args = Array.prototype.slice.call(arguments, 1);
|
||||
let obj = this._events[type];
|
||||
|
||||
for (let i = 0; i < obj.length; i++) {
|
||||
obj[i].apply(this, args);
|
||||
}
|
||||
|
||||
+8
-6
@@ -181,7 +181,7 @@ export class Parser {
|
||||
*
|
||||
* @param data The data to parse.
|
||||
*/
|
||||
public parse(data: string) {
|
||||
public parse(data: string): ParserState {
|
||||
let l = data.length, j, cs, ch, code, low;
|
||||
|
||||
this._position = 0;
|
||||
@@ -471,6 +471,8 @@ export class Parser {
|
||||
case ParserState.DCS:
|
||||
if (ch === C0.ESC || ch === C0.BEL) {
|
||||
if (ch === C0.ESC) this._position++;
|
||||
let pt;
|
||||
let valid: boolean;
|
||||
|
||||
switch (this._terminal.prefix) {
|
||||
// User-Defined Keys (DECUDK).
|
||||
@@ -480,8 +482,8 @@ export class Parser {
|
||||
// Request Status String (DECRQSS).
|
||||
// test: echo -e '\eP$q"p\e\\'
|
||||
case '$q':
|
||||
let pt = this._terminal.currentParam
|
||||
, valid = false;
|
||||
pt = this._terminal.currentParam;
|
||||
valid = false;
|
||||
|
||||
switch (pt) {
|
||||
// DECSCA
|
||||
@@ -526,9 +528,8 @@ export class Parser {
|
||||
// This can cause a small glitch in vim.
|
||||
// test: echo -ne '\eP+q6b64\e\\'
|
||||
case '+q':
|
||||
// TODO: Don't declare pt twice
|
||||
/*let*/ pt = this._terminal.currentParam
|
||||
, valid = false;
|
||||
pt = this._terminal.currentParam;
|
||||
valid = false;
|
||||
|
||||
this._terminal.send(C0.ESC + 'P' + +valid + '+r' + pt + C0.ESC + '\\');
|
||||
break;
|
||||
@@ -563,6 +564,7 @@ export class Parser {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return this._state;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+108
-77
@@ -3,6 +3,7 @@
|
||||
*/
|
||||
|
||||
import { ITerminal } from './Interfaces';
|
||||
import { DomElementObjectPool } from './utils/DomElementObjectPool';
|
||||
|
||||
/**
|
||||
* The maximum number of refresh frames to skip when the write buffer is non-
|
||||
@@ -30,12 +31,15 @@ export class Renderer {
|
||||
private _refreshFramesSkipped = 0;
|
||||
private _refreshAnimationFrame = null;
|
||||
|
||||
private _spanElementObjectPool = new DomElementObjectPool('span');
|
||||
|
||||
constructor(private _terminal: ITerminal) {
|
||||
// Figure out whether boldness affects
|
||||
// the character width of monospace fonts.
|
||||
if (brokenBold === null) {
|
||||
brokenBold = checkBoldBroken((<any>this._terminal).element);
|
||||
}
|
||||
this._spanElementObjectPool = new DomElementObjectPool('span');
|
||||
|
||||
// TODO: Pull more DOM interactions into Renderer.constructor, element for
|
||||
// example should be owned by Renderer (and also exposed by Terminal due to
|
||||
@@ -117,9 +121,8 @@ export class Renderer {
|
||||
* @param {number} end The row to end at (between fromRow and terminal's height terminal - 1)
|
||||
*/
|
||||
private _refresh(start: number, end: number): void {
|
||||
let x, y, i, line, out, ch, ch_width, width, data, attr, bg, fg, flags, row, parent, focused = document.activeElement;
|
||||
|
||||
// If this is a big refresh, remove the terminal rows from the DOM for faster calculations
|
||||
let parent;
|
||||
if (end - start >= this._terminal.rows / 2) {
|
||||
parent = this._terminal.element.parentNode;
|
||||
if (parent) {
|
||||
@@ -127,8 +130,8 @@ export class Renderer {
|
||||
}
|
||||
}
|
||||
|
||||
width = this._terminal.cols;
|
||||
y = start;
|
||||
let width = this._terminal.cols;
|
||||
let y = start;
|
||||
|
||||
if (end >= this._terminal.rows) {
|
||||
this._terminal.log('`end` is too large. Most likely a bad CSR.');
|
||||
@@ -136,80 +139,104 @@ export class Renderer {
|
||||
}
|
||||
|
||||
for (; y <= end; y++) {
|
||||
row = y + this._terminal.ydisp;
|
||||
let row = y + this._terminal.ydisp;
|
||||
|
||||
line = this._terminal.lines.get(row);
|
||||
if (!line || !this._terminal.children[y]) {
|
||||
// Continue if the line is not available, this means a resize is currently in progress
|
||||
continue;
|
||||
}
|
||||
out = '';
|
||||
let line = this._terminal.lines.get(row);
|
||||
|
||||
if (this._terminal.y === y - (this._terminal.ybase - this._terminal.ydisp)
|
||||
&& this._terminal.cursorState
|
||||
&& !this._terminal.cursorHidden) {
|
||||
let x;
|
||||
if (this._terminal.y === y - (this._terminal.ybase - this._terminal.ydisp) &&
|
||||
this._terminal.cursorState &&
|
||||
!this._terminal.cursorHidden) {
|
||||
x = this._terminal.x;
|
||||
} else {
|
||||
x = -1;
|
||||
}
|
||||
|
||||
attr = this._terminal.defAttr;
|
||||
i = 0;
|
||||
let attr = this._terminal.defAttr;
|
||||
|
||||
for (; i < width; i++) {
|
||||
if (!line[i]) {
|
||||
// Continue if the character is not available, this means a resize is currently in progress
|
||||
const documentFragment = document.createDocumentFragment();
|
||||
let innerHTML = '';
|
||||
let currentElement;
|
||||
|
||||
// Return the row's spans to the pool
|
||||
while (this._terminal.children[y].children.length) {
|
||||
const child = this._terminal.children[y].children[0];
|
||||
this._terminal.children[y].removeChild(child);
|
||||
this._spanElementObjectPool.release(<HTMLElement>child);
|
||||
}
|
||||
|
||||
for (let i = 0; i < width; i++) {
|
||||
// TODO: Could data be a more specific type?
|
||||
let data: any = line[i][0];
|
||||
const ch = line[i][1];
|
||||
const ch_width: any = line[i][2];
|
||||
if (!ch_width) {
|
||||
continue;
|
||||
}
|
||||
data = line[i][0];
|
||||
ch = line[i][1];
|
||||
ch_width = line[i][2];
|
||||
if (!ch_width)
|
||||
continue;
|
||||
|
||||
if (i === x) data = -1;
|
||||
if (i === x) {
|
||||
data = -1;
|
||||
}
|
||||
|
||||
if (data !== attr) {
|
||||
if (attr !== this._terminal.defAttr) {
|
||||
out += '</span>';
|
||||
if (innerHTML) {
|
||||
currentElement.innerHTML = innerHTML;
|
||||
innerHTML = '';
|
||||
}
|
||||
documentFragment.appendChild(currentElement);
|
||||
currentElement = null;
|
||||
}
|
||||
if (data !== this._terminal.defAttr) {
|
||||
if (innerHTML && !currentElement) {
|
||||
currentElement = this._spanElementObjectPool.acquire();
|
||||
}
|
||||
if (currentElement) {
|
||||
if (innerHTML) {
|
||||
currentElement.innerHTML = innerHTML;
|
||||
innerHTML = '';
|
||||
}
|
||||
documentFragment.appendChild(currentElement);
|
||||
}
|
||||
currentElement = this._spanElementObjectPool.acquire();
|
||||
if (data === -1) {
|
||||
out += '<span class="reverse-video terminal-cursor">';
|
||||
currentElement.classList.add('reverse-video', 'terminal-cursor');
|
||||
} else {
|
||||
let classNames = [];
|
||||
|
||||
bg = data & 0x1ff;
|
||||
fg = (data >> 9) & 0x1ff;
|
||||
flags = data >> 18;
|
||||
let bg = data & 0x1ff;
|
||||
let fg = (data >> 9) & 0x1ff;
|
||||
let flags = data >> 18;
|
||||
|
||||
if (flags & FLAGS.BOLD) {
|
||||
if (!brokenBold) {
|
||||
classNames.push('xterm-bold');
|
||||
currentElement.classList.add('xterm-bold');
|
||||
}
|
||||
// See: XTerm*boldColors
|
||||
if (fg < 8) fg += 8;
|
||||
if (fg < 8) {
|
||||
fg += 8;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & FLAGS.UNDERLINE) {
|
||||
classNames.push('xterm-underline');
|
||||
currentElement.classList.add('xterm-underline');
|
||||
}
|
||||
|
||||
if (flags & FLAGS.BLINK) {
|
||||
classNames.push('xterm-blink');
|
||||
currentElement.classList.add('xterm-blink');
|
||||
}
|
||||
|
||||
// If inverse flag is on, then swap the foreground and background variables.
|
||||
if (flags & FLAGS.INVERSE) {
|
||||
/* One-line variable swap in JavaScript: http://stackoverflow.com/a/16201730 */
|
||||
bg = [fg, fg = bg][0];
|
||||
// Should inverse just be before the
|
||||
// above boldColors effect instead?
|
||||
if ((flags & 1) && fg < 8) fg += 8;
|
||||
let temp = bg;
|
||||
bg = fg;
|
||||
fg = temp;
|
||||
// Should inverse just be before the above boldColors effect instead?
|
||||
if ((flags & 1) && fg < 8) {
|
||||
fg += 8;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & FLAGS.INVISIBLE) {
|
||||
classNames.push('xterm-hidden');
|
||||
currentElement.classList.add('xterm-hidden');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -229,55 +256,60 @@ export class Renderer {
|
||||
}
|
||||
|
||||
if (bg < 256) {
|
||||
classNames.push('xterm-bg-color-' + bg);
|
||||
currentElement.classList.add(`xterm-bg-color-${bg}`);
|
||||
}
|
||||
|
||||
if (fg < 256) {
|
||||
classNames.push('xterm-color-' + fg);
|
||||
currentElement.classList.add(`xterm-color-${fg}`);
|
||||
}
|
||||
|
||||
out += '<span';
|
||||
if (classNames.length) {
|
||||
out += ' class="' + classNames.join(' ') + '"';
|
||||
}
|
||||
out += '>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ch_width === 2) {
|
||||
out += '<span class="xterm-wide-char">';
|
||||
}
|
||||
switch (ch) {
|
||||
case '&':
|
||||
out += '&';
|
||||
break;
|
||||
case '<':
|
||||
out += '<';
|
||||
break;
|
||||
case '>':
|
||||
out += '>';
|
||||
break;
|
||||
default:
|
||||
if (ch <= ' ') {
|
||||
out += ' ';
|
||||
} else {
|
||||
out += ch;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (ch_width === 2) {
|
||||
out += '</span>';
|
||||
// Wrap wide characters so they're sized correctly. It's more difficult to release these
|
||||
// from the object pool so just create new ones via innerHTML.
|
||||
innerHTML += `<span class="xterm-wide-char">${ch}</span>`;
|
||||
} else if (ch.charCodeAt(0) > 255) {
|
||||
// Wrap any non-wide unicode character as some fonts size them badly
|
||||
innerHTML += `<span class="xterm-normal-char">${ch}</span>`;
|
||||
} else {
|
||||
switch (ch) {
|
||||
case '&':
|
||||
innerHTML += '&';
|
||||
break;
|
||||
case '<':
|
||||
innerHTML += '<';
|
||||
break;
|
||||
case '>':
|
||||
innerHTML += '>';
|
||||
break;
|
||||
default:
|
||||
if (ch <= ' ') {
|
||||
innerHTML += ' ';
|
||||
} else {
|
||||
innerHTML += ch;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
attr = data;
|
||||
}
|
||||
|
||||
if (attr !== this._terminal.defAttr) {
|
||||
out += '</span>';
|
||||
if (innerHTML && !currentElement) {
|
||||
currentElement = this._spanElementObjectPool.acquire();
|
||||
}
|
||||
if (currentElement) {
|
||||
if (innerHTML) {
|
||||
currentElement.innerHTML = innerHTML;
|
||||
innerHTML = '';
|
||||
}
|
||||
documentFragment.appendChild(currentElement);
|
||||
currentElement = null;
|
||||
}
|
||||
|
||||
this._terminal.children[y].innerHTML = out;
|
||||
this._terminal.children[y].appendChild(documentFragment);
|
||||
}
|
||||
|
||||
if (parent) {
|
||||
@@ -289,8 +321,7 @@ export class Renderer {
|
||||
}
|
||||
|
||||
|
||||
// if bold is broken, we can't
|
||||
// use it in the terminal.
|
||||
// If bold is broken, we can't use it in the terminal.
|
||||
function checkBoldBroken(terminal) {
|
||||
const document = terminal.ownerDocument;
|
||||
const el = document.createElement('span');
|
||||
|
||||
@@ -16,3 +16,14 @@ describe('evaluateCopiedTextProcessing', function () {
|
||||
assert.equal(processedText.indexOf(nonBreakingSpace), -1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('evaluatePastedTextProcessing', function () {
|
||||
it('should replace carriage return + line feed with line feed on windows', function () {
|
||||
const pastedText = 'foo\r\nbar\r\n',
|
||||
processedText = Clipboard.prepareTextForTerminal(pastedText, false),
|
||||
windowsProcessedText = Clipboard.prepareTextForTerminal(pastedText, true);
|
||||
|
||||
assert.equal(processedText, 'foo\r\nbar\r\n');
|
||||
assert.equal(windowsProcessedText, 'foo\nbar\n');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -38,6 +38,17 @@ export function prepareTextForClipboard(text: string): string {
|
||||
return processedText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares text to be pasted into the terminal by normalizing the line endings
|
||||
* @param text The pasted text that needs processing before inserting into the terminal
|
||||
*/
|
||||
export function prepareTextForTerminal(text: string, isMSWindows: boolean): string {
|
||||
if (isMSWindows) {
|
||||
return text.replace(/\r?\n/g, '\n');
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds copy functionality to the given terminal.
|
||||
* @param {ClipboardEvent} ev The original copy event to be handled
|
||||
@@ -68,8 +79,11 @@ export function pasteHandler(ev: ClipboardEvent, term: ITerminal) {
|
||||
let text: string;
|
||||
|
||||
let dispatchPaste = function(text) {
|
||||
text = prepareTextForTerminal(text, term.browser.isMSWindows);
|
||||
term.handler(text);
|
||||
term.textarea.value = '';
|
||||
term.emit('paste', text);
|
||||
|
||||
return term.cancel(ev);
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import { assert } from 'chai';
|
||||
import { DomElementObjectPool } from './DomElementObjectPool';
|
||||
|
||||
class MockDocument {
|
||||
private _attr: {[key: string]: string} = {};
|
||||
constructor() {}
|
||||
public getAttribute(key: string): string { return this._attr[key]; };
|
||||
public setAttribute(key: string, value: string): void { this._attr[key] = value; }
|
||||
}
|
||||
|
||||
describe('DomElementObjectPool', () => {
|
||||
let pool: DomElementObjectPool;
|
||||
|
||||
beforeEach(() => {
|
||||
pool = new DomElementObjectPool('span');
|
||||
(<any>global).document = {
|
||||
createElement: () => new MockDocument()
|
||||
};
|
||||
});
|
||||
|
||||
it('should acquire distinct elements', () => {
|
||||
const element1 = pool.acquire();
|
||||
const element2 = pool.acquire();
|
||||
assert.notEqual(element1, element2);
|
||||
});
|
||||
|
||||
it('should acquire released elements', () => {
|
||||
const element = pool.acquire();
|
||||
pool.release(element);
|
||||
assert.equal(pool.acquire(), element);
|
||||
});
|
||||
|
||||
it('should handle a series of acquisitions and releases', () => {
|
||||
const element1 = pool.acquire();
|
||||
const element2 = pool.acquire();
|
||||
pool.release(element1);
|
||||
assert.equal(pool.acquire(), element1);
|
||||
pool.release(element1);
|
||||
pool.release(element2);
|
||||
assert.equal(pool.acquire(), element2);
|
||||
assert.equal(pool.acquire(), element1);
|
||||
});
|
||||
|
||||
it('should throw when releasing an element that was not acquired', () => {
|
||||
assert.throws(() => pool.release(document.createElement('span')));
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* @module xterm/utils/DomElementObjectPool
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* An object pool that manages acquisition and releasing of DOM elements for
|
||||
* when reuse is desirable.
|
||||
*/
|
||||
export class DomElementObjectPool {
|
||||
private static readonly OBJECT_ID_ATTRIBUTE = 'data-obj-id';
|
||||
|
||||
private static _objectCount = 0;
|
||||
|
||||
private _type: string;
|
||||
private _pool: HTMLElement[];
|
||||
private _inUse: {[key: string]: HTMLElement};
|
||||
|
||||
/**
|
||||
* @param type The DOM element type (div, span, etc.).
|
||||
*/
|
||||
constructor(private type: string) {
|
||||
this._type = type;
|
||||
this._pool = [];
|
||||
this._inUse = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Acquire an element from the pool, creating it if the pool is empty.
|
||||
*/
|
||||
public acquire(): HTMLElement {
|
||||
let element: HTMLElement;
|
||||
if (this._pool.length === 0) {
|
||||
element = this._createNew();
|
||||
} else {
|
||||
element = this._pool.pop();
|
||||
}
|
||||
this._inUse[element.getAttribute(DomElementObjectPool.OBJECT_ID_ATTRIBUTE)] = element;
|
||||
return element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Release an element back into the pool. It's up to the caller of this
|
||||
* function to ensure that all external references to the element have been
|
||||
* removed.
|
||||
* @param element The element being released.
|
||||
*/
|
||||
public release(element: HTMLElement): void {
|
||||
if (!this._inUse[element.getAttribute(DomElementObjectPool.OBJECT_ID_ATTRIBUTE)]) {
|
||||
throw new Error('Could not release an element not yet acquired');
|
||||
}
|
||||
delete this._inUse[element.getAttribute(DomElementObjectPool.OBJECT_ID_ATTRIBUTE)];
|
||||
this._cleanElement(element);
|
||||
this._pool.push(element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new element for the pool.
|
||||
*/
|
||||
private _createNew(): HTMLElement {
|
||||
const element = document.createElement(this._type);
|
||||
const id = DomElementObjectPool._objectCount++;
|
||||
element.setAttribute(DomElementObjectPool.OBJECT_ID_ATTRIBUTE, id.toString(10));
|
||||
return element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets an element back to a "clean state".
|
||||
* @param element The element to be cleaned.
|
||||
*/
|
||||
private _cleanElement(element: HTMLElement): void {
|
||||
element.className = '';
|
||||
element.innerHTML = '';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { CharMeasure } from './CharMeasure';
|
||||
|
||||
/**
|
||||
* Gets coordinates within the terminal for a particular mouse event. The result
|
||||
* is returned as an array in the form [x, y] instead of an object as it's a
|
||||
* little faster and this function is used in some low level code.
|
||||
* @param event The mouse event.
|
||||
* @param rowContainer The terminal's row container.
|
||||
* @param charMeasure The char measure object used to determine character sizes.
|
||||
*/
|
||||
export function getCoords(event: MouseEvent, rowContainer: HTMLElement, charMeasure: CharMeasure): [number, number] {
|
||||
// Ignore browsers that don't support MouseEvent.pageX
|
||||
if (event.pageX == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let x = event.pageX;
|
||||
let y = event.pageY;
|
||||
let el = rowContainer;
|
||||
|
||||
// Converts the coordinates from being relative to the document to being
|
||||
// relative to the terminal.
|
||||
while (el && el !== self.document.documentElement) {
|
||||
x -= el.offsetLeft;
|
||||
y -= el.offsetTop;
|
||||
el = 'offsetParent' in el ? <HTMLElement>el.offsetParent : <HTMLElement>el.parentElement;
|
||||
}
|
||||
|
||||
// Convert to cols/rows
|
||||
x = Math.ceil(x / charMeasure.width);
|
||||
y = Math.ceil(y / charMeasure.height);
|
||||
|
||||
return [x, y];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets coordinates within the terminal for a particular mouse event, wrapping
|
||||
* them to the bounds of the terminal and adding 32 to both the x and y values
|
||||
* as expected by xterm.
|
||||
* @param event The mouse event.
|
||||
* @param rowContainer The terminal's row container.
|
||||
* @param charMeasure The char measure object used to determine character sizes.
|
||||
* @param colCount The number of columns in the terminal.
|
||||
* @param rowCount The number of rows in the terminal.
|
||||
*/
|
||||
export function getRawByteCoords(event: MouseEvent, rowContainer: HTMLElement, charMeasure: CharMeasure, colCount: number, rowCount: number): { x: number, y: number } {
|
||||
const coords = getCoords(event, rowContainer, charMeasure);
|
||||
let x = coords[0];
|
||||
let y = coords[1];
|
||||
|
||||
// Ensure coordinates are within the terminal viewport.
|
||||
x = Math.min(Math.max(x, 0), colCount);
|
||||
y = Math.min(Math.max(y, 0), rowCount);
|
||||
|
||||
// xterm sends raw bytes and starts at 32 (SP) for each.
|
||||
x += 32;
|
||||
y += 32;
|
||||
|
||||
return { x, y };
|
||||
}
|
||||
+2
-1
@@ -153,7 +153,8 @@
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.terminal .xterm-wide-char {
|
||||
.terminal .xterm-wide-char,
|
||||
.terminal .xterm-normal-char {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
|
||||
+13
-48
@@ -24,6 +24,7 @@ import { CharMeasure } from './utils/CharMeasure';
|
||||
import * as Browser from './utils/Browser';
|
||||
import * as Keyboard from './utils/Keyboard';
|
||||
import { CHARSETS } from './Charsets';
|
||||
import { getRawByteCoords } from './utils/Mouse';
|
||||
|
||||
/**
|
||||
* Terminal Emulation References:
|
||||
@@ -760,7 +761,9 @@ Terminal.loadAddon = function(addon, callback) {
|
||||
* character width has been changed.
|
||||
*/
|
||||
Terminal.prototype.updateCharSizeCSS = function() {
|
||||
this.charSizeStyleElement.textContent = '.xterm-wide-char{width:' + (this.charMeasure.width * 2) + 'px;}';
|
||||
this.charSizeStyleElement.textContent =
|
||||
`.xterm-wide-char{width:${this.charMeasure.width * 2}px;}` +
|
||||
`.xterm-normal-char{width:${this.charMeasure.width}px;}`
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -787,7 +790,7 @@ Terminal.prototype.bindMouse = function() {
|
||||
button = getButton(ev);
|
||||
|
||||
// get mouse coordinates
|
||||
pos = getCoords(ev);
|
||||
pos = getRawByteCoords(ev, self.rowContainer, self.charMeasure, self.cols, self.rows);
|
||||
if (!pos) return;
|
||||
|
||||
sendEvent(button, pos);
|
||||
@@ -815,7 +818,7 @@ Terminal.prototype.bindMouse = function() {
|
||||
var button = pressed
|
||||
, pos;
|
||||
|
||||
pos = getCoords(ev);
|
||||
pos = getRawByteCoords(ev, self.rowContainer, self.charMeasure, self.cols, self.rows);
|
||||
if (!pos) return;
|
||||
|
||||
// buttons marked as motions
|
||||
@@ -990,50 +993,6 @@ Terminal.prototype.bindMouse = function() {
|
||||
return button;
|
||||
}
|
||||
|
||||
// mouse coordinates measured in cols/rows
|
||||
function getCoords(ev) {
|
||||
var x, y, w, h, el;
|
||||
|
||||
// ignore browsers without pageX for now
|
||||
if (ev.pageX == null) return;
|
||||
|
||||
x = ev.pageX;
|
||||
y = ev.pageY;
|
||||
el = self.element;
|
||||
|
||||
// should probably check offsetParent
|
||||
// but this is more portable
|
||||
while (el && el !== self.document.documentElement) {
|
||||
x -= el.offsetLeft;
|
||||
y -= el.offsetTop;
|
||||
el = 'offsetParent' in el
|
||||
? el.offsetParent
|
||||
: el.parentNode;
|
||||
}
|
||||
|
||||
// convert to cols/rows
|
||||
x = Math.ceil(x / self.charMeasure.width);
|
||||
y = Math.ceil(y / self.charMeasure.height);
|
||||
|
||||
// be sure to avoid sending
|
||||
// bad positions to the program
|
||||
if (x < 0) x = 0;
|
||||
if (x > self.cols) x = self.cols;
|
||||
if (y < 0) y = 0;
|
||||
if (y > self.rows) y = self.rows;
|
||||
|
||||
// xterm sends raw bytes and
|
||||
// starts at 32 (SP) for each.
|
||||
x += 32;
|
||||
y += 32;
|
||||
|
||||
return {
|
||||
x: x,
|
||||
y: y,
|
||||
type: 'wheel'
|
||||
};
|
||||
}
|
||||
|
||||
on(el, 'mousedown', function(ev) {
|
||||
if (!self.mouseEvents) return;
|
||||
|
||||
@@ -1293,7 +1252,13 @@ Terminal.prototype.innerWrite = function() {
|
||||
this.refreshStart = this.y;
|
||||
this.refreshEnd = this.y;
|
||||
|
||||
this.parser.parse(data);
|
||||
// HACK: Set the parser state based on it's state at the time of return.
|
||||
// This works around the bug #662 which saw the parser state reset in the
|
||||
// middle of parsing escape sequence in two chunks. For some reason the
|
||||
// state of the parser resets to 0 after exiting parser.parse. This change
|
||||
// just sets the state back based on the correct return statement.
|
||||
var state = this.parser.parse(data);
|
||||
this.parser.setState(state);
|
||||
|
||||
this.updateRange(this.y);
|
||||
this.refresh(this.refreshStart, this.refreshEnd);
|
||||
|
||||
Reference in New Issue
Block a user