Coffized terminal.js

openid
Marcin Kulik 13 years ago
parent d380577b2f
commit a57cd2a241

@ -1,346 +0,0 @@
SP.Terminal = function(cols, lines) {
this.element = $(".player .term");
this.cols = cols;
this.lines = lines;
this.cursorX = 0;
this.cursorY = 0;
this.normalBuffer = [];
this.alternateBuffer = [];
this.lineData = this.normalBuffer;
this.dirtyLines = [];
this.fg = this.bg = undefined;
this.createChildElements();
this.showCursor(true);
// this.updateScreen();
// this.render();
// this.renderLine(0); // we only need 1 line
// this.element.css({ width: this.element.width(), height: this.element.height() });
};
SP.Terminal.prototype = {
createChildElements: function() {
for (var i = 0; i < this.lines; i++) {
var row = $('<span class="line">');
this.element.append(row);
this.element.append("\n");
}
},
getLine: function(n) {
n = (typeof n != "undefined" ? n : this.cursorY);
if (n >= this.lines)
throw 'cant getLine ' + n;
var line = this.lineData[n];
if (typeof line == 'undefined') {
line = this.lineData[n] = [];
this.fill(n, 0, this.cols, ' ');
}
return line;
},
clearScreen: function() {
// this.lineData.length = 0;
this.cursorY = this.cursorX = 0;
this.element.find(".line").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.cursorY) {
html = html.slice(0, this.cursorX).concat(['<span class="cursor">' + (html[this.cursorX] || '') + "</span>"], html.slice(this.cursorX + 1) || []);
}
this.element.find(".line:eq(" + n + ")").html(html.join(''));
},
render: function() {
var updated = [];
for (var i=0; i<this.dirtyLines.length; i++) {
var n = this.dirtyLines[i];
if (updated.indexOf(n) == -1) {
this.renderLine(n);
updated.push(n);
}
}
this.dirtyLines = [];
},
updateLine: function(n) {
n = (typeof n != "undefined" ? n : this.cursorY);
this.dirtyLines.push(n);
},
updateScreen: function() {
this.dirtyLines = [];
for (var l=0; l<this.lines; l++) {
this.dirtyLines.push(l);
}
},
showCursor: function(show) {
if (show) {
this.element.addClass('cursor-on');
} else {
this.element.removeClass('cursor-on');
}
},
setSGR: function(codes) {
if (codes.length == 0) {
codes = [0];
}
for (var i=0; i<codes.length; i++) {
var n = codes[i];
if (n === 0) {
this.fg = this.bg = undefined;
this.bright = false;
} else if (n == 1) {
this.bright = true;
} else if (n >= 30 && n <= 37) {
this.fg = n - 30;
} else if (n >= 40 && n <= 47) {
this.bg = n - 40;
} else if (n == 38) {
this.fg = codes[i+2];
i += 2;
} else if (n == 48) {
this.bg = codes[i+2];
i += 2;
}
}
},
setCursorPos: function(line, col) {
line -= 1;
col -= 1;
var oldLine = this.cursorY;
this.cursorY = line;
this.cursorX = col;
this.updateLine(oldLine);
this.updateLine();
},
saveCursor: function() {
this.savedCol = this.cursorX;
this.savedLine = this.cursorY;
},
restoreCursor: function() {
var oldLine = this.cursorY;
this.cursorY = this.savedLine;
this.cursorX = this.savedCol;
this.updateLine(oldLine);
this.updateLine();
},
cursorLeft: function() {
if (this.cursorX > 0) {
this.cursorX -= 1;
this.updateLine();
}
},
cursorRight: function() {
if (this.cursorX < this.cols) {
this.cursorX += 1;
this.updateLine();
}
},
cursorUp: function() {
if (this.cursorY > 0) {
this.cursorY -= 1;
this.updateLine(this.cursorY);
this.updateLine(this.cursorY+1);
}
},
cursorDown: function() {
if (this.cursorY + 1 < this.lines) {
this.cursorY += 1;
this.updateLine(this.cursorY-1);
this.updateLine(this.cursorY);
} else {
this.lineData.splice(0, 1);
this.updateScreen();
}
},
cursorForward: function(n) {
for (var i=0; i<n; i++) this.cursorRight();
},
cursorBack: function(n) {
for (var i=0; i<n; i++) this.cursorLeft();
},
cr: function() {
this.cursorX = 0;
this.updateLine();
},
bs: function() {
if (this.cursorX > 0) {
this.getLine()[this.cursorX - 1] = ' ';
this.cursorX -= 1;
this.updateLine();
}
},
print: function(text) {
text = Utf8.decode(text);
for (var i=0; i<text.length; i++) {
if (this.cursorX >= this.cols) {
this.cursorY += 1;
this.cursorX = 0;
}
this.fill(this.cursorY, this.cursorX, 1, text[i]);
this.cursorX += 1;
}
this.updateLine();
},
eraseData: function(n) {
if (n == 0) {
this.eraseInLine(0);
for (var l=this.cursorY+1; l<this.lines; l++) {
this.clearLineData(l);
this.updateLine(l);
}
} else if (n == 1) {
for (var l=0; l<this.cursorY; l++) {
this.clearLineData(l);
this.updateLine(l);
}
this.eraseInLine(n);
} else if (n == 2) {
for (var l=0; l<this.lines; l++) {
this.clearLineData(l);
this.updateLine(l);
}
}
},
eraseInLine: function(n) {
if (n == 0) {
this.fill(this.cursorY, this.cursorX, this.cols - this.cursorX, ' ');
this.updateLine();
} else if (n == 1) {
this.fill(this.cursorY, 0, this.cursorX, ' ');
this.updateLine();
} else if (n == 2) {
this.fill(this.cursorY, 0, this.cols, ' ');
this.updateLine();
}
},
clearLineData: function(n) {
this.fill(n, 0, this.cols, ' ');
},
reserveCharacters: function(n) {
var line = this.getLine();
this.lineData[this.cursorY] = line.slice(0, this.cursorX).concat(" ".times(n).split(''), line.slice(this.cursorX, this.cols - n));
this.updateLine();
},
ri: function(n) {
for (var i=0; i<n; i++) {
if (this.cursorY == 0) {
this.insertLines(0, n);
} else {
this.cursorUp();
}
}
},
insertLines: function(l, n) {
for (var i=0; i<n; i++) {
this.lineData.splice(l, 0, []);
this.clearLineData(l);
}
this.lineData.length = this.lines;
this.updateScreen();
},
fill: function(line, col, n, char) {
var prefix = '', postfix = '';
if (this.fg !== undefined || this.bg !== undefined || this.bright) {
prefix = '<span class="';
var brightOffset = this.bright ? 8 : 0;
if (this.fg !== undefined) {
prefix += ' fg' + (this.fg + brightOffset);
} else if (this.bright) {
prefix += ' bright';
}
if (this.bg !== undefined) {
prefix += ' bg' + this.bg;
}
prefix += '">';
postfix = '</span>';
}
var char = prefix + char + postfix;
var lineArr = this.getLine(line);
for (var i=0; i<n; i++) {
lineArr[col+i] = char;
}
},
blinkCursor: function() {
var cursor = this.element.find(".cursor");
if (cursor.hasClass("inverted")) {
cursor.removeClass("inverted");
} else {
cursor.addClass("inverted");
}
},
restartCursorBlink: function() {
if (this.cursorTimerId) {
clearInterval(this.cursorTimerId);
this.cursorTimerId = null;
}
this.cursorTimerId = setInterval(this.blinkCursor.bind(this), 500);
}
};

@ -0,0 +1,306 @@
class AsciiIo.Terminal
constructor: (cols, lines) ->
@element = $(".player .term")
@cols = cols
@lines = lines
@cursorX = 0
@cursorY = 0
@normalBuffer = []
@alternateBuffer = []
@lineData = @normalBuffer
@dirtyLines = []
@fg = @bg = undefined
@createChildElements()
@showCursor true
# this.updateScreen();
# this.render();
#
# this.renderLine(0); // we only need 1 line
# this.element.css({ width: this.element.width(), height: this.element.height() });
createChildElements: ->
i = 0
while i < @lines
row = $("<span class=\"line\">")
@element.append row
@element.append "\n"
i++
getLine: (n) ->
n = (if typeof n isnt "undefined" then n else @cursorY)
throw "cant getLine " + n if n >= @lines
line = @lineData[n]
if typeof line is "undefined"
line = @lineData[n] = []
@fill n, 0, @cols, " "
line
clearScreen: ->
# this.lineData.length = 0;
@cursorY = @cursorX = 0
@element.find(".line").empty()
switchToNormalBuffer: ->
@lineData = @normalBuffer
@updateScreen()
switchToAlternateBuffer: ->
@lineData = @alternateBuffer
@updateScreen()
renderLine: (n) ->
html = @getLine(n)
if n is @cursorY
html = html.slice(0, @cursorX).concat([ "<span class=\"cursor\">" + (html[@cursorX] or "") + "</span>" ], html.slice(@cursorX + 1) or [])
@element.find(".line:eq(" + n + ")").html html.join("")
render: ->
updated = []
i = 0
while i < @dirtyLines.length
n = @dirtyLines[i]
if updated.indexOf(n) is -1
@renderLine n
updated.push n
i++
@dirtyLines = []
updateLine: (n) ->
n = (if typeof n isnt "undefined" then n else @cursorY)
@dirtyLines.push n
updateScreen: ->
@dirtyLines = []
l = 0
while l < @lines
@dirtyLines.push l
l++
showCursor: (show) ->
if show
@element.addClass "cursor-on"
else
@element.removeClass "cursor-on"
setSGR: (codes) ->
codes = [0] if codes.length is 0
i = 0
while i < codes.length
n = codes[i]
if n is 0
@fg = @bg = undefined
@bright = false
else if n is 1
@bright = true
else if n >= 30 and n <= 37
@fg = n - 30
else if n >= 40 and n <= 47
@bg = n - 40
else if n is 38
@fg = codes[i + 2]
i += 2
else if n is 48
@bg = codes[i + 2]
i += 2
i++
setCursorPos: (line, col) ->
line -= 1
col -= 1
oldLine = @cursorY
@cursorY = line
@cursorX = col
@updateLine oldLine
@updateLine()
saveCursor: ->
@savedCol = @cursorX
@savedLine = @cursorY
restoreCursor: ->
oldLine = @cursorY
@cursorY = @savedLine
@cursorX = @savedCol
@updateLine oldLine
@updateLine()
cursorLeft: ->
if @cursorX > 0
@cursorX -= 1
@updateLine()
cursorRight: ->
if @cursorX < @cols
@cursorX += 1
@updateLine()
cursorUp: ->
if @cursorY > 0
@cursorY -= 1
@updateLine @cursorY
@updateLine @cursorY + 1
cursorDown: ->
if @cursorY + 1 < @lines
@cursorY += 1
@updateLine @cursorY - 1
@updateLine @cursorY
else
@lineData.splice 0, 1
@updateScreen()
cursorForward: (n) ->
i = 0
while i < n
@cursorRight()
i++
cursorBack: (n) ->
i = 0
while i < n
@cursorLeft()
i++
cr: ->
@cursorX = 0
@updateLine()
bs: ->
if @cursorX > 0
@getLine()[@cursorX - 1] = " "
@cursorX -= 1
@updateLine()
print: (text) ->
text = Utf8.decode(text)
i = 0
while i < text.length
if @cursorX >= @cols
@cursorY += 1
@cursorX = 0
@fill @cursorY, @cursorX, 1, text[i]
@cursorX += 1
i++
@updateLine()
eraseData: (n) ->
if n is 0
@eraseInLine 0
l = @cursorY + 1
while l < @lines
@clearLineData l
@updateLine l
l++
else if n is 1
l = 0
while l < @cursorY
@clearLineData l
@updateLine l
l++
@eraseInLine n
else if n is 2
l = 0
while l < @lines
@clearLineData l
@updateLine l
l++
eraseInLine: (n) ->
if n is 0
@fill @cursorY, @cursorX, @cols - @cursorX, " "
@updateLine()
else if n is 1
@fill @cursorY, 0, @cursorX, " "
@updateLine()
else if n is 2
@fill @cursorY, 0, @cols, " "
@updateLine()
clearLineData: (n) ->
@fill n, 0, @cols, " "
reserveCharacters: (n) ->
line = @getLine()
@lineData[@cursorY] = line.slice(0, @cursorX).concat(" ".times(n).split(""), line.slice(@cursorX, @cols - n))
@updateLine()
ri: (n) ->
i = 0
while i < n
if @cursorY is 0
@insertLines 0, n
else
@cursorUp()
i++
insertLines: (l, n) ->
i = 0
while i < n
@lineData.splice l, 0, []
@clearLineData l
i++
@lineData.length = @lines
@updateScreen()
fill: (line, col, n, char) ->
prefix = ""
postfix = ""
if @fg isnt undefined or @bg isnt undefined or @bright
prefix = "<span class=\""
brightOffset = (if @bright then 8 else 0)
if @fg isnt undefined
prefix += " fg" + (@fg + brightOffset)
else if @bright
prefix += " bright"
prefix += " bg" + @bg if @bg isnt undefined
prefix += "\">"
postfix = "</span>"
char = prefix + char + postfix
lineArr = @getLine(line)
i = 0
while i < n
lineArr[col + i] = char
i++
blinkCursor: ->
cursor = @element.find(".cursor")
if cursor.hasClass("inverted")
cursor.removeClass "inverted"
else
cursor.addClass "inverted"
restartCursorBlink: ->
if @cursorTimerId
clearInterval @cursorTimerId
@cursorTimerId = null
@cursorTimerId = setInterval(@blinkCursor.bind(this), 500)
Loading…
Cancel
Save