Coffize AnsiInterpreter

openid
Marcin Kulik 13 years ago
parent 0cc0416b56
commit b90582503e

@ -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; i<modes.length; i++) {
mode = modes[i];
if (mode == '1049') {
if (action == 'h') {
// Save cursor position, switch to alternate screen buffer, and clear screen.
this.terminal.saveCursor();
this.terminal.switchToAlternateBuffer();
this.terminal.clearScreen();
} else if (action == 'l') {
// Clear screen, switch to normal screen buffer, and restore cursor position.
this.terminal.clearScreen();
this.terminal.switchToNormalBuffer();
this.terminal.restoreCursor();
}
} else if (mode == '1002') {
// 2002 + h / l = mouse tracking stuff
} else if (mode == '1001') {
// pbly sth with mouse/keys...
} else if (mode == '1') {
// 1 + h / l = cursor keys stuff
} else if (mode == '47') {
if (action == 'h') {
this.terminal.switchToAlternateBuffer();
} else if (action == 'l') {
this.terminal.switchToNormalBuffer();
}
} else if (mode == '25') {
if (action == 'h') {
this.terminal.showCursor(true);
} else if (action == 'l') {
this.terminal.showCursor(false);
}
} else if (mode == '12') {
if (action == 'h') {
// blinking cursor
} else if (action == 'l') {
// steady cursor
}
} else {
throw 'unknown mode: ' + mode + action;
}
}
},
"\x1b\x3d": function(data) { // DECKPAM - Set keypad to applications mode (ESCape instead of digits)
},
"\x1b\x3e": function(data) { // DECKPNM - Set keypad to numeric mode (digits intead of ESCape seq)
},
"\x1b\\\x5d[012]\x3b(?:.)*?\x07": function(data, match) { // OSC - Operating System Command (terminal title)
},
"\x1b\\[>c": 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<this.COMPILED_PATTERNS.length; i++) {
var pattern = this.COMPILED_PATTERNS[i];
match = pattern[0].exec(data);
if (match) {
handler = pattern[1];
break;
}
}
if (handler) {
handler.call(this, data, match);
data = data.slice(match[0].length)
} else {
return data;
}
}
return '';
}
}

@ -0,0 +1,151 @@
class AsciiIo.AnsiInterpreter
constructor: (terminal) ->
@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
""

@ -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

Loading…
Cancel
Save