Skip to content

Instantly share code, notes, and snippets.

@FireyFly
Created March 29, 2012 12:56
Show Gist options
  • Save FireyFly/2237222 to your computer and use it in GitHub Desktop.
Save FireyFly/2237222 to your computer and use it in GitHub Desktop.
function WebTerm(pre, width, height) {
this.element = pre
this.width = width
this.height = height
this.charbuf = []
this.formatbuf = []
this.caret = { x:0, y:0 }
this.defFormatting =
{ bold : false
, italic : false
, underline : false
, blink : false
, conceal : false
, strikeout : false
, font : 'monospace'
, foreground : 7
, background : 0
}
this.formatting = this.defFormatting
for (var i=0; i<this.height; i++) {
this.charbuf[i] = getLineArrayOf(this, " ")
this.formatbuf[i] = getLineArrayOf(this, this.defFormatting)
}
}
function getLineArrayOf(self, val) {
var res = []
for (var i=0; i<self.width; i++) {
res[i] = val
}
return res
}
WebTerm.prototype.caretRight = function() {
this.caret.x += 1
if (this.caret.x >= this.width) {
this.caretDown()
}
}
WebTerm.prototype.caretDown = function() {
this.caret.x = 0
this.caret.y += 1
if (this.caret.y >= this.height) {
this.caret.y = this.height - 1
this.charbuf.shift()
this.formatbuf.shift()
this.charbuf.push(getLineArrayOf(this, " "))
this.formatbuf.push(getLineArrayOf(this, this.defFormatting))
}
}
function newFormatting(self) {
var res = {}
for (var k in self.formatting) {
res[k] = self.formatting[k]
}
self.formatting = res
}
WebTerm.prototype.doCSI = function(command /*, ...params*/) {
var params = Array.prototype.slice.call(arguments, 1)
var self = this
switch (command) {
case 'A': case 'F':
(params[0] == null) && (params[0] = 1)
this.caret.y -= params[0]
(this.caret.y < 0) && (this.caret.y = 0)
if (command == 'F') this.caret.x = 0
break
case 'B': case 'E':
(params[0] == null) && (params[0] = 1)
this.caret.y += params[0]
(this.caret.y >= this.height) && (this.caret.y = this.height - 1)
if (command == 'E') this.caret.x = 0
break
case 'C':
(params[0] == null) && (params[0] = 1)
this.caret.x -= params[0]
(this.caret.x < 0) && (this.caret.x = 0)
break
case 'D':
(params[0] == null) && (params[0] = 1)
this.caret.x += params[0]
(this.caret.x >= this.width) && (this.caret.x = this.width - 1)
break
case 'G':
this.caret.x = params[0]
break
case 'H': case 'f':
(params[0] == null) && (params[0] = 1)
(params[1] == null) && (params[1] = 1)
this.caret.y = params[0]
this.caret.x = params[1]
case 'J':
switch (+params[0]) {
case 0:
for (var y=this.caret.y; y>=0; y--) {
this.charbuf[y] = getLineArrayOf(" ")
} break
case 1:
for (var y=this.caret.y; y<this.height; y++) {
this.charbuf[y] = getLineArrayOf(" ")
} break
case 2:
for (var y=0; y<this.height; y++) {
this.charbuf[y] = getLineArrayOf(" ")
} break
} break
case 'K':
switch (+params[0]) {
case 0:
for (var x=this.caret.x; x>=0; x--) {
this.charbuf[this.caret.y][x] = " "
} break
case 1:
for (var x=this.caret.x; x<this.width; x++) {
this.charbuf[this.caret.y][x] = " "
} break
case 2:
this.charbuf[this.caret.y] = getLineArrayOf(" ")
break
} break
// TODO: S/T
case 'm':
(params[0] == null) && (params[0] = 0)
function set(prop, value) {
if (self.formatting[prop] != value) {
newFormatting(self)
self.formatting[prop] = value
}
}
params.forEach(function(code) {
switch (+code) {
case 0:
self.formatting = self.defFormatting
break
case 1: set('bold', true); break
case 3: set('italic', true); break
case 4: set('underline', true); break
case 5: set('blink', 90); break
case 6: set('blink', 300); break
case 7: case 27: // FIXME: Probably broken implementation.
var old = self.formatting
newFormatting(this)
formatting.foreground = old.background
formatting.background = old.foreground
break
case 8: set('conceal', true); break
case 9: set('strikeout', true); break
case 10: case 11: case 12: case 13: case 14:
case 15: case 16: case 17: case 18: case 19:
set('font', 'monospace'); break
case 21: set('bold', false); break
case 22: set('bold', false); break
case 23: set('italic', false); break
case 24: set('underline', false); break
case 25: set('blink', false); break
// case 27: set('reverse', false); break
case 28: set('conceal', false); break
case 29: set('strikeout', false); break
case 30: case 31: case 32: case 33:
case 34: case 35: case 36: case 37:
set('foreground', code - 30); break
case 39: set('foreground', 7); break
case 40: case 41: case 42: case 43:
case 44: case 45: case 46: case 47:
set('background', code - 40); break
case 49: set('background', 0); break
}
})
break
}
}
WebTerm.prototype.writeChar = function(chr) {
var car = this.caret
this.charbuf[car.y][car.x] = chr
this.formatbuf[car.y][car.x] = this.formatting
}
WebTerm.prototype.write = function(str) {
for (var i=0; i<str.length; i++) {
var chr = str[i]
, code = chr.charCodeAt()
if (code == 10) {
this.caretDown()
} else if (code < 32) {
switch (code) {
case 7:
// TODO: Bell
break
case 8:
this.writeChar(' ')
this.caret.x -= 1
if (this.caret.x < 0) this.caret.x = 0
break
case 13:
this.caret.x = 0
break
case 27:
if (str[i + 1] == "[") {
var match = str.slice(i + 1).match(
/\[(\d+)?(?:;(\d+)?)?([@-~])/)
, params = [ match[1], match[2] ]
, command = match[3]
log("ESC", command, params)
this.doCSI(command, params[0], params[1])
i += match[0].length
//this.write("<ESC>")
} else if (str[i + 1] == "]") {
var match = str.slice(i + 1).match(
/\]([\x08-\x0D\x20-\x7E]*)[\x9C\x07]/)
log("Hidden:", match[1])
i += match[0].length
} else {
log("Unknown C1 control code:", str[i + 1])
this.write("^" + String.fromCharCode(code + 64))
} break
}
} else {
this.writeChar(chr)
this.caretRight()
}
}
}
var colortable =
// { low: [ "#000", "#c00", "#0c0", "#cc0"
// , "#00c", "#c0c", "#0cc", "#ddd" ]
// , high: [ "#999", "#f00", "#0f0", "#ff0"
// , "#00f", "#f0f", "#0ff", "#fff" ]
// }
{ low: [ "#000000", "#E96060", "#2A8C2A", "#D9A641",
"#4E69BE", "#B037B0", "#66C3DE", "#dddddd" ]
, high: [ "#999999", "#E96060", "#2A8C2A", "#D9A641",
"#3E69BE", "#B037B0", "#66C3DE", "#ffffff" ]
}
WebTerm.prototype.flush = function() {
var self = this
, el = this.element
while (el.firstChild) { el.removeChild(el.firstChild) }
this.charbuf.forEach(function(line, idx) {
var fmtLine = self.formatbuf[idx]
for (var i=0; i<line.length; i++) {
var fmt = fmtLine[i]
for (var j=i; j<line.length && fmt == fmtLine[j]; j++);
var text = line.slice(i, j).join("")
, span = document.createElement('span')
var boldMode = (fmt.bold ? "high" : "low")
console.log(fmt.foreground, "'" + text + "'")
span.style.color = colortable[boldMode][fmt.foreground]
span.style.backgroundColor = colortable["low"][fmt.background]
span.style.fontWeight = (fmt.bold ? "bold" : "normal")
span.appendChild(document.createTextNode(text))
el.appendChild(span)
i = j - 1
}
el.appendChild(document.createTextNode("\n"))
//el.appendChild(document.createTextNode(line.join("") + "\n"))
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment