Insert mode + coding style

This commit is contained in:
Florian Mounier
2015-04-30 14:40:45 +02:00
parent c345367d6b
commit da3e9237be
11 changed files with 314 additions and 295 deletions

View File

@@ -23,15 +23,18 @@
/* THIS NEEDS the python `libsass` library to be installed.
/* You can also copy the imported files in those dirs, they will be imported prioritarily.
@import font /* You can change this file to import any webfont
/* You can change this file to import any webfont:
@import font
/* You can comment / uncomment the following to enable/disable terminal effects.
@import light_fx
@import text_fx /* Comment this one to remove the blurry text
/* Comment this one to remove the blurry text:
@import text_fx
/* @import all_fx
@import colors
@import 16_colors /* The color theme is defined in this one
/* The color theme is defined in this one:
@import 16_colors
@import 256_colors
@import layout

View File

@@ -1,8 +1,8 @@
(function() {
var Selection, alt, cancel, copy, ctrl, first, next_leaf, previous_leaf, selection, set_alarm, virtual_input,
var Selection, alt, cancel, copy, ctrl, first, nextLeaf, previousLeaf, selection, setAlarm, virtualInput,
indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
set_alarm = function(notification) {
setAlarm = function(notification) {
var alarm;
alarm = function(data) {
var note;
@@ -39,10 +39,10 @@
}
if (Notification && Notification.permission === 'default') {
Notification.requestPermission(function() {
return set_alarm(Notification.permission === 'granted');
return setAlarm(Notification.permission === 'granted');
});
} else {
set_alarm(Notification.permission === 'granted');
setAlarm(Notification.permission === 'granted');
}
return cancel(e);
});
@@ -90,7 +90,7 @@
return false;
};
previous_leaf = function(node) {
previousLeaf = function(node) {
var previous;
previous = node.previousSibling;
if (!previous) {
@@ -105,7 +105,7 @@
return previous;
};
next_leaf = function(node) {
nextLeaf = function(node) {
var next;
next = node.nextSibling;
if (!next) {
@@ -127,11 +127,11 @@
}
Selection.prototype.reset = function() {
var fake_range, ref, results;
var fakeRange, ref, results;
this.selection = getSelection();
fake_range = document.createRange();
fake_range.setStart(this.selection.anchorNode, this.selection.anchorOffset);
fake_range.setEnd(this.selection.focusNode, this.selection.focusOffset);
fakeRange = document.createRange();
fakeRange.setStart(this.selection.anchorNode, this.selection.anchorOffset);
fakeRange.setEnd(this.selection.focusNode, this.selection.focusOffset);
this.start = {
node: this.selection.anchorNode,
offset: this.selection.anchorOffset
@@ -140,17 +140,17 @@
node: this.selection.focusNode,
offset: this.selection.focusOffset
};
if (fake_range.collapsed) {
if (fakeRange.collapsed) {
ref = [this.end, this.start], this.start = ref[0], this.end = ref[1];
}
this.start_line = this.start.node;
while (!this.start_line.classList || indexOf.call(this.start_line.classList, 'line') < 0) {
this.start_line = this.start_line.parentNode;
this.startLine = this.start.node;
while (!this.startLine.classList || indexOf.call(this.startLine.classList, 'line') < 0) {
this.startLine = this.startLine.parentNode;
}
this.end_line = this.end.node;
this.endLine = this.end.node;
results = [];
while (!this.end_line.classList || indexOf.call(this.end_line.classList, 'line') < 0) {
results.push(this.end_line = this.end_line.parentNode);
while (!this.endLine.classList || indexOf.call(this.endLine.classList, 'line') < 0) {
results.push(this.endLine = this.endLine.parentNode);
}
return results;
};
@@ -178,7 +178,7 @@
Selection.prototype.go = function(n) {
var index;
index = butterfly.children.indexOf(this.start_line) + n;
index = butterfly.children.indexOf(this.startLine) + n;
if (!((0 <= index && index < butterfly.children.length))) {
return;
}
@@ -188,7 +188,7 @@
return;
}
}
return this.select_line(index);
return this.selectLine(index);
};
Selection.prototype.apply = function() {
@@ -200,30 +200,30 @@
return this.selection.addRange(range);
};
Selection.prototype.select_line = function(index) {
var line, line_end, line_start;
Selection.prototype.selectLine = function(index) {
var line, lineEnd, lineStart;
line = butterfly.children[index];
line_start = {
lineStart = {
node: line.firstChild,
offset: 0
};
line_end = {
lineEnd = {
node: line.lastChild,
offset: line.lastChild.textContent.length
};
this.start = this.walk(line_start, /\S/);
return this.end = this.walk(line_end, /\S/, true);
this.start = this.walk(lineStart, /\S/);
return this.end = this.walk(lineEnd, /\S/, true);
};
Selection.prototype.collapsed = function(start, end) {
var fake_range;
fake_range = document.createRange();
fake_range.setStart(start.node, start.offset);
fake_range.setEnd(end.node, end.offset);
return fake_range.collapsed;
var fakeRange;
fakeRange = document.createRange();
fakeRange.setStart(start.node, start.offset);
fakeRange.setEnd(end.node, end.offset);
return fakeRange.collapsed;
};
Selection.prototype.shrink_right = function() {
Selection.prototype.shrinkRight = function() {
var end, node;
node = this.walk(this.end, /\s/, true);
end = this.walk(node, /\S/, true);
@@ -232,7 +232,7 @@
}
};
Selection.prototype.shrink_left = function() {
Selection.prototype.shrinkLeft = function() {
var node, start;
node = this.walk(this.start, /\s/);
start = this.walk(node, /\S/);
@@ -241,13 +241,13 @@
}
};
Selection.prototype.expand_right = function() {
Selection.prototype.expandRight = function() {
var node;
node = this.walk(this.end, /\S/);
return this.end = this.walk(node, /\s/);
};
Selection.prototype.expand_left = function() {
Selection.prototype.expandLeft = function() {
var node;
node = this.walk(this.start, /\S/, true);
return this.start = this.walk(node, /\s/, true);
@@ -275,7 +275,7 @@
};
}
}
node = previous_leaf(node);
node = previousLeaf(node);
text = node.textContent;
i = text.length;
}
@@ -289,7 +289,7 @@
};
}
}
node = next_leaf(node);
node = nextLeaf(node);
text = node.textContent;
i = 0;
}
@@ -323,13 +323,13 @@
selection.down();
}
} else if (e.keyCode === 39) {
selection.shrink_left();
selection.shrinkLeft();
} else if (e.keyCode === 38) {
selection.expand_left();
selection.expandLeft();
} else if (e.keyCode === 37) {
selection.shrink_right();
selection.shrinkRight();
} else if (e.keyCode === 40) {
selection.expand_right();
selection.expandRight();
} else {
return cancel(e);
}
@@ -340,7 +340,7 @@
}
if (!selection && e.ctrlKey && e.shiftKey && e.keyCode === 38) {
selection = new Selection();
selection.select_line(butterfly.y - 1);
selection.selectLine(butterfly.y - 1);
selection.apply();
return cancel(e);
}
@@ -369,7 +369,7 @@
});
document.addEventListener('dblclick', function(e) {
var anchorNode, anchorOffset, new_range, range, sel;
var anchorNode, anchorOffset, newRange, range, sel;
if (e.ctrlKey || e.altkey) {
return;
}
@@ -382,10 +382,10 @@
range.setEnd(sel.focusNode, sel.focusOffset);
if (range.collapsed) {
sel.removeAllRanges();
new_range = document.createRange();
new_range.setStart(sel.focusNode, sel.focusOffset);
new_range.setEnd(sel.anchorNode, sel.anchorOffset);
sel.addRange(new_range);
newRange = document.createRange();
newRange.setStart(sel.focusNode, sel.focusOffset);
newRange.setEnd(sel.anchorNode, sel.anchorOffset);
sel.addRange(newRange);
}
while (!(sel.toString().match(/\s/) || !sel.toString())) {
sel.modify('extend', 'forward', 'character');
@@ -405,17 +405,17 @@
ctrl = false;
alt = false;
first = true;
virtual_input = document.createElement('input');
virtual_input.type = 'password';
virtual_input.style.position = 'fixed';
virtual_input.style.top = 0;
virtual_input.style.left = 0;
virtual_input.style.border = 'none';
virtual_input.style.outline = 'none';
virtual_input.style.opacity = 0;
virtual_input.value = '0';
document.body.appendChild(virtual_input);
virtual_input.addEventListener('blur', function() {
virtualInput = document.createElement('input');
virtualInput.type = 'password';
virtualInput.style.position = 'fixed';
virtualInput.style.top = 0;
virtualInput.style.left = 0;
virtualInput.style.border = 'none';
virtualInput.style.outline = 'none';
virtualInput.style.opacity = 0;
virtualInput.value = '0';
document.body.appendChild(virtualInput);
virtualInput.addEventListener('blur', function() {
return setTimeout(((function(_this) {
return function() {
return _this.focus();
@@ -423,7 +423,7 @@
})(this)), 10);
});
addEventListener('click', function() {
return virtual_input.focus();
return virtualInput.focus();
});
addEventListener('touchstart', function(e) {
if (e.touches.length === 2) {
@@ -436,11 +436,11 @@
return alt = true;
}
});
virtual_input.addEventListener('keydown', function(e) {
virtualInput.addEventListener('keydown', function(e) {
butterfly.keyDown(e);
return true;
});
virtual_input.addEventListener('input', function(e) {
virtualInput.addEventListener('input', function(e) {
var len;
len = this.value.length;
if (len === 0) {

File diff suppressed because one or more lines are too long

View File

@@ -11,6 +11,12 @@
/* GNU General Public License for more details. */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* Theses are the various imported style files */
/* You can put this file in /etc/butterfly/style.sass or ~/.butterfly/style.sass */
/* To customize the style of your terminal. */
/* THIS NEEDS the python `libsass` library to be installed. */
/* You can also copy the imported files in those dirs, they will be imported prioritarily. */
/* You can change this file to import any webfont: */
/* *-* coding: utf-8 *-* */
/* This file is part of butterfly */
/* butterfly Copyright (C) 2014 Florian Mounier */
@@ -63,6 +69,7 @@ body {
font-family: "SourceCodePro";
line-height: 1.2; }
/* You can comment / uncomment the following to enable/disable terminal effects. */
/* *-* coding: utf-8 *-* */
/* This file is part of butterfly */
/* butterfly Copyright (C) 2014 Florian Mounier */
@@ -116,14 +123,11 @@ body {
body.locked::-webkit-scrollbar-thumb:hover {
background: rgba(255, 0, 0, 0.8); }
/* Comment this one to remove the blurry text: */
body {
text-shadow: 0 0 6px rgba(255, 255, 255, 0.5); }
body.copied {
transform: scale(1.05); }
body.pasted {
transform: scale(.95); }
/* @import all_fx */
/* *-* coding: utf-8 *-* */
/* This file is part of butterfly */
/* butterfly Copyright (C) 2014 Florian Mounier */
@@ -144,6 +148,7 @@ html, body {
background-color: #110f13;
color: #f4ead5; }
/* The color theme is defined in this one: */
/* *-* coding: utf-8 *-* */
/* This file is part of butterfly */
/* butterfly Copyright (C) 2014 Florian Mounier */

View File

@@ -1,5 +1,5 @@
(function() {
var $, State, Terminal, cancel, cols, open_ts, quit, rows, s,
var $, State, Terminal, cancel, cols, openTs, quit, rows, s,
slice = [].slice,
indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
@@ -7,12 +7,12 @@
quit = false;
open_ts = (new Date()).getTime();
openTs = (new Date()).getTime();
$ = document.querySelectorAll.bind(document);
document.addEventListener('DOMContentLoaded', function() {
var ctl, last_data, queue, send, t_queue, term, treat, ws, ws_url;
var ctl, lastData, queue, send, t_queue, term, treat, ws, wsUrl;
send = function(data) {
return ws.send('S' + data);
};
@@ -25,21 +25,21 @@
}
};
if (location.protocol === 'https:') {
ws_url = 'wss://';
wsUrl = 'wss://';
} else {
ws_url = 'ws://';
wsUrl = 'ws://';
}
ws_url += document.location.host + '/ws' + location.pathname;
ws = new WebSocket(ws_url);
wsUrl += document.location.host + '/ws' + location.pathname;
ws = new WebSocket(wsUrl);
ws.addEventListener('open', function() {
console.log("WebSocket open", arguments);
ws.send('R' + term.cols + ',' + term.rows);
return open_ts = (new Date()).getTime();
return openTs = (new Date()).getTime();
});
ws.addEventListener('error', function() {
return console.log("WebSocket error", arguments);
});
last_data = '';
lastData = '';
t_queue = null;
queue = '';
ws.addEventListener('message', function(e) {
@@ -50,7 +50,7 @@
if (term.stop) {
queue = queue.slice(-10 * 1024);
}
if (queue.length > term.buff_size) {
if (queue.length > term.buffSize) {
return treat();
} else {
return t_queue = setTimeout(treat, 1);
@@ -72,7 +72,7 @@
return term.body.classList.add('dead');
}, 1);
quit = true;
if ((new Date()).getTime() - open_ts > 60 * 1000) {
if ((new Date()).getTime() - openTs > 60 * 1000) {
return open('', '_self').close();
}
});
@@ -148,8 +148,8 @@
this.ctl = ctl1 != null ? ctl1 : function() {};
this.document = this.parent.ownerDocument;
this.body = this.document.getElementsByTagName('body')[0];
this.html_escapes_enabled = this.body.getAttribute('data-allow-html') === 'yes';
this.force_width = this.body.getAttribute('data-force-unicode-width') === 'yes';
this.htmlEscapesEnabled = this.body.getAttribute('data-allow-html') === 'yes';
this.forceWidth = this.body.getAttribute('data-force-unicode-width') === 'yes';
this.body.className = 'terminal focus';
this.body.style.outline = 'none';
this.body.setAttribute('tabindex', 0);
@@ -158,21 +158,21 @@
div.className = 'line';
this.body.appendChild(div);
this.children = [div];
this.compute_char_size();
this.cols = Math.floor(this.body.clientWidth / this.char_size.width);
this.rows = Math.floor(window.innerHeight / this.char_size.height);
px = window.innerHeight % this.char_size.height;
this.computeCharSize();
this.cols = Math.floor(this.body.clientWidth / this.charSize.width);
this.rows = Math.floor(window.innerHeight / this.charSize.height);
px = window.innerHeight % this.charSize.height;
this.body.style['padding-bottom'] = px + "px";
this.scrollback = 1000000;
this.buff_size = 100000;
this.buffSize = 100000;
this.visualBell = 100;
this.convertEol = false;
this.termName = 'xterm';
this.cursorBlink = true;
this.cursorState = 0;
this.stop = false;
this.last_cc = 0;
this.reset_vars();
this.lastcc = 0;
this.resetVars();
this.focus();
this.startBlink();
addEventListener('keydown', this.keyDown.bind(this));
@@ -211,7 +211,17 @@
return a.bg === b.bg && a.fg === b.fg && a.bold === b.bold && a.underline === b.underline && a.blink === b.blink && a.inverse === b.inverse && a.invisible === b.invisible;
};
Terminal.prototype.reset_vars = function() {
Terminal.prototype.putChar = function(c) {
if (this.insertMode) {
this.screen[this.y + this.shift][0].splice(this.x, 0, this.cloneAttr(this.curAttr, c));
this.screen[this.y + this.shift][0].pop();
} else {
this.screen[this.y + this.shift][0][this.x] = this.cloneAttr(this.curAttr, c);
}
return this.screen[this.y + this.shift][1] = true;
};
Terminal.prototype.resetVars = function() {
var i;
this.x = 0;
this.y = 0;
@@ -248,22 +258,22 @@
i = this.rows;
this.shift = 0;
while (i--) {
this.screen.push([this.blank_line(), true]);
this.screen.push([this.blankLine(), true]);
}
this.setupStops();
return this.skipNextKey = null;
};
Terminal.prototype.compute_char_size = function() {
var test_span;
test_span = document.createElement('span');
test_span.textContent = '0123456789';
this.children[0].appendChild(test_span);
this.char_size = {
width: test_span.getBoundingClientRect().width / 10,
Terminal.prototype.computeCharSize = function() {
var testSpan;
testSpan = document.createElement('span');
testSpan.textContent = '0123456789';
this.children[0].appendChild(testSpan);
this.charSize = {
width: testSpan.getBoundingClientRect().width / 10,
height: this.children[0].getBoundingClientRect().height
};
return this.children[0].removeChild(test_span);
return this.children[0].removeChild(testSpan);
};
Terminal.prototype.eraseAttr = function() {
@@ -474,7 +484,7 @@
};
Terminal.prototype.refresh = function(force) {
var attr, ch, classes, cursor, data, dirty, fg, group, i, j, k, len, len1, len2, len3, line, lines, m, new_out, o, out, q, ref, ref1, ref2, ref3, ref4, ref5, skipnext, styles, u, x;
var attr, ch, classes, cursor, data, dirty, fg, group, i, j, k, len, len1, len2, len3, line, lines, m, newOut, o, out, q, ref, ref1, ref2, ref3, ref4, ref5, skipnext, styles, u, x;
if (force == null) {
force = false;
}
@@ -483,7 +493,7 @@
cursor = ref[k];
cursor.parentNode.replaceChild(this.document.createTextNode(cursor.textContent), cursor);
}
new_out = '';
newOut = '';
ref1 = this.screen;
for (j = m = 0, len1 = ref1.length; m < len1; j = ++m) {
ref2 = ref1[j], line = ref2[0], dirty = ref2[1];
@@ -578,13 +588,13 @@
out += '<span class="nbsp">\u2007</span>';
} else if (ch <= " ") {
out += "&nbsp;";
} else if (!this.force_width || ch <= "~") {
} else if (!this.forceWidth || ch <= "~") {
out += ch;
} else if (("\uff00" < ch && ch < "\uffef")) {
skipnext = true;
out += "<span style=\"display: inline-block; width: " + (2 * this.char_size.width) + "px\">" + ch + "</span>";
out += "<span style=\"display: inline-block; width: " + (2 * this.charSize.width) + "px\">" + ch + "</span>";
} else {
out += "<span style=\"display: inline-block; width: " + this.char_size.width + "px\">" + ch + "</span>";
out += "<span style=\"display: inline-block; width: " + this.charSize.width + "px\">" + ch + "</span>";
}
}
}
@@ -599,14 +609,14 @@
if (this.children[j]) {
this.children[j].innerHTML = out;
} else {
new_out += "<div class=\"line\">" + out + "</div>";
newOut += "<div class=\"line\">" + out + "</div>";
}
this.screen[j][1] = false;
}
if (new_out !== '') {
if (newOut !== '') {
group = this.document.createElement('div');
group.className = 'group';
group.innerHTML = new_out;
group.innerHTML = newOut;
this.body.appendChild(group);
this.screen = this.screen.slice(-this.rows);
this.shift = 0;
@@ -627,7 +637,7 @@
this.children = Array.prototype.slice.call(lines, -this.rows);
}
if (!this.scrollLock) {
return this.native_scroll_to();
return this.nativeScrollTo();
}
};
@@ -676,7 +686,7 @@
Terminal.prototype.scroll = function() {
var i, k, ref, ref1, results;
if (this.normal || this.scrollTop !== 0 || this.scrollBottom !== this.rows - 1) {
this.screen.splice(this.shift + this.scrollBottom + 1, 0, [this.blank_line(), true]);
this.screen.splice(this.shift + this.scrollBottom + 1, 0, [this.blankLine(), true]);
this.screen.splice(this.shift + this.scrollTop, 1);
results = [];
for (i = k = ref = this.scrollTop, ref1 = this.scrollBottom; ref <= ref1 ? k <= ref1 : k >= ref1; i = ref <= ref1 ? ++k : --k) {
@@ -684,14 +694,14 @@
}
return results;
} else {
this.screen.push([this.blank_line(), true]);
this.screen.push([this.blankLine(), true]);
return this.shift++;
}
};
Terminal.prototype.unscroll = function() {
var i, k, ref, ref1, results;
this.screen.splice(this.shift + this.scrollTop, 0, [this.blank_line(true), true]);
this.screen.splice(this.shift + this.scrollTop, 0, [this.blankLine(true), true]);
this.screen.splice(this.shift + this.scrollBottom + 1, 1);
results = [];
for (i = k = ref = this.scrollTop, ref1 = this.scrollBottom; ref <= ref1 ? k <= ref1 : k >= ref1; i = ref <= ref1 ? ++k : --k) {
@@ -700,18 +710,18 @@
return results;
};
Terminal.prototype.native_scroll_to = function(scroll) {
Terminal.prototype.nativeScrollTo = function(scroll) {
if (scroll == null) {
scroll = 2000000000;
}
return window.scrollTo(0, scroll);
};
Terminal.prototype.scroll_display = function(disp) {
return this.native_scroll_to(window.scrollY + disp * this.char_size.height);
Terminal.prototype.scrollDisplay = function(disp) {
return this.nativeScrollTo(window.scrollY + disp * this.charSize.height);
};
Terminal.prototype.next_line = function() {
Terminal.prototype.nextLine = function() {
this.y++;
if (this.y > this.scrollBottom) {
this.y--;
@@ -719,7 +729,7 @@
}
};
Terminal.prototype.prev_line = function() {
Terminal.prototype.prevLine = function() {
this.y--;
if (this.y < this.scrollTop) {
this.y++;
@@ -742,7 +752,7 @@
case "\n":
case "\x0b":
case "\x0c":
this.next_line();
this.nextLine();
break;
case "\r":
this.x = 0;
@@ -770,22 +780,18 @@
ch = this.charset[ch];
}
if (this.x >= this.cols) {
this.screen[this.y + this.shift][0][this.x] = this.cloneAttr(this.curAttr, '\u23CE');
this.screen[this.y + this.shift][1] = true;
this.putChar('\u23CE');
this.x = 0;
this.next_line();
this.nextLine();
}
this.screen[this.y + this.shift][0][this.x] = this.cloneAttr(this.curAttr, ch);
this.screen[this.y + this.shift][1] = true;
this.putChar(ch);
this.x++;
if (this.force_width && ("\uff00" < ch && ch < "\uffef")) {
if (this.forceWidth && ("\uff00" < ch && ch < "\uffef")) {
if (this.cols < 2 || this.x >= this.cols) {
this.screen[this.y + this.shift][0][this.x - 1] = this.cloneAttr(this.curAttr, " ");
this.screen[this.y + this.shift][1] = true;
this.putChar(" ");
break;
}
this.screen[this.y + this.shift][0][this.x] = this.cloneAttr(this.curAttr, " ");
this.screen[this.y + this.shift][1] = true;
this.putChar(" ");
this.x++;
}
}
@@ -1168,7 +1174,7 @@
}
switch (type) {
case "HTML":
if (!this.html_escapes_enabled) {
if (!this.htmlEscapesEnabled) {
console.log("HTML escapes are disabled");
break;
}
@@ -1321,7 +1327,7 @@
break;
}
if (ev.ctrlKey) {
this.scroll_display(-1);
this.scrollDisplay(-1);
return cancel(ev);
} else {
key = "\x1b[A";
@@ -1333,7 +1339,7 @@
break;
}
if (ev.ctrlKey) {
this.scroll_display(1);
this.scrollDisplay(1);
return cancel(ev);
} else {
key = "\x1b[B";
@@ -1361,7 +1367,7 @@
break;
case 33:
if (ev.shiftKey) {
this.scroll_display(-(this.rows - 1));
this.scrollDisplay(-(this.rows - 1));
return cancel(ev);
} else {
key = "\x1b[5~";
@@ -1369,7 +1375,7 @@
break;
case 34:
if (ev.shiftKey) {
this.scroll_display(this.rows - 1);
this.scrollDisplay(this.rows - 1);
return cancel(ev);
} else {
key = "\x1b[6~";
@@ -1424,7 +1430,7 @@
if (ev.keyCode >= 65 && ev.keyCode <= 90) {
if (ev.keyCode === 67) {
t = (new Date()).getTime();
if ((t - this.last_cc) < 500 && !this.stop) {
if ((t - this.lastcc) < 500 && !this.stop) {
id = setTimeout(function() {});
while (id--) {
if (id !== this.t_bell && id !== this.t_queue && id !== this.t_blink) {
@@ -1436,7 +1442,7 @@
} else if (this.stop) {
return true;
}
this.last_cc = t;
this.lastcc = t;
}
key = String.fromCharCode(ev.keyCode - 64);
} else if (ev.keyCode === 32) {
@@ -1543,32 +1549,32 @@
};
Terminal.prototype.resize = function(x, y) {
var el, i, j, line, old_cols, old_rows, px;
var el, i, j, line, oldCols, oldRows, px;
if (x == null) {
x = null;
}
if (y == null) {
y = null;
}
old_cols = this.cols;
old_rows = this.rows;
this.compute_char_size();
this.cols = x || Math.floor(this.body.clientWidth / this.char_size.width);
this.rows = y || Math.floor(window.innerHeight / this.char_size.height);
px = window.innerHeight % this.char_size.height;
oldCols = this.cols;
oldRows = this.rows;
this.computeCharSize();
this.cols = x || Math.floor(this.body.clientWidth / this.charSize.width);
this.rows = y || Math.floor(window.innerHeight / this.charSize.height);
px = window.innerHeight % this.charSize.height;
this.body.style['padding-bottom'] = px + "px";
if ((!x && !y) && old_cols === this.cols && old_rows === this.rows) {
if ((!x && !y) && oldCols === this.cols && oldRows === this.rows) {
return;
}
this.ctl('Resize', this.cols, this.rows);
if (old_cols < this.cols) {
if (oldCols < this.cols) {
i = this.screen.length;
while (i--) {
while (this.screen[i][0].length < this.cols) {
this.screen[i][0].push(this.defAttr);
}
}
} else if (old_cols > this.cols) {
} else if (oldCols > this.cols) {
i = this.screen.length;
while (i--) {
while (this.screen[i][0].length > this.cols) {
@@ -1576,13 +1582,13 @@
}
}
}
this.setupStops(old_cols);
j = old_rows;
this.setupStops(oldCols);
j = oldRows;
if (j < this.rows) {
el = this.body;
while (j++ < this.rows) {
if (this.screen.length < this.rows) {
this.screen.push([this.blank_line(), true]);
this.screen.push([this.blankLine(), true]);
}
if (this.children.length < this.rows) {
line = this.document.createElement("div");
@@ -1695,7 +1701,7 @@
return this.eraseRight(0, y);
};
Terminal.prototype.blank_line = function(cur) {
Terminal.prototype.blankLine = function(cur) {
var attr, i, line;
attr = (cur ? this.eraseAttr() : this.defAttr);
line = [];
@@ -1728,17 +1734,17 @@
};
Terminal.prototype.index = function() {
this.next_line();
this.nextLine();
return this.state = State.normal;
};
Terminal.prototype.reverseIndex = function() {
this.prev_line();
this.prevLine();
return this.state = State.normal;
};
Terminal.prototype.reset = function() {
this.reset_vars();
this.resetVars();
return this.refresh(true);
};
@@ -2014,7 +2020,7 @@
param = 1;
}
while (param--) {
this.screen.splice(this.y + this.shift, 0, [this.blank_line(true), true]);
this.screen.splice(this.y + this.shift, 0, [this.blankLine(true), true]);
this.screen.splice(this.scrollBottom + 1 + this.shift, 1);
}
results = [];
@@ -2031,7 +2037,7 @@
param = 1;
}
while (param--) {
this.screen.splice(this.scrollBottom + this.shift, 0, [this.blank_line(true), true]);
this.screen.splice(this.scrollBottom + this.shift, 0, [this.blankLine(true), true]);
this.screen.splice(this.y + this.shift, 1);
if (!(this.normal || this.scrollTop !== 0 || this.scrollBottom !== this.rows - 1)) {
this.children[this.y + this.shift].remove();
@@ -2353,7 +2359,7 @@
param = params[0] || 1;
while (param--) {
this.screen.splice(this.scrollTop, 1);
this.screen.splice(this.scrollBottom, 0, [this.blank_line(), true]);
this.screen.splice(this.scrollBottom, 0, [this.blankLine(), true]);
}
results = [];
for (i = k = ref = this.scrollTop, ref1 = this.scrollBottom; ref <= ref1 ? k <= ref1 : k >= ref1; i = ref <= ref1 ? ++k : --k) {
@@ -2367,7 +2373,7 @@
param = params[0] || 1;
while (param--) {
this.screen.splice(this.scrollBottom, 1);
this.screen.splice(this.scrollTop, 0, [this.blank_line(), true]);
this.screen.splice(this.scrollTop, 0, [this.blankLine(), true]);
}
results = [];
for (i = k = ref = this.scrollTop, ref1 = this.scrollBottom; ref <= ref1 ? k <= ref1 : k >= ref1; i = ref <= ref1 ? ++k : --k) {

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +1,4 @@
set_alarm = (notification) ->
setAlarm = (notification) ->
alarm = (data) ->
butterfly.body.classList.remove 'alarm'
note = "New activity on butterfly terminal [#{ butterfly.title }]"
@@ -29,8 +29,8 @@ document.addEventListener 'keydown', (e) ->
if Notification and Notification.permission is 'default'
Notification.requestPermission ->
set_alarm(Notification.permission is 'granted')
setAlarm(Notification.permission is 'granted')
else
set_alarm(Notification.permission is 'granted')
setAlarm(Notification.permission is 'granted')
cancel(e)

View File

@@ -22,7 +22,7 @@ cancel = (ev) ->
ev.cancelBubble = true
false
previous_leaf = (node) ->
previousLeaf = (node) ->
previous = node.previousSibling
if not previous
previous = node.parentNode.previousSibling
@@ -32,7 +32,7 @@ previous_leaf = (node) ->
previous = previous.lastChild
previous
next_leaf = (node) ->
nextLeaf = (node) ->
next = node.nextSibling
if not next
next = node.parentNode.nextSibling
@@ -49,9 +49,9 @@ class Selection
reset: ->
@selection = getSelection()
fake_range = document.createRange()
fake_range.setStart(@selection.anchorNode, @selection.anchorOffset)
fake_range.setEnd(@selection.focusNode, @selection.focusOffset)
fakeRange = document.createRange()
fakeRange.setStart(@selection.anchorNode, @selection.anchorOffset)
fakeRange.setEnd(@selection.focusNode, @selection.focusOffset)
@start =
node: @selection.anchorNode
offset: @selection.anchorOffset
@@ -59,16 +59,16 @@ class Selection
node: @selection.focusNode
offset: @selection.focusOffset
if fake_range.collapsed
if fakeRange.collapsed
[@start, @end] = [@end, @start]
@start_line = @start.node
while not @start_line.classList or 'line' not in @start_line.classList
@start_line = @start_line.parentNode
@startLine = @start.node
while not @startLine.classList or 'line' not in @startLine.classList
@startLine = @startLine.parentNode
@end_line = @end.node
while not @end_line.classList or 'line' not in @end_line.classList
@end_line = @end_line.parentNode
@endLine = @end.node
while not @endLine.classList or 'line' not in @endLine.classList
@endLine = @endLine.parentNode
clear: ->
@selection.removeAllRanges()
@@ -87,14 +87,14 @@ class Selection
@go +1
go: (n) ->
index = butterfly.children.indexOf(@start_line) + n
index = butterfly.children.indexOf(@startLine) + n
return unless 0 <= index < butterfly.children.length
until butterfly.children[index].textContent.match /\S/
index += n
return unless 0 <= index < butterfly.children.length
@select_line index
@selectLine index
apply: ->
@clear()
@@ -103,42 +103,42 @@ class Selection
range.setEnd @end.node, @end.offset
@selection.addRange range
select_line: (index) ->
selectLine: (index) ->
line = butterfly.children[index]
line_start =
lineStart =
node: line.firstChild
offset: 0
line_end =
lineEnd =
node: line.lastChild
offset: line.lastChild.textContent.length
@start = @walk line_start, /\S/
@end = @walk line_end, /\S/, true
@start = @walk lineStart, /\S/
@end = @walk lineEnd, /\S/, true
collapsed: (start, end) ->
fake_range = document.createRange()
fake_range.setStart(start.node, start.offset)
fake_range.setEnd(end.node, end.offset)
fake_range.collapsed
fakeRange = document.createRange()
fakeRange.setStart(start.node, start.offset)
fakeRange.setEnd(end.node, end.offset)
fakeRange.collapsed
shrink_right: ->
shrinkRight: ->
node = @walk @end, /\s/, true
end = @walk node, /\S/, true
if not @collapsed(@start, end)
@end = end
shrink_left: ->
shrinkLeft: ->
node = @walk @start, /\s/
start = @walk node, /\S/
if not @collapsed(start, @end)
@start = start
expand_right: ->
expandRight: ->
node = @walk @end, /\S/
@end = @walk node, /\s/
expand_left: ->
expandLeft: ->
node = @walk @start, /\S/, true
@start = @walk node, /\s/, true
@@ -155,7 +155,7 @@ class Selection
while i > 0
if text[--i].match til
return node: node, offset: i + 1
node = previous_leaf node
node = previousLeaf node
text = node.textContent
i = text.length
else
@@ -163,7 +163,7 @@ class Selection
while i < text.length
if text[i++].match til
return node: node, offset: i - 1
node = next_leaf node
node = nextLeaf node
text = node.textContent
i = 0
@@ -189,13 +189,13 @@ document.addEventListener 'keydown', (e) ->
else if e.keyCode == 40
selection.down()
else if e.keyCode == 39
selection.shrink_left()
selection.shrinkLeft()
else if e.keyCode == 38
selection.expand_left()
selection.expandLeft()
else if e.keyCode == 37
selection.shrink_right()
selection.shrinkRight()
else if e.keyCode == 40
selection.expand_right()
selection.expandRight()
else
return cancel e
@@ -205,7 +205,7 @@ document.addEventListener 'keydown', (e) ->
# Start selection mode with shift up
if not selection and e.ctrlKey and e.shiftKey and e.keyCode == 38
selection = new Selection()
selection.select_line butterfly.y - 1
selection.selectLine butterfly.y - 1
selection.apply()
return cancel e
true
@@ -235,10 +235,10 @@ document.addEventListener 'dblclick', (e) ->
range.setEnd(sel.focusNode, sel.focusOffset)
if range.collapsed
sel.removeAllRanges()
new_range = document.createRange()
new_range.setStart(sel.focusNode, sel.focusOffset)
new_range.setEnd(sel.anchorNode, sel.anchorOffset)
sel.addRange(new_range)
newRange = document.createRange()
newRange.setStart(sel.focusNode, sel.focusOffset)
newRange.setEnd(sel.anchorNode, sel.anchorOffset)
sel.addRange(newRange)
until sel.toString().match(/\s/) or not sel.toString()
sel.modify 'extend', 'forward', 'character'

View File

@@ -21,22 +21,22 @@ if /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i
ctrl = false
alt = false
first = true
virtual_input = document.createElement 'input'
virtual_input.type = 'password'
virtual_input.style.position = 'fixed'
virtual_input.style.top = 0
virtual_input.style.left = 0
virtual_input.style.border = 'none'
virtual_input.style.outline = 'none'
virtual_input.style.opacity = 0
virtual_input.value = '0'
document.body.appendChild virtual_input
virtualInput = document.createElement 'input'
virtualInput.type = 'password'
virtualInput.style.position = 'fixed'
virtualInput.style.top = 0
virtualInput.style.left = 0
virtualInput.style.border = 'none'
virtualInput.style.outline = 'none'
virtualInput.style.opacity = 0
virtualInput.value = '0'
document.body.appendChild virtualInput
virtual_input.addEventListener 'blur', ->
virtualInput.addEventListener 'blur', ->
setTimeout((=> @focus()), 10)
addEventListener 'click', ->
virtual_input.focus()
virtualInput.focus()
addEventListener 'touchstart', (e) ->
if e.touches.length == 2
@@ -48,11 +48,11 @@ if /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i
ctrl = true
alt = true
virtual_input.addEventListener 'keydown', (e) ->
virtualInput.addEventListener 'keydown', (e) ->
butterfly.keyDown(e)
return true
virtual_input.addEventListener 'input', (e) ->
virtualInput.addEventListener 'input', (e) ->
len = @value.length
if len == 0

View File

@@ -17,7 +17,7 @@
cols = rows = null
quit = false
open_ts = (new Date()).getTime()
openTs = (new Date()).getTime()
$ = document.querySelectorAll.bind(document)
@@ -32,22 +32,22 @@ document.addEventListener 'DOMContentLoaded', ->
ws.send 'R' + params
if location.protocol == 'https:'
ws_url = 'wss://'
wsUrl = 'wss://'
else
ws_url = 'ws://'
wsUrl = 'ws://'
ws_url += document.location.host + '/ws' + location.pathname
ws = new WebSocket ws_url
wsUrl += document.location.host + '/ws' + location.pathname
ws = new WebSocket wsUrl
ws.addEventListener 'open', ->
console.log "WebSocket open", arguments
ws.send 'R' + term.cols + ',' + term.rows
open_ts = (new Date()).getTime()
openTs = (new Date()).getTime()
ws.addEventListener 'error', ->
console.log "WebSocket error", arguments
last_data = ''
lastData = ''
t_queue = null
queue = ''
@@ -57,7 +57,7 @@ document.addEventListener 'DOMContentLoaded', ->
if term.stop
queue = queue.slice -10 * 1024
if queue.length > term.buff_size
if queue.length > term.buffSize
treat()
else
t_queue = setTimeout treat, 1
@@ -79,7 +79,7 @@ document.addEventListener 'DOMContentLoaded', ->
, 1
quit = true
# Don't autoclose if websocket didn't last 1 minute
if (new Date()).getTime() - open_ts > 60 * 1000
if (new Date()).getTime() - openTs > 60 * 1000
open('','_self').close()
term = new Terminal document.body, send, ctl

View File

@@ -51,8 +51,8 @@ class Terminal
# Global elements
@document = @parent.ownerDocument
@body = @document.getElementsByTagName('body')[0]
@html_escapes_enabled = @body.getAttribute('data-allow-html') is 'yes'
@force_width = @body.getAttribute(
@htmlEscapesEnabled = @body.getAttribute('data-allow-html') is 'yes'
@forceWidth = @body.getAttribute(
'data-force-unicode-width') is 'yes'
# Main terminal element
@@ -67,14 +67,14 @@ class Terminal
@body.appendChild(div)
@children = [div]
@compute_char_size()
@cols = Math.floor(@body.clientWidth / @char_size.width)
@rows = Math.floor(window.innerHeight / @char_size.height)
px = window.innerHeight % @char_size.height
@computeCharSize()
@cols = Math.floor(@body.clientWidth / @charSize.width)
@rows = Math.floor(window.innerHeight / @charSize.height)
px = window.innerHeight % @charSize.height
@body.style['padding-bottom'] = "#{px}px"
@scrollback = 1000000
@buff_size = 100000
@buffSize = 100000
@visualBell = 100
@convertEol = false
@@ -82,8 +82,8 @@ class Terminal
@cursorBlink = true
@cursorState = 0
@stop = false
@last_cc = 0
@reset_vars()
@lastcc = 0
@resetVars()
@focus()
@@ -118,7 +118,16 @@ class Terminal
a.underline is b.underline and a.blink is b.blink and
a.inverse is b.inverse and a.invisible is b.invisible)
reset_vars: ->
putChar: (c) ->
if @insertMode
@screen[@y + @shift][0].splice(@x, 0, @cloneAttr @curAttr, c)
@screen[@y + @shift][0].pop()
else
@screen[@y + @shift][0][@x] = @cloneAttr @curAttr, c
@screen[@y + @shift][1] = true
resetVars: ->
@x = 0
@y = 0
@cursorHidden = false
@@ -160,18 +169,18 @@ class Terminal
@screen = []
i = @rows
@shift = 0
@screen.push [@blank_line(), true] while i--
@screen.push [@blankLine(), true] while i--
@setupStops()
@skipNextKey = null
compute_char_size: ->
test_span = document.createElement('span')
test_span.textContent = '0123456789'
@children[0].appendChild(test_span)
@char_size =
width: test_span.getBoundingClientRect().width / 10
computeCharSize: ->
testSpan = document.createElement('span')
testSpan.textContent = '0123456789'
@children[0].appendChild(testSpan)
@charSize =
width: testSpan.getBoundingClientRect().width / 10
height: @children[0].getBoundingClientRect().height
@children[0].removeChild(test_span)
@children[0].removeChild(testSpan)
eraseAttr: ->
erased = @cloneAttr @defAttr
@@ -379,7 +388,7 @@ class Terminal
for cursor in @body.querySelectorAll(".cursor")
cursor.parentNode.replaceChild(
@document.createTextNode(cursor.textContent), cursor)
new_out = ''
newOut = ''
for [line, dirty], j in @screen
continue unless dirty or force
out = ""
@@ -461,15 +470,15 @@ class Terminal
out += '<span class="nbsp">\u2007</span>'
else if ch <= " "
out += "&nbsp;"
else if not @force_width or ch <= "~" # Ascii chars
else if not @forceWidth or ch <= "~" # Ascii chars
out += ch
else if "\uff00" < ch < "\uffef"
skipnext = true
out += "<span style=\"display: inline-block;
width: #{2 * @char_size.width}px\">#{ch}</span>"
width: #{2 * @charSize.width}px\">#{ch}</span>"
else
out += "<span style=\"display: inline-block;
width: #{@char_size.width}px\">#{ch}</span>"
width: #{@charSize.width}px\">#{ch}</span>"
out += "</span>" if i is x
attr = data
@@ -477,13 +486,13 @@ class Terminal
if @children[j]
@children[j].innerHTML = out
else
new_out += "<div class=\"line\">#{out}</div>"
newOut += "<div class=\"line\">#{out}</div>"
@screen[j][1] = false
if new_out isnt ''
if newOut isnt ''
group = @document.createElement('div')
group.className = 'group'
group.innerHTML = new_out
group.innerHTML = newOut
@body.appendChild group
@screen = @screen.slice(-@rows)
@shift = 0
@@ -499,7 +508,7 @@ class Terminal
@children = Array.prototype.slice.call(
lines, -@rows)
@native_scroll_to() unless @scrollLock
@nativeScrollTo() unless @scrollLock
_cursorBlink: ->
@cursorState ^= 1
@@ -534,36 +543,36 @@ class Terminal
# Use emulated scroll in alternate buffer or when scroll region is defined
if @normal or @scrollTop isnt 0 or @scrollBottom isnt @rows - 1
# inner scroll
@screen.splice @shift + @scrollBottom + 1, 0, [@blank_line(), true]
@screen.splice @shift + @scrollBottom + 1, 0, [@blankLine(), true]
@screen.splice @shift + @scrollTop, 1
for i in [@scrollTop..@scrollBottom]
@screen[i + @shift][1] = true
else
@screen.push [@blank_line(), true]
@screen.push [@blankLine(), true]
@shift++
unscroll: ->
@screen.splice @shift + @scrollTop , 0, [@blank_line(true), true]
@screen.splice @shift + @scrollTop , 0, [@blankLine(true), true]
@screen.splice @shift + @scrollBottom + 1, 1
for i in [@scrollTop..@scrollBottom]
@screen[i + @shift][1] = true
native_scroll_to: (scroll=2000000000) -> # ~ Max ff number
nativeScrollTo: (scroll=2000000000) -> # ~ Max ff number
window.scrollTo 0, scroll
scroll_display: (disp) ->
@native_scroll_to window.scrollY + disp * @char_size.height
scrollDisplay: (disp) ->
@nativeScrollTo window.scrollY + disp * @charSize.height
next_line: ->
nextLine: ->
@y++
if @y > @scrollBottom
@y--
@scroll()
prev_line: ->
prevLine: ->
@y--
if @y < @scrollTop
@y++
@@ -585,7 +594,7 @@ class Terminal
# '\n', '\v', '\f'
when "\n", "\x0b", "\x0c"
# @x = 0 if @convertEol
@next_line()
@nextLine()
# '\r'
when "\r"
@@ -616,22 +625,18 @@ class Terminal
if ch >= " "
ch = @charset[ch] if @charset?[ch]
if @x >= @cols
@screen[@y + @shift][0][@x] = @cloneAttr @curAttr, '\u23CE'
@screen[@y + @shift][1] = true
@putChar '\u23CE'
@x = 0
@next_line()
@nextLine()
@screen[@y + @shift][0][@x] = @cloneAttr @curAttr, ch
@screen[@y + @shift][1] = true
@putChar ch
@x++
if @force_width and "\uff00" < ch < "\uffef"
if @forceWidth and "\uff00" < ch < "\uffef"
if @cols < 2 or @x >= @cols
@screen[@y + @shift][0][@x - 1] = @cloneAttr @curAttr, " "
@screen[@y + @shift][1] = true
@putChar " "
break
@screen[@y + @shift][0][@x] = @cloneAttr @curAttr, " "
@screen[@y + @shift][1] = true
@putChar " "
@x++
when State.escaped
@@ -1075,7 +1080,7 @@ class Terminal
switch type
when "HTML"
unless @html_escapes_enabled
unless @htmlEscapesEnabled
console.log "HTML escapes are disabled"
break
@@ -1238,7 +1243,7 @@ class Terminal
key = "\x1bOA"
break
if ev.ctrlKey
@scroll_display -1
@scrollDisplay -1
return cancel(ev)
else
key = "\x1b[A"
@@ -1249,7 +1254,7 @@ class Terminal
key = "\x1bOB"
break
if ev.ctrlKey
@scroll_display 1
@scrollDisplay 1
return cancel(ev)
else
key = "\x1b[B"
@@ -1279,7 +1284,7 @@ class Terminal
# page up
when 33
if ev.shiftKey
@scroll_display -(@rows - 1)
@scrollDisplay -(@rows - 1)
return cancel(ev)
else
key = "\x1b[5~"
@@ -1287,7 +1292,7 @@ class Terminal
# page down
when 34
if ev.shiftKey
@scroll_display @rows - 1
@scrollDisplay @rows - 1
return cancel(ev)
else
key = "\x1b[6~"
@@ -1355,7 +1360,7 @@ class Terminal
if ev.keyCode >= 65 and ev.keyCode <= 90
if ev.keyCode is 67
t = (new Date()).getTime()
if (t - @last_cc) < 500 and not @stop
if (t - @lastcc) < 500 and not @stop
id = (setTimeout ->)
(clearTimeout id if id not in [
@t_bell, @t_queue, @t_blink]) while id--
@@ -1363,7 +1368,7 @@ class Terminal
@stop = true
else if @stop
return true
@last_cc = t
@lastcc = t
key = String.fromCharCode(ev.keyCode - 64)
else if ev.keyCode is 32
@@ -1461,38 +1466,38 @@ class Terminal
), @visualBell
resize: (x=null, y=null) ->
old_cols = @cols
old_rows = @rows
@compute_char_size()
@cols = x or Math.floor(@body.clientWidth / @char_size.width)
@rows = y or Math.floor(window.innerHeight / @char_size.height)
px = window.innerHeight % @char_size.height
oldCols = @cols
oldRows = @rows
@computeCharSize()
@cols = x or Math.floor(@body.clientWidth / @charSize.width)
@rows = y or Math.floor(window.innerHeight / @charSize.height)
px = window.innerHeight % @charSize.height
@body.style['padding-bottom'] = "#{px}px"
if (not x and not y) and old_cols == @cols and old_rows == @rows
if (not x and not y) and oldCols == @cols and oldRows == @rows
return
@ctl 'Resize', @cols, @rows
# resize cols
if old_cols < @cols
if oldCols < @cols
# does xterm use the default attr?
i = @screen.length
while i--
@screen[i][0].push @defAttr while @screen[i][0].length < @cols
else if old_cols > @cols
else if oldCols > @cols
i = @screen.length
while i--
@screen[i][0].pop() while @screen[i][0].length > @cols
@setupStops old_cols
@setupStops oldCols
# resize rows
j = old_rows
j = oldRows
if j < @rows
el = @body
while j++ < @rows
@screen.push [@blank_line(), true] if @screen.length < @rows
@screen.push [@blankLine(), true] if @screen.length < @rows
if @children.length < @rows
line = @document.createElement("div")
line.className = 'line'
@@ -1562,7 +1567,7 @@ class Terminal
eraseLine: (y) ->
@eraseRight 0, y
blank_line: (cur) ->
blankLine: (cur) ->
attr = (if cur then @eraseAttr() else @defAttr)
line = []
i = 0
@@ -1587,17 +1592,17 @@ class Terminal
# ESC D Index (IND is 0x84).
index: ->
@next_line()
@nextLine()
@state = State.normal
# ESC M Reverse Index (RI is 0x8d).
reverseIndex: ->
@prev_line()
@prevLine()
@state = State.normal
# ESC c Full Reset (RIS).
reset: ->
@reset_vars()
@resetVars()
@refresh(true)
# ESC H Tab Set (HTS is 0x88).
@@ -1956,8 +1961,8 @@ class Terminal
param = 1 if param < 1
while param--
@screen.splice @y + @shift, 0, [@blank_line(true), true]
# blank_line(true) - xterm/linux behavior
@screen.splice @y + @shift, 0, [@blankLine(true), true]
# blankLine(true) - xterm/linux behavior
@screen.splice @scrollBottom + 1 + @shift, 1
for i in [@y + @shift..@screen.length - 1]
@@ -1971,8 +1976,8 @@ class Terminal
while param--
# test: echo -e '\e[44m\e[1M\e[0m'
# blank_line(true) - xterm/linux behavior
@screen.splice @scrollBottom + @shift, 0, [@blank_line(true), true]
# blankLine(true) - xterm/linux behavior
@screen.splice @scrollBottom + @shift, 0, [@blankLine(true), true]
@screen.splice @y + @shift, 1
unless @normal or @scrollTop isnt 0 or @scrollBottom isnt @rows - 1
@children[@y + @shift].remove()
@@ -2455,7 +2460,7 @@ class Terminal
param = params[0] or 1
while param--
@screen.splice @scrollTop, 1
@screen.splice @scrollBottom, 0, [@blank_line(), true]
@screen.splice @scrollBottom, 0, [@blankLine(), true]
for i in [@scrollTop..@scrollBottom]
@screen[i + @shift][1] = true
@@ -2466,7 +2471,7 @@ class Terminal
param = params[0] or 1
while param--
@screen.splice @scrollBottom, 1
@screen.splice @scrollTop, 0, [@blank_line(), true]
@screen.splice @scrollTop, 0, [@blankLine(), true]
for i in [@scrollTop..@scrollBottom]
@screen[i + @shift][1] = true