From b90582503e0c8b91909ace839ddcd946fdfdfb28 Mon Sep 17 00:00:00 2001 From: Marcin Kulik Date: Sun, 27 Nov 2011 21:58:10 +0100 Subject: [PATCH] Coffize AnsiInterpreter --- app/assets/javascripts/ansi-interpreter.js | 219 ------------------ .../javascripts/ansi-interpreter.js.coffee | 151 ++++++++++++ app/assets/javascripts/player.js.coffee | 2 +- 3 files changed, 152 insertions(+), 220 deletions(-) delete mode 100644 app/assets/javascripts/ansi-interpreter.js create mode 100644 app/assets/javascripts/ansi-interpreter.js.coffee diff --git a/app/assets/javascripts/ansi-interpreter.js b/app/assets/javascripts/ansi-interpreter.js deleted file mode 100644 index 4a334ba..0000000 --- a/app/assets/javascripts/ansi-interpreter.js +++ /dev/null @@ -1,219 +0,0 @@ -SP.AnsiInterpreter = function(terminal) { - this.terminal = terminal; - this.compilePatterns(); -} - -SP.AnsiInterpreter.prototype = { - PATTERNS: { - "\x07": function(data) { - // bell - }, - - "\x08": function(data) { - this.terminal.bs(); - }, - - "\x0a": function(data) { - this.terminal.cursorDown(); - }, - - "\x0d": function(data) { - this.terminal.cr(); - }, - - "\x0e": function(data) { - }, - - "\x0f": function(data) { - }, - - "\x82": function(data) { // Reserved (?) - }, - - "\x94": function(data) { // Cancel Character, ignore previous character - }, - - // 20 - 7e - "([\x20-\x7e]|\xe2..|[\xc5\xc4].)+": function(data, match) { - this.terminal.print(match[0]); - }, - - "\x1b\\(B": function(data) { // SCS (Set G0 Character SET) - }, - - "\x1b\\[(?:[0-9]+)?(?:;[0-9]+)*([\x40-\x7e])": function(data, match) { - this.params = []; - var re = /(\d+)/g; - var m; - - while (m = re.exec(match[0])) { - this.params.push(parseInt(m[1])); - } - - this.n = this.params[0]; - this.m = this.params[1]; - - this.handleCSI(match[1]); - }, - - "\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) - // 1001 + s = ? - // 1001 + r = ? - var modes = match[1].split(';'); - var action = match[2]; - var mode; - - for (var i=0; ic": function(data) { // Secondary Device Attribute request (?) - }, - - "\x1bP([^\\\\])*?\\\\": function(data) { // DCS, Device Control String - }, - - "\x1bM": function() { - this.terminal.ri(this.n || 1); - }, - - "\x1b\x37": function(data) { // save cursor pos and char attrs - this.terminal.saveCursor(); - }, - - "\x1b\x38": function(data) { // restore cursor pos and char attrs - this.terminal.restoreCursor(); - } - }, - - handleCSI: function(term) { - switch(term) { - case "@": - this.terminal.reserveCharacters(this.n); - break; - case "A": - this.terminal.cursorUp(this.n || 1); - break; - case "B": - this.terminal.cursorDown(this.n || 1); - break; - case "C": - this.terminal.cursorForward(this.n || 1); - break; - case "D": - this.terminal.cursorBack(this.n || 1); - break; - case "H": - this.terminal.setCursorPos(this.n || 1, this.m || 1); - break; - case "J": - this.terminal.eraseData(this.n || 0); - break; - case "K": - this.terminal.eraseLine(this.n || 0); - break; - case "L": - this.terminal.insertLines(this.cursorY, this.n || 1); - break; - case "l": // l, Reset mode - console.log("(TODO) reset: " + this.n); - break; - case "m": - this.terminal.setSGR(this.params); - break; - case "r": // Set top and bottom margins (scroll region on VT100) - break; - default: - throw 'no handler for CSI term: ' + term; - } - }, - - compilePatterns: function() { - this.COMPILED_PATTERNS = []; - var regexp; - - for (re in this.PATTERNS) { - regexp = new RegExp('^' + re); - this.COMPILED_PATTERNS.push([regexp, this.PATTERNS[re]]); - } - }, - - feed: function(data) { - var match; - var handler; - - while (data.length > 0) { - match = handler = null; - - for (var i=0; i + @terminal = terminal + @compilePatterns() + + PATTERNS: + "\x07": (data) -> # bell + "\x08": (data) -> @terminal.bs() + "\x0a": (data) -> @terminal.cursorDown() + "\x0d": (data) -> @terminal.cr() + "\x0e": (data) -> + "\x0f": (data) -> + "\x82": (data) -> # Reserved (?) + "\x94": (data) -> # Cancel Character, ignore previous character + + # 20 - 7e + "([\x20-\x7e]|\xe2..|[\xc2\xc4\xc5].)+": (data, match) -> + @terminal.print match[0] + + "\x1b\\(B": (data) -> # SCS (Set G0 Character SET) + + "\x1b\\[(?:[0-9]+)?(?:;[0-9]+)*([\x40-\x7e])": (data, match) -> + @params = [] + re = /(\d+)/g + m = undefined + @params.push parseInt(m[1]) while m = re.exec(match[0]) + @n = @params[0] + @m = @params[1] + @handleCSI match[1] + + # private standards + "\x1b\\[\\?([\x30-\x3f]+)([hlsr])": (data, match) -> + # 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) + # 1001 + s = ? + # 1001 + r = ? + modes = match[1].split(";") + action = match[2] + mode = undefined + i = 0 + + while i < modes.length + mode = modes[i] + if mode is "1049" + if action is "h" + # Save cursor position, switch to alternate screen buffer, and clear screen. + @terminal.saveCursor() + @terminal.switchToAlternateBuffer() + @terminal.clearScreen() + else if action is "l" + # Clear screen, switch to normal screen buffer, and restore cursor position. + @terminal.clearScreen() + @terminal.switchToNormalBuffer() + @terminal.restoreCursor() + else if mode is "1002" + # 2002 + h / l = mouse tracking stuff + else if mode is "1001" + # pbly sth with mouse/keys... + else if mode is "1" + # 1 + h / l = cursor keys stuff + else if mode is "47" + if action is "h" + @terminal.switchToAlternateBuffer() + else @terminal.switchToNormalBuffer() if action is "l" + else if mode is "25" + if action is "h" + @terminal.showCursor true + else @terminal.showCursor false if action is "l" + else if mode is "12" + if action is "h" + # blinking cursor + else action is "l" + # steady cursor + else + throw "unknown mode: " + mode + action + i++ + + "\x1b\x3d": (data) -> # DECKPAM - Set keypad to applications mode (ESCape instead of digits) + + "\x1b\x3e": (data) -> # DECKPNM - Set keypad to numeric mode (digits intead of ESCape seq) + + "\x1b\\\x5d[012]\x3b(?:.)*?\x07": (data, match) -> # OSC - Operating System Command (terminal title) + + "\x1b\\[>c": (data) -> # Secondary Device Attribute request (?) + + "\x1bP([^\\\\])*?\\\\": (data) -> # DCS, Device Control String + + "\x1bM": -> + @terminal.ri @n or 1 + + "\x1b\x37": (data) -> # save cursor pos and char attrs + @terminal.saveCursor() + + "\x1b\x38": (data) -> # restore cursor pos and char attrs + @terminal.restoreCursor() + + handleCSI: (term) -> + switch term + when "@" + @terminal.reserveCharacters @n + when "A" + @terminal.cursorUp @n or 1 + when "B" + @terminal.cursorDown @n or 1 + when "C" + @terminal.cursorForward @n or 1 + when "D" + @terminal.cursorBack @n or 1 + when "H" + @terminal.setCursorPos @n or 1, @m or 1 + when "J" + @terminal.eraseData @n or 0 + when "K" + @terminal.eraseInLine @n or 0 + when "L" + @terminal.insertLines @cursorY, @n or 1 + when "l" # l, Reset mode + console.log "(TODO) reset: " + @n + when "m" + @terminal.setSGR @params + when "r" # Set top and bottom margins (scroll region on VT100) + else + throw "no handler for CSI term: " + term + + compilePatterns: -> + @COMPILED_PATTERNS = [] + regexp = undefined + for re of @PATTERNS + regexp = new RegExp("^" + re) + @COMPILED_PATTERNS.push [ regexp, @PATTERNS[re] ] + + feed: (data) -> + match = undefined + handler = undefined + while data.length > 0 + match = handler = null + i = 0 + + while i < @COMPILED_PATTERNS.length + pattern = @COMPILED_PATTERNS[i] + match = pattern[0].exec(data) + if match + handler = pattern[1] + break + i++ + if handler + handler.call this, data, match + data = data.slice(match[0].length) + else + return data + "" diff --git a/app/assets/javascripts/player.js.coffee b/app/assets/javascripts/player.js.coffee index 170e7a7..1ebb241 100644 --- a/app/assets/javascripts/player.js.coffee +++ b/app/assets/javascripts/player.js.coffee @@ -3,7 +3,7 @@ class AsciiIo.Player @minDelay = 0.01 @speed = 1.0 @terminal = new SP.Terminal(cols, lines) - @interpreter = new SP.AnsiInterpreter(@terminal) + @interpreter = new AsciiIo.AnsiInterpreter(@terminal) @data = data @time = time @dataIndex = 0