From 97d435ce1826a5be62b897058769d6b4e05d7030 Mon Sep 17 00:00:00 2001 From: Florian Mounier Date: Thu, 29 Sep 2016 11:31:45 +0200 Subject: [PATCH] Add horizontal wrap (expandable no wrapping lines) on decset 77 --- butterfly/sass/_layout.sass | 28 +++++++++++ butterfly/static/ext.js | 23 +++++++++ butterfly/static/main.css | 21 +++++++++ butterfly/static/main.js | 76 ++++++++++++++++++++---------- coffees/ext/expand_extended.coffee | 9 ++++ coffees/term.coffee | 70 +++++++++++++++++---------- 6 files changed, 177 insertions(+), 50 deletions(-) create mode 100644 coffees/ext/expand_extended.coffee diff --git a/butterfly/sass/_layout.sass b/butterfly/sass/_layout.sass index ac0637e..5b19c37 100644 --- a/butterfly/sass/_layout.sass +++ b/butterfly/sass/_layout.sass @@ -29,6 +29,34 @@ body .line.active background-color: $active-bg + .line.extended + overflow-x: auto + overflow-x: overlay + cursor: zoom-in + background-image: linear-gradient(90deg, rgba(darken($bg, 3%), 0), 95%, darken($bg, 3%)) + + &:not(.expanded):hover + background-color: lighten($bg, 2%) + + &.expanded + cursor: zoom-out + background-color: darken($bg, 3%) + + .extra + display: block + white-space: pre-line + word-break: break-all + + &::-webkit-scrollbar + background: rgba($scroll-bg, .1) + height: 0 + + &::-webkit-scrollbar-thumb + background: rgba($scroll-fg, .1) + + &::-webkit-scrollbar-thumb:hover + background: rgba($scroll-fg-hover, .1) + &::-webkit-scrollbar background: $scroll-bg width: $scroll-width diff --git a/butterfly/static/ext.js b/butterfly/static/ext.js index f1d975f..c77169d 100644 --- a/butterfly/static/ext.js +++ b/butterfly/static/ext.js @@ -156,6 +156,29 @@ } }); + Terminal.on('change', function(lines) { + var j, len1, line, results; + results = []; + for (j = 0, len1 = lines.length; j < len1; j++) { + line = lines[j]; + if (indexOf.call(line.classList, 'extended') >= 0) { + results.push(line.addEventListener('click', (function(line) { + return function() { + if (indexOf.call(line.classList, 'expanded') >= 0) { + return line.classList.remove('expanded'); + } else { + line.classList.add('expanded'); + return butterfly.nativeScrollTo(); + } + }; + })(line))); + } else { + results.push(void 0); + } + } + return results; + }); + walk = function(node, callback) { var child, j, len1, ref, results; ref = node.childNodes; diff --git a/butterfly/static/main.css b/butterfly/static/main.css index 036663b..949bc20 100644 --- a/butterfly/static/main.css +++ b/butterfly/static/main.css @@ -2816,6 +2816,27 @@ body { /* Pop ups */ } body .line.active { background-color: transparent; } + body .line.extended { + overflow-x: auto; + overflow-x: overlay; + cursor: zoom-in; + background-image: linear-gradient(90deg, rgba(9, 8, 10, 0), 95%, #09080a); } + body .line.extended:not(.expanded):hover { + background-color: #161419; } + body .line.extended.expanded { + cursor: zoom-out; + background-color: #09080a; } + body .line.extended.expanded .extra { + display: block; + white-space: pre-line; + word-break: break-all; } + body .line.extended::-webkit-scrollbar { + background: rgba(17, 15, 19, 0.1); + height: 0; } + body .line.extended::-webkit-scrollbar-thumb { + background: rgba(244, 234, 213, 0.1); } + body .line.extended::-webkit-scrollbar-thumb:hover { + background: rgba(244, 234, 213, 0.1); } body::-webkit-scrollbar { background: #110f13; width: 0.75em; } diff --git a/butterfly/static/main.js b/butterfly/static/main.js index 3f346a8..1269ddd 100644 --- a/butterfly/static/main.js +++ b/butterfly/static/main.js @@ -282,6 +282,7 @@ this.applicationCursor = false; this.originMode = false; this.autowrap = true; + this.horizontalWrap = false; this.normal = null; this.charset = null; this.gcharset = null; @@ -535,7 +536,7 @@ }; Terminal.prototype.refresh = function(force) { - var active, attr, ch, classes, cursor, data, fg, group, i, j, k, len, len1, len2, len3, len4, line, lines, m, modified, newOut, o, out, q, ref, ref1, ref2, ref3, ref4, ref5, skipnext, styles, u, v, x; + var active, attr, ch, classes, cls, cursor, data, fg, group, i, j, k, len, len1, len2, len3, len4, line, lines, m, modified, newOut, o, out, q, ref, ref1, ref2, ref3, ref4, ref5, skipnext, styles, u, v, x; if (force == null) { force = false; } @@ -678,14 +679,27 @@ if (line.wrap) { out += '\u23CE'; } + if (line.extra) { + out += '' + line.extra + ''; + } if (this.children[j]) { this.children[j].innerHTML = out; modified.push(this.children[j]); if (x !== -Infinity) { this.children[j].classList.add('active'); } + if (line.extra) { + this.children[j].classList.add('extended'); + } } else { - newOut += "
" + out + "
"; + cls = ['line']; + if (x !== -Infinity) { + cls.push('active'); + } + if (line.extra) { + cls.push('extended'); + } + newOut += "
" + out + "
"; } this.screen[j].dirty = false; } @@ -831,11 +845,17 @@ case "\n": case "\x0b": case "\x0c": - this.screen[this.y + this.shift].dirty = true; - this.nextLine(); + if (this.horizontalWrap) { + this.screen[this.y + this.shift].extra += ch; + } else { + this.screen[this.y + this.shift].dirty = true; + this.nextLine(); + } break; case "\r": - this.x = 0; + if (!this.horizontalWrap) { + this.x = 0; + } break; case "\b": if (this.x >= this.cols) { @@ -877,11 +897,15 @@ ch = this.charset[ch]; } if (this.x >= this.cols) { - if (this.autowrap) { - this.screen[this.y + this.shift].wrap = true; - this.nextLine(); + if (this.horizontalWrap) { + this.screen[this.y + this.shift].extra += ch; + } else { + if (this.autowrap) { + this.screen[this.y + this.shift].wrap = true; + this.nextLine(); + } + this.x = 0; } - this.x = 0; } this.putChar(ch); this.x++; @@ -1291,8 +1315,7 @@ attr = this.cloneAttr(this.curAttr); attr.html = "
" + safe + "
"; this.screen[this.y + this.shift].chars[this.x] = attr; - this.screen[this.y + this.shift].dirty = true; - this.screen[this.y + this.shift].wrap = false; + this.resetLine(this.screen[this.y + this.shift]); this.nextLine(); break; case "IMAGE": @@ -1307,8 +1330,7 @@ attr = this.cloneAttr(this.curAttr); attr.html = ""; this.screen[this.y + this.shift].chars[this.x] = attr; - this.screen[this.y + this.shift].dirty = true; - this.screen[this.y + this.shift].wrap = false; + this.resetLine(this.screen[this.y + this.shift]); break; case "PROMPT": this.send(content); @@ -1865,8 +1887,7 @@ line[x] = this.eraseAttr(); x++; } - this.screen[y + this.shift].dirty = true; - return this.screen[y + this.shift].wrap = false; + return this.resetLine(this.screen[y + this.shift]); }; Terminal.prototype.eraseLeft = function(x, y) { @@ -1874,14 +1895,19 @@ while (x--) { this.screen[y + this.shift].chars[x] = this.eraseAttr(); } - this.screen[y + this.shift].dirty = true; - return this.screen[y + this.shift].wrap = false; + return this.resetLine(this.screen[y + this.shift]); }; Terminal.prototype.eraseLine = function(y) { return this.eraseRight(0, y); }; + Terminal.prototype.resetLine = function(l) { + l.dirty = true; + l.wrap = false; + return l.extra = ''; + }; + Terminal.prototype.blankLine = function(cur, dirty) { var attr, i, line; if (cur == null) { @@ -1900,7 +1926,8 @@ return { chars: line, dirty: dirty, - wrap: false + wrap: false, + extra: '' }; }; @@ -2304,8 +2331,7 @@ this.screen[this.y + this.shift].chars.splice(this.x, 1); this.screen[this.y + this.shift].chars.push(this.eraseAttr()); } - this.screen[this.y + this.shift].dirty = true; - return this.screen[this.y + this.shift].wrap = false; + return this.resetLine(this.screen[this.y + this.shift]); }; Terminal.prototype.eraseChars = function(params) { @@ -2318,8 +2344,7 @@ while (param-- && j < this.cols) { this.screen[this.y + this.shift].chars[j++] = this.eraseAttr(); } - this.screen[this.y + this.shift].dirty = true; - return this.screen[this.y + this.shift].wrap = false; + return this.resetLine(this.screen[this.y + this.shift]); }; Terminal.prototype.charPosAbsolute = function(params) { @@ -2455,6 +2480,8 @@ return this.autowrap = true; case 66: return this.applicationKeypad = true; + case 77: + return this.horizontalWrap = true; case 9: case 1000: case 1002: @@ -2534,6 +2561,8 @@ return this.autowrap = false; case 66: return this.applicationKeypad = false; + case 77: + return this.horizontalWrap = false; case 9: case 1000: case 1002: @@ -2834,8 +2863,7 @@ while (i < l) { this.screen[i].chars.splice(this.x, 1); this.screen[i].chars.push(this.eraseAttr()); - this.screen[i].dirty = true; - this.screen[i].wrap = false; + this.resetLine(this.screen[i].dirty); results1.push(i++); } return results1; diff --git a/coffees/ext/expand_extended.coffee b/coffees/ext/expand_extended.coffee new file mode 100644 index 0000000..9361333 --- /dev/null +++ b/coffees/ext/expand_extended.coffee @@ -0,0 +1,9 @@ +Terminal.on 'change', (lines) -> + for line in lines + if 'extended' in line.classList + line.addEventListener 'click', do (line) -> -> + if 'expanded' in line.classList + line.classList.remove 'expanded' + else + line.classList.add 'expanded' + butterfly.nativeScrollTo() diff --git a/coffees/term.coffee b/coffees/term.coffee index 7be84a1..d7ef5fe 100644 --- a/coffees/term.coffee +++ b/coffees/term.coffee @@ -168,6 +168,7 @@ class Terminal @applicationCursor = false @originMode = false @autowrap = true + @horizontalWrap = false @normal = null # charset @@ -421,6 +422,8 @@ class Terminal @document.createTextNode(cursor.textContent), cursor) for active in @body.querySelectorAll(".line.active") active.classList.remove('active') + # for active in @body.querySelectorAll(".line.extended") + # active.classList.remove('extended') newOut = '' modified = [] @@ -526,14 +529,22 @@ class Terminal attr = data out += "" unless @equalAttr attr, @defAttr out += '\u23CE' if line.wrap + if line.extra + out += '' + line.extra + '' if @children[j] @children[j].innerHTML = out modified.push @children[j] if x isnt -Infinity @children[j].classList.add 'active' + if line.extra + @children[j].classList.add 'extended' else - newOut += "
#{out}
" + cls = ['line'] + if x isnt -Infinity + cls.push 'active' + if line.extra + cls.push 'extended' + newOut += "
#{out}
" @screen[j].dirty = false if newOut isnt '' @@ -644,12 +655,16 @@ class Terminal # '\n', '\v', '\f' when "\n", "\x0b", "\x0c" # @x = 0 if @convertEol - @screen[@y + @shift].dirty = true - @nextLine() + if @horizontalWrap + @screen[@y + @shift].extra += ch + else + @screen[@y + @shift].dirty = true + @nextLine() # '\r' when "\r" - @x = 0 + unless @horizontalWrap + @x = 0 # '\b' when "\b" @@ -697,11 +712,13 @@ class Terminal if ch >= " " ch = @charset[ch] if @charset?[ch] if @x >= @cols - if @autowrap - @screen[@y + @shift].wrap = true - @nextLine() - @x = 0 - + if @horizontalWrap + @screen[@y + @shift].extra += ch + else + if @autowrap + @screen[@y + @shift].wrap = true + @nextLine() + @x = 0 @putChar ch @x++ if @forceWidth and "\uff00" < ch < "\uffef" @@ -1150,8 +1167,6 @@ class Terminal switch @prefix # User-Defined Keys (DECUDK). when "" - # Disabling this for now as we need a good script - # striper to avoid malicious script injection pt = @currentParam unless pt[0] is ';' console.error "Unknown DECUDK: #{pt}" @@ -1171,8 +1186,7 @@ class Terminal attr.html = ( "
#{safe}
") @screen[@y + @shift].chars[@x] = attr - @screen[@y + @shift].dirty = true - @screen[@y + @shift].wrap = false + @resetLine @screen[@y + @shift] @nextLine() when "IMAGE" @@ -1190,8 +1204,7 @@ class Terminal "") @screen[@y + @shift].chars[@x] = attr - @screen[@y + @shift].dirty = true - @screen[@y + @shift].wrap = false + @resetLine @screen[@y + @shift] when "PROMPT" @send content @@ -1690,18 +1703,21 @@ class Terminal while x < @cols line[x] = @eraseAttr() x++ - @screen[y + @shift].dirty = true - @screen[y + @shift].wrap = false + @resetLine @screen[y + @shift] eraseLeft: (x, y) -> x++ @screen[y + @shift].chars[x] = @eraseAttr() while x-- - @screen[y + @shift].dirty = true - @screen[y + @shift].wrap = false + @resetLine @screen[y + @shift] eraseLine: (y) -> @eraseRight 0, y + resetLine: (l) -> + l.dirty = true + l.wrap = false + l.extra = '' + blankLine: (cur=false, dirty=true) -> attr = (if cur then @eraseAttr() else @defAttr) line = [] @@ -1713,6 +1729,7 @@ class Terminal chars: line dirty: dirty wrap: false + extra: '' ch: (cur) -> if cur then @eraseAttr() else @defAttr @@ -2193,8 +2210,7 @@ class Terminal while param-- @screen[@y + @shift].chars.splice @x, 1 @screen[@y + @shift].chars.push @eraseAttr() - @screen[@y + @shift].dirty = true - @screen[@y + @shift].wrap = false + @resetLine @screen[@y + @shift] # CSI Ps X # Erase Ps Character(s) (default = 1) (ECH). @@ -2204,8 +2220,7 @@ class Terminal j = @x # xterm @screen[@y + @shift].chars[j++] = @eraseAttr() while param-- and j < @cols - @screen[@y + @shift].dirty = true - @screen[@y + @shift].wrap = false + @resetLine @screen[@y + @shift] # CSI Pm ` Character Position Absolute # [column] (default = [row,1]) (HPA). @@ -2434,6 +2449,8 @@ class Terminal @autowrap = true when 66 @applicationKeypad = true + when 77 + @horizontalWrap = true # X10 Mouse # no release, no motion, no wheel, no modifiers. when 9, 1000, 1002, 1003 # any event mouse @@ -2595,6 +2612,8 @@ class Terminal @autowrap = false when 66 @applicationKeypad = false + when 77 + @horizontalWrap = false when 9, 1000, 1002 , 1003 # any event mouse @x10Mouse = false @vt200Mouse = false @@ -3175,8 +3194,7 @@ class Terminal while i < l @screen[i].chars.splice @x, 1 @screen[i].chars.push @eraseAttr() - @screen[i].dirty = true - @screen[i].wrap = false + @resetLine @screen[i].dirty i++ # DEC Special Character and Line Drawing Set.