Finally a near perfect resize

This commit is contained in:
Florian Mounier
2016-10-13 15:24:57 +02:00
parent 5a7c4da0b1
commit b9f1727f1e
5 changed files with 140 additions and 198 deletions

File diff suppressed because one or more lines are too long

View File

@@ -177,6 +177,7 @@
this.document = this.parent.ownerDocument;
this.html = this.document.getElementsByTagName('html')[0];
this.body = this.document.getElementsByTagName('body')[0];
this.term = this.document.getElementById('term');
this.forceWidth = this.body.getAttribute('data-force-unicode-width') === 'yes';
this.body.className = 'terminal focus';
this.body.style.outline = 'none';
@@ -184,13 +185,11 @@
this.body.setAttribute('spellcheck', 'false');
div = this.document.createElement('div');
div.className = 'line';
this.body.appendChild(div);
this.children = [div];
this.term.appendChild(div);
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 = 10000;
this.buffSize = 100000;
this.visualBell = 100;
@@ -280,7 +279,7 @@
};
Terminal.prototype.resetVars = function() {
var i;
var k, ref, row;
this.x = 0;
this.y = 0;
this.cursorHidden = false;
@@ -317,9 +316,8 @@
this.currentParam = 0;
this.prefix = "";
this.screen = [];
i = this.rows;
this.shift = 0;
while (i--) {
for (row = k = 0, ref = this.rows; 0 <= ref ? k <= ref : k >= ref; row = 0 <= ref ? ++k : --k) {
this.screen.push(this.blankLine(false, false));
}
this.setupStops();
@@ -327,15 +325,16 @@
};
Terminal.prototype.computeCharSize = function() {
var testSpan;
var line, testSpan;
testSpan = document.createElement('span');
testSpan.textContent = '0123456789';
this.children[0].appendChild(testSpan);
line = this.term.firstChild;
line.appendChild(testSpan);
this.charSize = {
width: testSpan.getBoundingClientRect().width / 10,
height: this.children[0].getBoundingClientRect().height
height: line.getBoundingClientRect().height
};
return this.children[0].removeChild(testSpan);
return line.removeChild(testSpan);
};
Terminal.prototype.eraseAttr = function() {
@@ -705,34 +704,31 @@
};
Terminal.prototype.writeDom = function(dom) {
var i, k, len, line, m, ref, y;
var frag, i, k, len, line, m, r, ref, results, y;
r = Math.max(this.term.childElementCount - this.rows, 0);
for (y = k = 0, len = dom.length; k < len; y = ++k) {
line = dom[y];
if (!line) {
continue;
}
this.screen[y].dirty = false;
if (y < this.children.length) {
this.body.replaceChild(line, this.children[y]);
this.children[y] = line;
this.emit('change', this.children[y]);
if (y < this.rows && y < this.term.childElementCount) {
this.term.replaceChild(line, this.term.childNodes[r + y]);
} else {
if (this.children.length >= this.rows) {
this.children.shift();
}
this.body.appendChild(line);
this.children.push(line);
this.emit('change', line);
frag = frag || document.createDocumentFragment('fragment');
frag.appendChild(line);
}
this.emit('change', line);
}
this.screen = this.screen.slice(-this.rows);
frag && this.term.appendChild(frag);
this.shift = 0;
if (this.body.childElementCount > this.scrollback) {
this.body.style.display = 'none';
for (i = m = 0, ref = this.body.childElementCount - this.scrollback; 0 <= ref ? m <= ref : m >= ref; i = 0 <= ref ? ++m : --m) {
this.body.firstChild.remove();
this.screen = this.screen.slice(-this.rows);
if (this.term.childElementCount > this.scrollback) {
results = [];
for (i = m = 0, ref = this.term.childElementCount - this.scrollback; 0 <= ref ? m <= ref : m >= ref; i = 0 <= ref ? ++m : --m) {
results.push(this.term.firstChild.remove());
}
return this.body.style.display = 'block';
return results;
}
};
@@ -752,7 +748,7 @@
Terminal.prototype._cursorBlink = function() {
var cursor;
this.cursorState ^= 1;
cursor = this.body.querySelector(".cursor");
cursor = this.term.querySelector(".cursor");
if (!cursor) {
return;
}
@@ -1705,7 +1701,7 @@
};
Terminal.prototype.resize = function(x, y, notif) {
var h, i, j, oldCols, oldRows, px, w;
var h, insert, k, len, len1, len2, len3, line, m, n, o, oldCols, oldRows, ref, ref1, ref2, ref3, w;
if (x == null) {
x = null;
}
@@ -1726,8 +1722,6 @@
}
this.cols = x || Math.floor(w / this.charSize.width);
this.rows = y || Math.floor(h / this.charSize.height);
px = h % this.charSize.height;
this.body.style['padding-bottom'] = px + "px";
this.cols = Math.max(1, this.cols);
this.rows = Math.max(1, this.rows);
this.nativeScrollTo();
@@ -1741,67 +1735,62 @@
rows: this.rows
}));
}
if (oldCols < this.cols) {
i = this.screen.length;
while (i--) {
while (this.screen[i].chars.length < this.cols) {
this.screen[i].chars.push(this.defAttr);
if (this.cols > oldCols) {
ref = this.screen;
for (k = 0, len = ref.length; k < len; k++) {
line = ref[k];
while (line.chars.length < this.cols) {
line.chars.push(this.defAttr);
}
this.screen[i].wrap = false;
line.wrap = false;
}
} else if (oldCols > this.cols) {
i = this.screen.length;
while (i--) {
while (this.screen[i].chars.length > this.cols) {
this.screen[i].chars.pop();
if (this.normal) {
ref1 = this.normal.screen;
for (m = 0, len1 = ref1.length; m < len1; m++) {
line = ref1[m];
while (line.chars.length < this.cols) {
line.chars.push(this.defAttr);
}
line.wrap = false;
}
}
} else if (this.cols < oldCols) {
ref2 = this.screen;
for (n = 0, len2 = ref2.length; n < len2; n++) {
line = ref2[n];
while (line.chars.length > this.cols) {
line.chars.pop();
}
}
if (this.normal) {
ref3 = this.normal.screen;
for (o = 0, len3 = ref3.length; o < len3; o++) {
line = ref3[o];
while (line.chars.length > this.cols) {
line.chars.pop();
}
}
}
}
this.setupStops(oldCols);
j = oldRows;
if (j < this.rows) {
while (j++ < this.rows) {
if (this.screen.length < this.rows) {
this.screen.push(this.blankLine());
}
}
} else if (j > this.rows) {
while (j-- > this.rows) {
if (this.screen.length > this.rows) {
this.screen.pop();
}
}
if (this.term.childElementCount >= this.rows) {
this.y += this.rows - oldRows;
insert = 'unshift';
} else {
insert = 'push';
}
while (this.screen.length > this.rows) {
this.screen.shift();
}
while (this.screen.length < this.rows) {
this.screen[insert](this.blankLine(false, false));
}
if (this.normal) {
if (oldCols < this.cols) {
i = this.normal.screen.length;
while (i--) {
while (this.normal.screen[i].chars.length < this.cols) {
this.normal.screen[i].chars.push(this.defAttr);
}
this.normal.screen[i].wrap = false;
}
} else if (oldCols > this.cols) {
i = this.normal.screen.length;
while (i--) {
while (this.normal.screen[i].chars.length > this.cols) {
this.normal.screen[i].chars.pop();
}
}
while (this.normal.screen.length > this.rows) {
this.normal.screen.shift();
}
j = oldRows;
if (j < this.rows) {
while (j++ < this.rows) {
if (this.normal.screen.length < this.rows) {
this.normal.screen.push(this.blankLine());
}
}
} else if (j > this.rows) {
while (j-- > this.rows) {
if (this.normal.screen.length > this.rows) {
this.normal.screen.pop();
}
}
while (this.normal.screen.length < this.rows) {
this.normal.screen[insert](this.blankLine(false, false));
}
}
if (this.y >= this.rows) {
@@ -1812,7 +1801,7 @@
}
this.scrollTop = 0;
this.scrollBottom = this.rows - 1;
this.refresh(true);
this.refresh();
if (!notif && (x || y)) {
return this.reset();
}
@@ -1966,22 +1955,12 @@
};
Terminal.prototype.clearScrollback = function() {
var group, k, len, len1, line, lines, m, ref, ref1;
lines = document.querySelectorAll('.line');
if (lines.length > this.rows) {
ref = Array.prototype.slice.call(lines, 0, lines.length - this.rows);
for (k = 0, len = ref.length; k < len; k++) {
line = ref[k];
line.remove();
}
ref1 = document.querySelectorAll('.group:empty');
for (m = 0, len1 = ref1.length; m < len1; m++) {
group = ref1[m];
group.remove();
}
lines = document.querySelectorAll('.line');
var results;
results = [];
while (this.term.childElementCount > this.rows) {
results.push(this.term.firstChild.remove());
}
return this.children = Array.prototype.slice.call(lines, -this.rows);
return results;
};
Terminal.prototype.tabSet = function() {
@@ -2298,7 +2277,7 @@
};
Terminal.prototype.deleteLines = function(params) {
var i, k, param, ref, ref1, results;
var i, k, node, param, ref, ref1, results;
param = params[0];
if (param < 1) {
param = 1;
@@ -2307,8 +2286,8 @@
this.screen.splice(this.scrollBottom + this.shift, 0, this.blankLine(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();
this.children.splice(this.y + this.shift, 1);
node = this.term.childElementCount - this.rows + this.y + this.shift;
this.term.childNodes[node].remove();
}
}
if (this.normal || this.scrollTop !== 0 || this.scrollBottom !== this.rows - 1) {

File diff suppressed because one or more lines are too long

View File

@@ -24,5 +24,6 @@
<script src="{{ static_url('ext.%sjs' % (
'' if options.unminified else 'min.')) }}"></script>
<script src="{{ reverse_url('LocalJsStatic') }}"></script>
<div id="term"></div>
</body>
</html>

View File

@@ -63,6 +63,7 @@ class Terminal
@document = @parent.ownerDocument
@html = @document.getElementsByTagName('html')[0]
@body = @document.getElementsByTagName('body')[0]
@term = @document.getElementById('term')
@forceWidth = @body.getAttribute(
'data-force-unicode-width') is 'yes'
@@ -75,14 +76,12 @@ class Terminal
# Adding one line to compute char size
div = @document.createElement('div')
div.className = 'line'
@body.appendChild(div)
@children = [div]
@term.appendChild(div)
@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 = 10000
@buffSize = 100000
@@ -198,20 +197,21 @@ class Terminal
@currentParam = 0
@prefix = ""
@screen = []
i = @rows
@shift = 0
@screen.push @blankLine(false, false) while i--
for row in [0..@rows]
@screen.push @blankLine(false, false)
@setupStops()
@skipNextKey = null
computeCharSize: ->
testSpan = document.createElement('span')
testSpan.textContent = '0123456789'
@children[0].appendChild(testSpan)
line = @term.firstChild
line.appendChild(testSpan)
@charSize =
width: testSpan.getBoundingClientRect().width / 10
height: @children[0].getBoundingClientRect().height
@children[0].removeChild(testSpan)
height: line.getBoundingClientRect().height
line.removeChild(testSpan)
eraseAttr: ->
erased = @cloneAttr @defAttr
@@ -520,29 +520,24 @@ class Terminal
@active = div
writeDom: (dom) ->
# frag = document.createDocumentFragment('fragment')
r = Math.max @term.childElementCount - @rows, 0
for line, y in dom
continue unless line
@screen[y].dirty = false
if y < @children.length
@body.replaceChild line, @children[y]
@children[y] = line
@emit 'change', @children[y]
if y < @rows and y < @term.childElementCount
@term.replaceChild(line, @term.childNodes[r + y])
else
@children.shift() if @children.length >= @rows
@body.appendChild line
@children.push line
@emit 'change', line
frag = frag or document.createDocumentFragment('fragment')
frag.appendChild line
@emit 'change', line
# @body.appendChild frag
frag and @term.appendChild frag
@screen = @screen.slice(-@rows)
@shift = 0
if @body.childElementCount > @scrollback
@body.style.display = 'none'
for i in [0..@body.childElementCount - @scrollback]
@body.firstChild.remove()
@body.style.display = 'block'
@screen = @screen.slice -@rows
if @term.childElementCount > @scrollback
for i in [0..@term.childElementCount - @scrollback]
@term.firstChild.remove()
refresh: (force=false) ->
@active?.classList.remove('active')
@@ -552,7 +547,7 @@ class Terminal
_cursorBlink: ->
@cursorState ^= 1
cursor = @body.querySelector(".cursor")
cursor = @term.querySelector(".cursor")
return unless cursor
if cursor.classList.contains("reverse-video")
cursor.classList.remove "reverse-video"
@@ -1558,8 +1553,6 @@ class Terminal
return
@cols = x or Math.floor(w / @charSize.width)
@rows = y or Math.floor(h / @charSize.height)
px = h % @charSize.height
@body.style['padding-bottom'] = "#{px}px"
@cols = Math.max 1, @cols
@rows = Math.max 1, @rows
@@ -1572,72 +1565,50 @@ class Terminal
cmd: 'size', cols: @cols, rows: @rows)) unless notif
# resize cols
if oldCols < @cols
if @cols > oldCols
# does xterm use the default attr?
i = @screen.length
while i--
@screen[i].chars.push @defAttr while @screen[i].chars.length < @cols
@screen[i].wrap = false
for line in @screen
line.chars.push @defAttr while line.chars.length < @cols
line.wrap = false
if @normal
for line in @normal.screen
line.chars.push @defAttr while line.chars.length < @cols
line.wrap = false
else if oldCols > @cols
i = @screen.length
while i--
@screen[i].chars.pop() while @screen[i].chars.length > @cols
else if @cols < oldCols
for line in @screen
line.chars.pop() while line.chars.length > @cols
if @normal
for line in @normal.screen
line.chars.pop() while line.chars.length > @cols
@setupStops oldCols
if @term.childElementCount >= @rows
@y += @rows - oldRows
insert = 'unshift'
else
insert = 'push'
# resize rows
j = oldRows
if j < @rows
# @body.style.display = 'none'
while j++ < @rows
@screen.push @blankLine() if @screen.length < @rows
# if @children.length < @rows
# line = @document.createElement("div")
# line.className = 'line'
# @body.appendChild line
# @children.push line
# @body.style.display = 'block'
else if j > @rows
while j-- > @rows
@screen.pop() if @screen.length > @rows
# if @children.length > @rows
# el = @children.pop()
# el?.parentNode.removeChild el
while @screen.length > @rows
@screen.shift()
while @screen.length < @rows
@screen[insert] @blankLine(false, false)
if @normal
# resize cols
if oldCols < @cols
# does xterm use the default attr?
i = @normal.screen.length
while i--
while @normal.screen[i].chars.length < @cols
@normal.screen[i].chars.push @defAttr
@normal.screen[i].wrap = false
else if oldCols > @cols
i = @normal.screen.length
while i--
while @normal.screen[i].chars.length > @cols
@normal.screen[i].chars.pop()
# resize rows
j = oldRows
if j < @rows
while j++ < @rows
@normal.screen.push @blankLine() if @normal.screen.length < @rows
else if j > @rows
while j-- > @rows
@normal.screen.pop() if @normal.screen.length > @rows
while @normal.screen.length > @rows
@normal.screen.shift()
while @normal.screen.length < @rows
@normal.screen[insert] @blankLine(false, false)
# make sure the cursor stays on screen
@y = @rows - 1 if @y >= @rows
@x = @cols - 1 if @x >= @cols
@scrollTop = 0
@scrollBottom = @rows - 1
@refresh(true)
@refresh()
@reset() if not notif and (x or y)
resizeWindowPlease: (cols) ->
@@ -1737,17 +1708,8 @@ class Terminal
clearScrollback: ->
# In case of real hard reset
# Drop DOM history
lines = document.querySelectorAll('.line')
if lines.length > @rows
for line in Array.prototype.slice.call(
lines, 0, lines.length - @rows)
line.remove()
for group in document.querySelectorAll('.group:empty')
group.remove()
lines = document.querySelectorAll('.line')
@children = Array.prototype.slice.call(
lines, -@rows)
while @term.childElementCount > @rows
@term.firstChild.remove()
# ESC H Tab Set (HTS is 0x88).
tabSet: ->
@@ -2168,8 +2130,8 @@ class Terminal
@screen.splice @scrollBottom + @shift, 0, @blankLine(true)
@screen.splice @y + @shift, 1
unless @normal or @scrollTop isnt 0 or @scrollBottom isnt @rows - 1
@children[@y + @shift].remove()
@children.splice @y + @shift, 1
node = @term.childElementCount - @rows + @y + @shift
@term.childNodes[node].remove()
if @normal or @scrollTop isnt 0 or @scrollBottom isnt @rows - 1
for i in [@y + @shift..@screen.length - 1]