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>
|
imoses <ido@twiggle.com>
|
||||||
InDieTasten <indietasten@gmail.com>
|
InDieTasten <indietasten@gmail.com>
|
||||||
Jean Bruenn <himself@jeanbruenn.info>
|
Jean Bruenn <himself@jeanbruenn.info>
|
||||||
|
Jeremy Danyow <jedanyow@microsoft.com>
|
||||||
Jörg Breitbart <jerch@rockborn.de>
|
Jörg Breitbart <jerch@rockborn.de>
|
||||||
Justin Mecham <justin@mecham.me>
|
Justin Mecham <justin@mecham.me>
|
||||||
Lucian Buzzo <lucian.buzzo@gmail.com>
|
Lucian Buzzo <lucian.buzzo@gmail.com>
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "xterm.js",
|
"name": "xterm.js",
|
||||||
"version": "2.6.0",
|
"version": "2.7.0",
|
||||||
"ignore": ["demo", "test", ".gitignore"],
|
"ignore": ["demo", "test", ".gitignore"],
|
||||||
"main": [
|
"main": [
|
||||||
"dist/xterm.js",
|
"dist/xterm.js",
|
||||||
|
|||||||
Vendored
+2
-1
@@ -153,7 +153,8 @@
|
|||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
.terminal .xterm-wide-char {
|
.terminal .xterm-wide-char,
|
||||||
|
.terminal .xterm-normal-char {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Vendored
+209
-110
@@ -372,10 +372,13 @@ var EventEmitter = (function () {
|
|||||||
return this.on(type, on);
|
return this.on(type, on);
|
||||||
};
|
};
|
||||||
EventEmitter.prototype.emit = function (type) {
|
EventEmitter.prototype.emit = function (type) {
|
||||||
|
var args = [];
|
||||||
|
for (var _i = 1; _i < arguments.length; _i++) {
|
||||||
|
args[_i - 1] = arguments[_i];
|
||||||
|
}
|
||||||
if (!this._events[type]) {
|
if (!this._events[type]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var args = Array.prototype.slice.call(arguments, 1);
|
|
||||||
var obj = this._events[type];
|
var obj = this._events[type];
|
||||||
for (var i = 0; i < obj.length; i++) {
|
for (var i = 0; i < obj.length; i++) {
|
||||||
obj[i].apply(this, args);
|
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 || ch === EscapeSequences_1.C0.BEL) {
|
||||||
if (ch === EscapeSequences_1.C0.ESC)
|
if (ch === EscapeSequences_1.C0.ESC)
|
||||||
this._position++;
|
this._position++;
|
||||||
|
var pt = void 0;
|
||||||
|
var valid = void 0;
|
||||||
switch (this._terminal.prefix) {
|
switch (this._terminal.prefix) {
|
||||||
case '':
|
case '':
|
||||||
break;
|
break;
|
||||||
case '$q':
|
case '$q':
|
||||||
var pt = this._terminal.currentParam, valid = false;
|
pt = this._terminal.currentParam;
|
||||||
|
valid = false;
|
||||||
switch (pt) {
|
switch (pt) {
|
||||||
case '"q':
|
case '"q':
|
||||||
pt = '0"q';
|
pt = '0"q';
|
||||||
@@ -1960,8 +1966,8 @@ var Parser = (function () {
|
|||||||
case '+p':
|
case '+p':
|
||||||
break;
|
break;
|
||||||
case '+q':
|
case '+q':
|
||||||
pt = this._terminal.currentParam
|
pt = this._terminal.currentParam;
|
||||||
, valid = false;
|
valid = false;
|
||||||
this._terminal.send(EscapeSequences_1.C0.ESC + 'P' + +valid + '+r' + pt + EscapeSequences_1.C0.ESC + '\\');
|
this._terminal.send(EscapeSequences_1.C0.ESC + 'P' + +valid + '+r' + pt + EscapeSequences_1.C0.ESC + '\\');
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -1996,6 +2002,7 @@ var Parser = (function () {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return this._state;
|
||||||
};
|
};
|
||||||
Parser.prototype.setState = function (state) {
|
Parser.prototype.setState = function (state) {
|
||||||
this._state = state;
|
this._state = state;
|
||||||
@@ -2028,6 +2035,7 @@ exports.Parser = Parser;
|
|||||||
},{"./Charsets":1,"./EscapeSequences":3}],8:[function(require,module,exports){
|
},{"./Charsets":1,"./EscapeSequences":3}],8:[function(require,module,exports){
|
||||||
"use strict";
|
"use strict";
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
var DomElementObjectPool_1 = require("./utils/DomElementObjectPool");
|
||||||
var MAX_REFRESH_FRAME_SKIP = 5;
|
var MAX_REFRESH_FRAME_SKIP = 5;
|
||||||
var FLAGS;
|
var FLAGS;
|
||||||
(function (FLAGS) {
|
(function (FLAGS) {
|
||||||
@@ -2045,9 +2053,11 @@ var Renderer = (function () {
|
|||||||
this._refreshRowsQueue = [];
|
this._refreshRowsQueue = [];
|
||||||
this._refreshFramesSkipped = 0;
|
this._refreshFramesSkipped = 0;
|
||||||
this._refreshAnimationFrame = null;
|
this._refreshAnimationFrame = null;
|
||||||
|
this._spanElementObjectPool = new DomElementObjectPool_1.DomElementObjectPool('span');
|
||||||
if (brokenBold === null) {
|
if (brokenBold === null) {
|
||||||
brokenBold = checkBoldBroken(this._terminal.element);
|
brokenBold = checkBoldBroken(this._terminal.element);
|
||||||
}
|
}
|
||||||
|
this._spanElementObjectPool = new DomElementObjectPool_1.DomElementObjectPool('span');
|
||||||
}
|
}
|
||||||
Renderer.prototype.queueRefresh = function (start, end) {
|
Renderer.prototype.queueRefresh = function (start, end) {
|
||||||
this._refreshRowsQueue.push({ start: start, end: end });
|
this._refreshRowsQueue.push({ start: start, end: end });
|
||||||
@@ -2085,80 +2095,102 @@ var Renderer = (function () {
|
|||||||
this._refresh(start, end);
|
this._refresh(start, end);
|
||||||
};
|
};
|
||||||
Renderer.prototype._refresh = function (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) {
|
if (end - start >= this._terminal.rows / 2) {
|
||||||
parent = this._terminal.element.parentNode;
|
parent = this._terminal.element.parentNode;
|
||||||
if (parent) {
|
if (parent) {
|
||||||
this._terminal.element.removeChild(this._terminal.rowContainer);
|
this._terminal.element.removeChild(this._terminal.rowContainer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
width = this._terminal.cols;
|
var width = this._terminal.cols;
|
||||||
y = start;
|
var y = start;
|
||||||
if (end >= this._terminal.rows) {
|
if (end >= this._terminal.rows) {
|
||||||
this._terminal.log('`end` is too large. Most likely a bad CSR.');
|
this._terminal.log('`end` is too large. Most likely a bad CSR.');
|
||||||
end = this._terminal.rows - 1;
|
end = this._terminal.rows - 1;
|
||||||
}
|
}
|
||||||
for (; y <= end; y++) {
|
for (; y <= end; y++) {
|
||||||
row = y + this._terminal.ydisp;
|
var row = y + this._terminal.ydisp;
|
||||||
line = this._terminal.lines.get(row);
|
var line = this._terminal.lines.get(row);
|
||||||
if (!line || !this._terminal.children[y]) {
|
var x = void 0;
|
||||||
continue;
|
if (this._terminal.y === y - (this._terminal.ybase - this._terminal.ydisp) &&
|
||||||
}
|
this._terminal.cursorState &&
|
||||||
out = '';
|
!this._terminal.cursorHidden) {
|
||||||
if (this._terminal.y === y - (this._terminal.ybase - this._terminal.ydisp)
|
|
||||||
&& this._terminal.cursorState
|
|
||||||
&& !this._terminal.cursorHidden) {
|
|
||||||
x = this._terminal.x;
|
x = this._terminal.x;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
x = -1;
|
x = -1;
|
||||||
}
|
}
|
||||||
attr = this._terminal.defAttr;
|
var attr = this._terminal.defAttr;
|
||||||
i = 0;
|
var documentFragment = document.createDocumentFragment();
|
||||||
for (; i < width; i++) {
|
var innerHTML = '';
|
||||||
if (!line[i]) {
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
data = line[i][0];
|
if (i === x) {
|
||||||
ch = line[i][1];
|
|
||||||
ch_width = line[i][2];
|
|
||||||
if (!ch_width)
|
|
||||||
continue;
|
|
||||||
if (i === x)
|
|
||||||
data = -1;
|
data = -1;
|
||||||
|
}
|
||||||
if (data !== attr) {
|
if (data !== attr) {
|
||||||
if (attr !== this._terminal.defAttr) {
|
if (attr !== this._terminal.defAttr) {
|
||||||
out += '</span>';
|
if (innerHTML) {
|
||||||
|
currentElement.innerHTML = innerHTML;
|
||||||
|
innerHTML = '';
|
||||||
|
}
|
||||||
|
documentFragment.appendChild(currentElement);
|
||||||
|
currentElement = null;
|
||||||
}
|
}
|
||||||
if (data !== this._terminal.defAttr) {
|
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) {
|
if (data === -1) {
|
||||||
out += '<span class="reverse-video terminal-cursor">';
|
currentElement.classList.add('reverse-video', 'terminal-cursor');
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
var classNames = [];
|
var bg = data & 0x1ff;
|
||||||
bg = data & 0x1ff;
|
var fg = (data >> 9) & 0x1ff;
|
||||||
fg = (data >> 9) & 0x1ff;
|
var flags = data >> 18;
|
||||||
flags = data >> 18;
|
|
||||||
if (flags & FLAGS.BOLD) {
|
if (flags & FLAGS.BOLD) {
|
||||||
if (!brokenBold) {
|
if (!brokenBold) {
|
||||||
classNames.push('xterm-bold');
|
currentElement.classList.add('xterm-bold');
|
||||||
}
|
}
|
||||||
if (fg < 8)
|
if (fg < 8) {
|
||||||
fg += 8;
|
fg += 8;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (flags & FLAGS.UNDERLINE) {
|
if (flags & FLAGS.UNDERLINE) {
|
||||||
classNames.push('xterm-underline');
|
currentElement.classList.add('xterm-underline');
|
||||||
}
|
}
|
||||||
if (flags & FLAGS.BLINK) {
|
if (flags & FLAGS.BLINK) {
|
||||||
classNames.push('xterm-blink');
|
currentElement.classList.add('xterm-blink');
|
||||||
}
|
}
|
||||||
if (flags & FLAGS.INVERSE) {
|
if (flags & FLAGS.INVERSE) {
|
||||||
bg = [fg, fg = bg][0];
|
var temp = bg;
|
||||||
if ((flags & 1) && fg < 8)
|
bg = fg;
|
||||||
|
fg = temp;
|
||||||
|
if ((flags & 1) && fg < 8) {
|
||||||
fg += 8;
|
fg += 8;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (flags & FLAGS.INVISIBLE) {
|
if (flags & FLAGS.INVISIBLE) {
|
||||||
classNames.push('xterm-hidden');
|
currentElement.classList.add('xterm-hidden');
|
||||||
}
|
}
|
||||||
if (flags & FLAGS.INVERSE) {
|
if (flags & FLAGS.INVERSE) {
|
||||||
if (bg === 257) {
|
if (bg === 257) {
|
||||||
@@ -2169,50 +2201,55 @@ var Renderer = (function () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (bg < 256) {
|
if (bg < 256) {
|
||||||
classNames.push('xterm-bg-color-' + bg);
|
currentElement.classList.add("xterm-bg-color-" + bg);
|
||||||
}
|
}
|
||||||
if (fg < 256) {
|
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) {
|
if (ch_width === 2) {
|
||||||
out += '<span class="xterm-wide-char">';
|
innerHTML += "<span class=\"xterm-wide-char\">" + ch + "</span>";
|
||||||
}
|
}
|
||||||
switch (ch) {
|
else if (ch.charCodeAt(0) > 255) {
|
||||||
case '&':
|
innerHTML += "<span class=\"xterm-normal-char\">" + ch + "</span>";
|
||||||
out += '&';
|
|
||||||
break;
|
|
||||||
case '<':
|
|
||||||
out += '<';
|
|
||||||
break;
|
|
||||||
case '>':
|
|
||||||
out += '>';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (ch <= ' ') {
|
|
||||||
out += ' ';
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
out += ch;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
if (ch_width === 2) {
|
else {
|
||||||
out += '</span>';
|
switch (ch) {
|
||||||
|
case '&':
|
||||||
|
innerHTML += '&';
|
||||||
|
break;
|
||||||
|
case '<':
|
||||||
|
innerHTML += '<';
|
||||||
|
break;
|
||||||
|
case '>':
|
||||||
|
innerHTML += '>';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (ch <= ' ') {
|
||||||
|
innerHTML += ' ';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
innerHTML += ch;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
attr = data;
|
attr = data;
|
||||||
}
|
}
|
||||||
if (attr !== this._terminal.defAttr) {
|
if (innerHTML && !currentElement) {
|
||||||
out += '</span>';
|
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) {
|
if (parent) {
|
||||||
this._terminal.element.appendChild(this._terminal.rowContainer);
|
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";
|
"use strict";
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
var Viewport = (function () {
|
var Viewport = (function () {
|
||||||
@@ -2328,6 +2365,13 @@ function prepareTextForClipboard(text) {
|
|||||||
return processedText;
|
return processedText;
|
||||||
}
|
}
|
||||||
exports.prepareTextForClipboard = prepareTextForClipboard;
|
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) {
|
function copyHandler(ev, term) {
|
||||||
var copiedText = window.getSelection().toString(), text = prepareTextForClipboard(copiedText);
|
var copiedText = window.getSelection().toString(), text = prepareTextForClipboard(copiedText);
|
||||||
if (term.browser.isMSIE) {
|
if (term.browser.isMSIE) {
|
||||||
@@ -2343,8 +2387,10 @@ function pasteHandler(ev, term) {
|
|||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
var text;
|
var text;
|
||||||
var dispatchPaste = function (text) {
|
var dispatchPaste = function (text) {
|
||||||
|
text = prepareTextForTerminal(text, term.browser.isMSWindows);
|
||||||
term.handler(text);
|
term.handler(text);
|
||||||
term.textarea.value = '';
|
term.textarea.value = '';
|
||||||
|
term.emit('paste', text);
|
||||||
return term.cancel(ev);
|
return term.cancel(ev);
|
||||||
};
|
};
|
||||||
if (term.browser.isMSIE) {
|
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";
|
"use strict";
|
||||||
var __extends = (this && this.__extends) || (function () {
|
var __extends = (this && this.__extends) || (function () {
|
||||||
var extendStatics = Object.setPrototypeOf ||
|
var extendStatics = Object.setPrototypeOf ||
|
||||||
@@ -2626,6 +2672,53 @@ exports.CircularList = CircularList;
|
|||||||
},{}],14:[function(require,module,exports){
|
},{}],14:[function(require,module,exports){
|
||||||
"use strict";
|
"use strict";
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
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) {
|
function contains(arr, el) {
|
||||||
return arr.indexOf(el) >= 0;
|
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";
|
"use strict";
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
var CompositionHelper_1 = require("./CompositionHelper");
|
var CompositionHelper_1 = require("./CompositionHelper");
|
||||||
@@ -2649,6 +2776,7 @@ var Renderer_1 = require("./Renderer");
|
|||||||
var Linkifier_1 = require("./Linkifier");
|
var Linkifier_1 = require("./Linkifier");
|
||||||
var CharMeasure_1 = require("./utils/CharMeasure");
|
var CharMeasure_1 = require("./utils/CharMeasure");
|
||||||
var Browser = require("./utils/Browser");
|
var Browser = require("./utils/Browser");
|
||||||
|
var Mouse_1 = require("./utils/Mouse");
|
||||||
var document = (typeof window != 'undefined') ? window.document : null;
|
var document = (typeof window != 'undefined') ? window.document : null;
|
||||||
var WRITE_BUFFER_PAUSE_THRESHOLD = 5;
|
var WRITE_BUFFER_PAUSE_THRESHOLD = 5;
|
||||||
var WRITE_BATCH_SIZE = 300;
|
var WRITE_BATCH_SIZE = 300;
|
||||||
@@ -3102,14 +3230,16 @@ Terminal.loadAddon = function (addon, callback) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
Terminal.prototype.updateCharSizeCSS = function () {
|
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 () {
|
Terminal.prototype.bindMouse = function () {
|
||||||
var el = this.element, self = this, pressed = 32;
|
var el = this.element, self = this, pressed = 32;
|
||||||
function sendButton(ev) {
|
function sendButton(ev) {
|
||||||
var button, pos;
|
var button, pos;
|
||||||
button = getButton(ev);
|
button = getButton(ev);
|
||||||
pos = getCoords(ev);
|
pos = Mouse_1.getRawByteCoords(ev, self.rowContainer, self.charMeasure, self.cols, self.rows);
|
||||||
if (!pos)
|
if (!pos)
|
||||||
return;
|
return;
|
||||||
sendEvent(button, pos);
|
sendEvent(button, pos);
|
||||||
@@ -3126,7 +3256,7 @@ Terminal.prototype.bindMouse = function () {
|
|||||||
}
|
}
|
||||||
function sendMove(ev) {
|
function sendMove(ev) {
|
||||||
var button = pressed, pos;
|
var button = pressed, pos;
|
||||||
pos = getCoords(ev);
|
pos = Mouse_1.getRawByteCoords(ev, self.rowContainer, self.charMeasure, self.cols, self.rows);
|
||||||
if (!pos)
|
if (!pos)
|
||||||
return;
|
return;
|
||||||
button += 32;
|
button += 32;
|
||||||
@@ -3265,38 +3395,6 @@ Terminal.prototype.bindMouse = function () {
|
|||||||
button = (32 + (mod << 2)) + button;
|
button = (32 + (mod << 2)) + button;
|
||||||
return 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) {
|
on(el, 'mousedown', function (ev) {
|
||||||
if (!self.mouseEvents)
|
if (!self.mouseEvents)
|
||||||
return;
|
return;
|
||||||
@@ -3452,7 +3550,8 @@ Terminal.prototype.innerWrite = function () {
|
|||||||
}
|
}
|
||||||
this.refreshStart = this.y;
|
this.refreshStart = this.y;
|
||||||
this.refreshEnd = 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.updateRange(this.y);
|
||||||
this.refresh(this.refreshStart, this.refreshEnd);
|
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
|
//# 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",
|
"name": "xterm",
|
||||||
"description": "Full xterm terminal, in your browser",
|
"description": "Full xterm terminal, in your browser",
|
||||||
"version": "2.6.0",
|
"version": "2.7.0",
|
||||||
"ignore": [
|
"ignore": [
|
||||||
"demo",
|
"demo",
|
||||||
"test",
|
"test",
|
||||||
|
|||||||
+1
-4
@@ -53,14 +53,11 @@ export class EventEmitter {
|
|||||||
return this.on(type, on);
|
return this.on(type, on);
|
||||||
}
|
}
|
||||||
|
|
||||||
public emit(type): void {
|
public emit(type: string, ...args: any[]): void {
|
||||||
if (!this._events[type]) {
|
if (!this._events[type]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let args = Array.prototype.slice.call(arguments, 1);
|
|
||||||
let obj = this._events[type];
|
let obj = this._events[type];
|
||||||
|
|
||||||
for (let i = 0; i < obj.length; i++) {
|
for (let i = 0; i < obj.length; i++) {
|
||||||
obj[i].apply(this, args);
|
obj[i].apply(this, args);
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-6
@@ -181,7 +181,7 @@ export class Parser {
|
|||||||
*
|
*
|
||||||
* @param data The data to parse.
|
* @param data The data to parse.
|
||||||
*/
|
*/
|
||||||
public parse(data: string) {
|
public parse(data: string): ParserState {
|
||||||
let l = data.length, j, cs, ch, code, low;
|
let l = data.length, j, cs, ch, code, low;
|
||||||
|
|
||||||
this._position = 0;
|
this._position = 0;
|
||||||
@@ -471,6 +471,8 @@ export class Parser {
|
|||||||
case ParserState.DCS:
|
case ParserState.DCS:
|
||||||
if (ch === C0.ESC || ch === C0.BEL) {
|
if (ch === C0.ESC || ch === C0.BEL) {
|
||||||
if (ch === C0.ESC) this._position++;
|
if (ch === C0.ESC) this._position++;
|
||||||
|
let pt;
|
||||||
|
let valid: boolean;
|
||||||
|
|
||||||
switch (this._terminal.prefix) {
|
switch (this._terminal.prefix) {
|
||||||
// User-Defined Keys (DECUDK).
|
// User-Defined Keys (DECUDK).
|
||||||
@@ -480,8 +482,8 @@ export class Parser {
|
|||||||
// Request Status String (DECRQSS).
|
// Request Status String (DECRQSS).
|
||||||
// test: echo -e '\eP$q"p\e\\'
|
// test: echo -e '\eP$q"p\e\\'
|
||||||
case '$q':
|
case '$q':
|
||||||
let pt = this._terminal.currentParam
|
pt = this._terminal.currentParam;
|
||||||
, valid = false;
|
valid = false;
|
||||||
|
|
||||||
switch (pt) {
|
switch (pt) {
|
||||||
// DECSCA
|
// DECSCA
|
||||||
@@ -526,9 +528,8 @@ export class Parser {
|
|||||||
// This can cause a small glitch in vim.
|
// This can cause a small glitch in vim.
|
||||||
// test: echo -ne '\eP+q6b64\e\\'
|
// test: echo -ne '\eP+q6b64\e\\'
|
||||||
case '+q':
|
case '+q':
|
||||||
// TODO: Don't declare pt twice
|
pt = this._terminal.currentParam;
|
||||||
/*let*/ pt = this._terminal.currentParam
|
valid = false;
|
||||||
, valid = false;
|
|
||||||
|
|
||||||
this._terminal.send(C0.ESC + 'P' + +valid + '+r' + pt + C0.ESC + '\\');
|
this._terminal.send(C0.ESC + 'P' + +valid + '+r' + pt + C0.ESC + '\\');
|
||||||
break;
|
break;
|
||||||
@@ -563,6 +564,7 @@ export class Parser {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return this._state;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+108
-77
@@ -3,6 +3,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { ITerminal } from './Interfaces';
|
import { ITerminal } from './Interfaces';
|
||||||
|
import { DomElementObjectPool } from './utils/DomElementObjectPool';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The maximum number of refresh frames to skip when the write buffer is non-
|
* 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 _refreshFramesSkipped = 0;
|
||||||
private _refreshAnimationFrame = null;
|
private _refreshAnimationFrame = null;
|
||||||
|
|
||||||
|
private _spanElementObjectPool = new DomElementObjectPool('span');
|
||||||
|
|
||||||
constructor(private _terminal: ITerminal) {
|
constructor(private _terminal: ITerminal) {
|
||||||
// Figure out whether boldness affects
|
// Figure out whether boldness affects
|
||||||
// the character width of monospace fonts.
|
// the character width of monospace fonts.
|
||||||
if (brokenBold === null) {
|
if (brokenBold === null) {
|
||||||
brokenBold = checkBoldBroken((<any>this._terminal).element);
|
brokenBold = checkBoldBroken((<any>this._terminal).element);
|
||||||
}
|
}
|
||||||
|
this._spanElementObjectPool = new DomElementObjectPool('span');
|
||||||
|
|
||||||
// TODO: Pull more DOM interactions into Renderer.constructor, element for
|
// TODO: Pull more DOM interactions into Renderer.constructor, element for
|
||||||
// example should be owned by Renderer (and also exposed by Terminal due to
|
// 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)
|
* @param {number} end The row to end at (between fromRow and terminal's height terminal - 1)
|
||||||
*/
|
*/
|
||||||
private _refresh(start: number, end: number): void {
|
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
|
// 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) {
|
if (end - start >= this._terminal.rows / 2) {
|
||||||
parent = this._terminal.element.parentNode;
|
parent = this._terminal.element.parentNode;
|
||||||
if (parent) {
|
if (parent) {
|
||||||
@@ -127,8 +130,8 @@ export class Renderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
width = this._terminal.cols;
|
let width = this._terminal.cols;
|
||||||
y = start;
|
let y = start;
|
||||||
|
|
||||||
if (end >= this._terminal.rows) {
|
if (end >= this._terminal.rows) {
|
||||||
this._terminal.log('`end` is too large. Most likely a bad CSR.');
|
this._terminal.log('`end` is too large. Most likely a bad CSR.');
|
||||||
@@ -136,80 +139,104 @@ export class Renderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (; y <= end; y++) {
|
for (; y <= end; y++) {
|
||||||
row = y + this._terminal.ydisp;
|
let row = y + this._terminal.ydisp;
|
||||||
|
|
||||||
line = this._terminal.lines.get(row);
|
let 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 = '';
|
|
||||||
|
|
||||||
if (this._terminal.y === y - (this._terminal.ybase - this._terminal.ydisp)
|
let x;
|
||||||
&& this._terminal.cursorState
|
if (this._terminal.y === y - (this._terminal.ybase - this._terminal.ydisp) &&
|
||||||
&& !this._terminal.cursorHidden) {
|
this._terminal.cursorState &&
|
||||||
|
!this._terminal.cursorHidden) {
|
||||||
x = this._terminal.x;
|
x = this._terminal.x;
|
||||||
} else {
|
} else {
|
||||||
x = -1;
|
x = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
attr = this._terminal.defAttr;
|
let attr = this._terminal.defAttr;
|
||||||
i = 0;
|
|
||||||
|
|
||||||
for (; i < width; i++) {
|
const documentFragment = document.createDocumentFragment();
|
||||||
if (!line[i]) {
|
let innerHTML = '';
|
||||||
// Continue if the character is not available, this means a resize is currently in progress
|
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;
|
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 (data !== attr) {
|
||||||
if (attr !== this._terminal.defAttr) {
|
if (attr !== this._terminal.defAttr) {
|
||||||
out += '</span>';
|
if (innerHTML) {
|
||||||
|
currentElement.innerHTML = innerHTML;
|
||||||
|
innerHTML = '';
|
||||||
|
}
|
||||||
|
documentFragment.appendChild(currentElement);
|
||||||
|
currentElement = null;
|
||||||
}
|
}
|
||||||
if (data !== this._terminal.defAttr) {
|
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) {
|
if (data === -1) {
|
||||||
out += '<span class="reverse-video terminal-cursor">';
|
currentElement.classList.add('reverse-video', 'terminal-cursor');
|
||||||
} else {
|
} else {
|
||||||
let classNames = [];
|
let bg = data & 0x1ff;
|
||||||
|
let fg = (data >> 9) & 0x1ff;
|
||||||
bg = data & 0x1ff;
|
let flags = data >> 18;
|
||||||
fg = (data >> 9) & 0x1ff;
|
|
||||||
flags = data >> 18;
|
|
||||||
|
|
||||||
if (flags & FLAGS.BOLD) {
|
if (flags & FLAGS.BOLD) {
|
||||||
if (!brokenBold) {
|
if (!brokenBold) {
|
||||||
classNames.push('xterm-bold');
|
currentElement.classList.add('xterm-bold');
|
||||||
}
|
}
|
||||||
// See: XTerm*boldColors
|
// See: XTerm*boldColors
|
||||||
if (fg < 8) fg += 8;
|
if (fg < 8) {
|
||||||
|
fg += 8;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & FLAGS.UNDERLINE) {
|
if (flags & FLAGS.UNDERLINE) {
|
||||||
classNames.push('xterm-underline');
|
currentElement.classList.add('xterm-underline');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & FLAGS.BLINK) {
|
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 inverse flag is on, then swap the foreground and background variables.
|
||||||
if (flags & FLAGS.INVERSE) {
|
if (flags & FLAGS.INVERSE) {
|
||||||
/* One-line variable swap in JavaScript: http://stackoverflow.com/a/16201730 */
|
let temp = bg;
|
||||||
bg = [fg, fg = bg][0];
|
bg = fg;
|
||||||
// Should inverse just be before the
|
fg = temp;
|
||||||
// above boldColors effect instead?
|
// Should inverse just be before the above boldColors effect instead?
|
||||||
if ((flags & 1) && fg < 8) fg += 8;
|
if ((flags & 1) && fg < 8) {
|
||||||
|
fg += 8;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & FLAGS.INVISIBLE) {
|
if (flags & FLAGS.INVISIBLE) {
|
||||||
classNames.push('xterm-hidden');
|
currentElement.classList.add('xterm-hidden');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -229,55 +256,60 @@ export class Renderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (bg < 256) {
|
if (bg < 256) {
|
||||||
classNames.push('xterm-bg-color-' + bg);
|
currentElement.classList.add(`xterm-bg-color-${bg}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fg < 256) {
|
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) {
|
if (ch_width === 2) {
|
||||||
out += '<span class="xterm-wide-char">';
|
// 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.
|
||||||
switch (ch) {
|
innerHTML += `<span class="xterm-wide-char">${ch}</span>`;
|
||||||
case '&':
|
} else if (ch.charCodeAt(0) > 255) {
|
||||||
out += '&';
|
// Wrap any non-wide unicode character as some fonts size them badly
|
||||||
break;
|
innerHTML += `<span class="xterm-normal-char">${ch}</span>`;
|
||||||
case '<':
|
} else {
|
||||||
out += '<';
|
switch (ch) {
|
||||||
break;
|
case '&':
|
||||||
case '>':
|
innerHTML += '&';
|
||||||
out += '>';
|
break;
|
||||||
break;
|
case '<':
|
||||||
default:
|
innerHTML += '<';
|
||||||
if (ch <= ' ') {
|
break;
|
||||||
out += ' ';
|
case '>':
|
||||||
} else {
|
innerHTML += '>';
|
||||||
out += ch;
|
break;
|
||||||
}
|
default:
|
||||||
break;
|
if (ch <= ' ') {
|
||||||
}
|
innerHTML += ' ';
|
||||||
if (ch_width === 2) {
|
} else {
|
||||||
out += '</span>';
|
innerHTML += ch;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
attr = data;
|
attr = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attr !== this._terminal.defAttr) {
|
if (innerHTML && !currentElement) {
|
||||||
out += '</span>';
|
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) {
|
if (parent) {
|
||||||
@@ -289,8 +321,7 @@ export class Renderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// if bold is broken, we can't
|
// If bold is broken, we can't use it in the terminal.
|
||||||
// use it in the terminal.
|
|
||||||
function checkBoldBroken(terminal) {
|
function checkBoldBroken(terminal) {
|
||||||
const document = terminal.ownerDocument;
|
const document = terminal.ownerDocument;
|
||||||
const el = document.createElement('span');
|
const el = document.createElement('span');
|
||||||
|
|||||||
@@ -16,3 +16,14 @@ describe('evaluateCopiedTextProcessing', function () {
|
|||||||
assert.equal(processedText.indexOf(nonBreakingSpace), -1);
|
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;
|
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.
|
* Binds copy functionality to the given terminal.
|
||||||
* @param {ClipboardEvent} ev The original copy event to be handled
|
* @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 text: string;
|
||||||
|
|
||||||
let dispatchPaste = function(text) {
|
let dispatchPaste = function(text) {
|
||||||
|
text = prepareTextForTerminal(text, term.browser.isMSWindows);
|
||||||
term.handler(text);
|
term.handler(text);
|
||||||
term.textarea.value = '';
|
term.textarea.value = '';
|
||||||
|
term.emit('paste', text);
|
||||||
|
|
||||||
return term.cancel(ev);
|
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;
|
overflow-y: scroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
.terminal .xterm-wide-char {
|
.terminal .xterm-wide-char,
|
||||||
|
.terminal .xterm-normal-char {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+13
-48
@@ -24,6 +24,7 @@ import { CharMeasure } from './utils/CharMeasure';
|
|||||||
import * as Browser from './utils/Browser';
|
import * as Browser from './utils/Browser';
|
||||||
import * as Keyboard from './utils/Keyboard';
|
import * as Keyboard from './utils/Keyboard';
|
||||||
import { CHARSETS } from './Charsets';
|
import { CHARSETS } from './Charsets';
|
||||||
|
import { getRawByteCoords } from './utils/Mouse';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Terminal Emulation References:
|
* Terminal Emulation References:
|
||||||
@@ -760,7 +761,9 @@ Terminal.loadAddon = function(addon, callback) {
|
|||||||
* character width has been changed.
|
* character width has been changed.
|
||||||
*/
|
*/
|
||||||
Terminal.prototype.updateCharSizeCSS = function() {
|
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);
|
button = getButton(ev);
|
||||||
|
|
||||||
// get mouse coordinates
|
// get mouse coordinates
|
||||||
pos = getCoords(ev);
|
pos = getRawByteCoords(ev, self.rowContainer, self.charMeasure, self.cols, self.rows);
|
||||||
if (!pos) return;
|
if (!pos) return;
|
||||||
|
|
||||||
sendEvent(button, pos);
|
sendEvent(button, pos);
|
||||||
@@ -815,7 +818,7 @@ Terminal.prototype.bindMouse = function() {
|
|||||||
var button = pressed
|
var button = pressed
|
||||||
, pos;
|
, pos;
|
||||||
|
|
||||||
pos = getCoords(ev);
|
pos = getRawByteCoords(ev, self.rowContainer, self.charMeasure, self.cols, self.rows);
|
||||||
if (!pos) return;
|
if (!pos) return;
|
||||||
|
|
||||||
// buttons marked as motions
|
// buttons marked as motions
|
||||||
@@ -990,50 +993,6 @@ Terminal.prototype.bindMouse = function() {
|
|||||||
return button;
|
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) {
|
on(el, 'mousedown', function(ev) {
|
||||||
if (!self.mouseEvents) return;
|
if (!self.mouseEvents) return;
|
||||||
|
|
||||||
@@ -1293,7 +1252,13 @@ Terminal.prototype.innerWrite = function() {
|
|||||||
this.refreshStart = this.y;
|
this.refreshStart = this.y;
|
||||||
this.refreshEnd = 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.updateRange(this.y);
|
||||||
this.refresh(this.refreshStart, this.refreshEnd);
|
this.refresh(this.refreshStart, this.refreshEnd);
|
||||||
|
|||||||
Reference in New Issue
Block a user