From 2a27089243369855b53c488c9957810cfd794799 Mon Sep 17 00:00:00 2001 From: Marcin Kulik Date: Thu, 17 Mar 2011 23:18:49 +0100 Subject: [PATCH] Added support for alternate screen buffer (1049 h/l codes) --- public/javascripts/ansi-interpreter.js | 12 +- public/javascripts/player.js | 2 +- public/javascripts/terminal.js | 163 ++++++++++++++++--------- 3 files changed, 114 insertions(+), 63 deletions(-) diff --git a/public/javascripts/ansi-interpreter.js b/public/javascripts/ansi-interpreter.js index 20a3dc5..b1ce571 100644 --- a/public/javascripts/ansi-interpreter.js +++ b/public/javascripts/ansi-interpreter.js @@ -59,17 +59,25 @@ SP.AnsiInterpreter.prototype = { "\x1b\\[\\?([\x30-\x3f]+)([hlsr])": function(data, match) { // private standards // h = Sets DEC/xterm specific mode (http://ttssh2.sourceforge.jp/manual/en/about/ctrlseq.html#decmode) // l = Resets mode (http://ttssh2.sourceforge.jp/manual/en/about/ctrlseq.html#mode) - // 1049 + h = Save cursor position, switch to alternate screen buffer, and clear screen. - // 1049 + l = Clear screen, switch to normal screen buffer, and restore cursor position. // 1001 + s = ? // 1001 + r = ? if (match[1] == '1049') { if (match[2] == 'h') { + // 1049 + h = Save cursor position, switch to alternate screen buffer, and clear screen. this.terminal.saveCursor(); + this.terminal.switchToAlternateBuffer(); + this.terminal.clearScreen(); } else if (match[2] == 'l') { + // 1049 + l = Clear screen, switch to normal screen buffer, and restore cursor position. + this.terminal.clearScreen(); + this.terminal.switchToNormalBuffer(); this.terminal.restoreCursor(); } + } else if (match[1] == '1002') { + // 2002 + h / l = mouse tracking stuff + } else if (match[1] == '1') { + // 1 + h / l = cursor keys stuff } }, diff --git a/public/javascripts/player.js b/public/javascripts/player.js index c0098ba..c3eabb4 100644 --- a/public/javascripts/player.js +++ b/public/javascripts/player.js @@ -28,7 +28,7 @@ SP.Player.prototype = { var run = function() { var rest = this.interpreter.feed(this.currentData); - this.terminal.updateDirtyLines(); + this.terminal.renderDirtyLines(); var n = timing[1]; if (rest.length > 0) diff --git a/public/javascripts/terminal.js b/public/javascripts/terminal.js index f96c4bb..ac862e6 100644 --- a/public/javascripts/terminal.js +++ b/public/javascripts/terminal.js @@ -3,7 +3,9 @@ SP.Terminal = function(cols, lines) { this.lines = lines; this.cursorLine = 0; this.cursorCol = 0; - this.lineData = []; + this.normalBuffer = []; + this.alternateBuffer = []; + this.lineData = this.normalBuffer; this.fg = this.bg = undefined; this.dirtyLines = []; this.initialize(); @@ -13,48 +15,65 @@ SP.Terminal.prototype = { initialize: function() { var container = $(".player .term"); this.element = container; - for (l = 0; l < this.lines; l++) { - var row = $(""); - container.append(row); - container.append("\n"); - this.lineData[l] = []; - this.updateLine(l); + this.renderLine(0); // we only need 1 line + this.element.css({ height: this.element.height() * this.lines }); + }, + + getLine: function(n) { + n = (typeof n != "undefined" ? n : this.cursorLine); + + var line = this.lineData[n]; + + if (typeof line == 'undefined') { + line = this.lineData[n] = []; + this.fill(n, 0, this.cols, ' '); } + + return line; }, - setSGR: function(codes) { - if (codes.length == 0) { - codes = [0]; + clearScreen: function() { + this.lineData.length = 0; + this.cursorLine = this.cursorCol = 0; + this.element.empty(); + }, + + switchToNormalBuffer: function() { + this.lineData = this.normalBuffer; + this.updateScreen(); + }, + + switchToAlternateBuffer: function() { + this.lineData = this.alternateBuffer; + this.updateScreen(); + }, + + renderLine: function(n) { + var html = this.getLine(n); + + if (n == this.cursorLine) { + html = html.slice(0, this.cursorCol).concat(['' + (html[this.cursorCol] || '') + ""], html.slice(this.cursorCol + 1) || []); } - for (var i=0; i= 30 && n <= 37) { - this.fg = n - 30; - } else if (n >= 40 && n <= 47) { - this.bg = n - 40; - } + for (var i = 0; i < missingLines; i++) { + var row = $(''); + this.element.append(row); + this.element.append("\n"); + this.element.scrollTop(100000);//row.offset().top); } - }, - updateLine: function(n) { - n = (typeof n != "undefined" ? n : this.cursorLine); - this.dirtyLines.push(n); + this.element.find(".line:eq(" + n + ")").html(html.join('')); }, - updateDirtyLines: function() { + renderDirtyLines: function() { var updated = []; for (var i=0; i' + (text[this.cursorCol] || '') + ""], text.slice(this.cursorCol + 1) || []); - } else { - html = this.lineData[n]; + updateScreen: function() { + this.dirtyLines = []; + + for (var l=0; l= 30 && n <= 37) { + this.fg = n - 30; + } else if (n >= 40 && n <= 47) { + this.bg = n - 40; + } + } }, setCursorPos: function(line, col) { @@ -101,27 +141,29 @@ SP.Terminal.prototype = { }, cursorLeft: function() { - if (this.cursorCol > 0) - this.cursorCol = this.cursorCol - 1; - this.updateLine(); + if (this.cursorCol > 0) { + this.cursorCol -= 1; + this.updateLine(); + } }, cursorRight: function() { - if (this.cursorCol < this.cols) - this.cursorCol = this.cursorCol + 1; - this.updateLine(); + if (this.cursorCol < this.cols) { + this.cursorCol += 1; + this.updateLine(); + } }, cursorUp: function() { - if (this.cursorLine > 0) - this.cursorLine = this.cursorLine - 1; - this.updateLine(this.cursorLine); - this.updateLine(this.cursorLine+1); + if (this.cursorLine > 0) { + this.cursorLine -= 1; + this.updateLine(this.cursorLine); + this.updateLine(this.cursorLine+1); + } }, cursorDown: function() { - if (this.cursorLine < this.lines) - this.cursorLine = this.cursorLine + 1; + this.cursorLine += 1; this.updateLine(this.cursorLine); this.updateLine(this.cursorLine-1); }, @@ -141,8 +183,8 @@ SP.Terminal.prototype = { bs: function() { if (this.cursorCol > 0) { - this.lineData[this.cursorLine][this.cursorCol - 1] = ' '; - this.cursorCol = this.cursorCol - 1; + this.getLine()[this.cursorCol - 1] = ' '; + this.cursorCol -= 1; this.updateLine(); } }, @@ -157,7 +199,7 @@ SP.Terminal.prototype = { } this.fill(this.cursorLine, this.cursorCol, 1, text[i]); - this.cursorCol = this.cursorCol + 1; + this.cursorCol += 1; } this.updateLine(); @@ -165,8 +207,8 @@ SP.Terminal.prototype = { eraseData: function(n) { if (n == 0) { - this.eraseLine(n); - for (var l=this.cursorLine+1; l