Implement 16M colors

This commit is contained in:
Florian Mounier
2015-04-13 18:25:20 +02:00
parent ca454b4149
commit 165b17da4e
3 changed files with 191 additions and 126 deletions

8
bin/16Mtest Executable file
View File

@@ -0,0 +1,8 @@
#!/bin/env python
import sys
import os
rows, cols = map(int, os.popen('stty size', 'r').read().split())
for r in range(rows):
for c in range(cols):
sys.stdout.write('\x1b[48;2;%d;%d;%dm ' % (255 - r, 255 - c, 255))

View File

@@ -205,6 +205,34 @@
setTimeout(this.resize.bind(this), 100);
}
Terminal.prototype.getDefAttr = function() {
return {
bg: 256,
fg: 0,
bold: false,
underline: false,
blink: false,
inverse: false,
invisible: false
};
};
Terminal.prototype.cloneAttr = function(a) {
return {
bg: a.bg,
fg: a.fg,
bold: a.bold,
underline: a.underline,
blink: a.blink,
inverse: a.inverse,
invisible: a.invisible
};
};
Terminal.prototype.equalAttr = function(a, b) {
return a.bg === b.bg && a.fg === b.fg && a.bold === b.bold && a.underline === b.underline && a.blink === b.blink && a.inverse === b.inverse && a.invisible === b.invisible;
};
Terminal.prototype.reset_vars = function() {
var i;
this.x = 0;
@@ -225,8 +253,8 @@
this.gcharset = null;
this.glevel = 0;
this.charsets = [null];
this.defAttr = (0 << 18) | (257 << 9) | (256 << 0);
this.curAttr = this.defAttr;
this.defAttr = this.getDefAttr();
this.curAttr = this.getDefAttr();
this.params = [];
this.currentParam = 0;
this.prefix = "";
@@ -458,7 +486,7 @@
};
Terminal.prototype.refresh = function(start, end) {
var attr, bg, ch, classes, data, fg, flags, html, i, j, k, l, line, m, out, parent, ref, ref1, ref2, ref3, row, x;
var attr, ch, classes, data, fg, html, i, j, k, l, line, m, out, parent, ref, ref1, ref2, ref3, row, styles, x;
if (!this.native_scroll && end - start >= this.rows / 3) {
parent = this.element.parentNode;
if (parent != null) {
@@ -475,43 +503,56 @@
} else {
x = -Infinity;
}
attr = this.defAttr;
attr = this.getDefAttr();
for (i = m = 0, ref2 = this.cols - 1; 0 <= ref2 ? m <= ref2 : m >= ref2; i = 0 <= ref2 ? ++m : --m) {
data = line[i][0];
ch = line[i][1];
if (data !== attr) {
if (attr !== this.defAttr) {
if (!this.equalAttr(data, attr)) {
if (!this.equalAttr(attr, this.getDefAttr())) {
out += "</span>";
}
if (data !== this.defAttr) {
if (!this.equalAttr(data, this.getDefAttr())) {
classes = [];
styles = [];
out += "<span ";
bg = data & 0x1ff;
fg = (data >> 9) & 0x1ff;
flags = data >> 18;
if (flags & 1) {
if (data.bold) {
classes.push("bold");
}
if (flags & 2) {
if (data.underline) {
classes.push("underline");
}
if (flags & 4) {
if (data.blink) {
classes.push("blink");
}
if (flags & 8) {
if (data.inverse) {
classes.push("reverse-video");
}
if (flags & 16) {
if (data.invisible) {
classes.push("invisible");
}
if (flags & 1 && fg < 8) {
fg += 8;
if (typeof data.fg === 'number') {
fg = data.fg;
if (data.bold && fg < 8) {
fg += 8;
}
classes.push("fg-color-" + fg);
}
if (typeof data.fg === 'string') {
styles.push("color: " + data.fg);
}
if (typeof data.bg === 'number') {
classes.push("bg-color-" + data.bg);
}
if (typeof data.bg === 'string') {
styles.push("background-color: " + data.bg);
}
classes.push("bg-color-" + bg);
classes.push("fg-color-" + fg);
out += "class=\"";
out += classes.join(" ");
out += "\">";
out += "\"";
if (styles.length) {
out += " style=\"" + styles.join("; ") + "\"";
}
out += ">";
}
}
if (i === x) {
@@ -548,7 +589,7 @@
}
attr = data;
}
if (attr !== this.defAttr) {
if (!this.equalAttr(attr, this.getDefAttr())) {
out += "</span>";
}
this.children[j].innerHTML = out;
@@ -747,19 +788,19 @@
ch = this.charset[ch];
}
if (this.x >= this.cols) {
this.screen[this.y + this.ybase][this.x] = [this.curAttr, '\u23CE'];
this.screen[this.y + this.ybase][this.x] = [this.cloneAttr(this.curAttr), '\u23CE'];
this.x = 0;
this.next_line();
}
this.updateRange(this.y);
this.screen[this.y + this.ybase][this.x] = [this.curAttr, ch];
this.screen[this.y + this.ybase][this.x] = [this.cloneAttr(this.curAttr), ch];
this.x++;
if (("\uff00" < ch && ch < "\uffef")) {
if (this.cols < 2 || this.x >= this.cols) {
this.screen[this.y + this.ybase][this.x - 1] = [this.curAttr, " "];
this.screen[this.y + this.ybase][this.x - 1] = [this.cloneAttr(this.curAttr), " "];
break;
}
this.screen[this.y + this.ybase][this.x] = [this.curAttr, " "];
this.screen[this.y + this.ybase][this.x] = [this.cloneAttr(this.curAttr), " "];
this.x++;
}
}
@@ -1133,7 +1174,7 @@
this.updateRange(this.y);
} else {
html = "<div class=\"inline-html\">" + content + "</div>";
this.screen[this.y + this.ybase][this.x] = [this.curAttr, html];
this.screen[this.y + this.ybase][this.x] = [this.cloneAttr(this.curAttr), html];
line = 0;
while (line < this.get_html_height_in_lines(html) - 1) {
this.y++;
@@ -1895,85 +1936,81 @@
};
Terminal.prototype.charAttributes = function(params) {
var bg, fg, flags, i, l, p;
var i, l, p, results;
if (params.length === 1 && params[0] === 0) {
this.curAttr = this.defAttr;
this.curAttr = this.getDefAttr();
return;
}
flags = this.curAttr >> 18;
fg = (this.curAttr >> 9) & 0x1ff;
bg = this.curAttr & 0x1ff;
l = params.length;
i = 0;
results = [];
while (i < l) {
p = params[i];
if (p >= 30 && p <= 37) {
fg = p - 30;
this.curAttr.fg = p - 30;
} else if (p >= 40 && p <= 47) {
bg = p - 40;
this.curAttr.bg = p - 40;
} else if (p >= 90 && p <= 97) {
p += 8;
fg = p - 90;
this.curAttr.fg = p - 90;
} else if (p >= 100 && p <= 107) {
p += 8;
bg = p - 100;
this.curAttr.bg = p - 100;
} else if (p === 0) {
flags = this.defAttr >> 18;
fg = (this.defAttr >> 9) & 0x1ff;
bg = this.defAttr & 0x1ff;
this.curAttr = this.getDefAttr();
} else if (p === 1) {
flags |= 1;
this.curAttr.bold = true;
} else if (p === 4) {
flags |= 2;
this.curAttr.underline = true;
} else if (p === 5) {
flags |= 4;
this.curAttr.blink = true;
} else if (p === 7) {
flags |= 8;
this.curAttr.inverse = true;
} else if (p === 8) {
flags |= 16;
this.curAttr.invisible = true;
} else if (p === 10) {
} else if (p === 22) {
flags &= ~1;
this.curAttr.bold = false;
} else if (p === 24) {
flags &= ~2;
this.curAttr.underline = false;
} else if (p === 25) {
flags &= ~4;
this.curAttr.blink = false;
} else if (p === 27) {
flags &= ~8;
this.curAttr.inverse = false;
} else if (p === 28) {
flags &= ~16;
this.curAttr.invisible = false;
} else if (p === 39) {
fg = (this.defAttr >> 9) & 0x1ff;
this.curAttr.fg = 0;
} else if (p === 49) {
bg = this.defAttr & 0x1ff;
this.curAttr.bg = 256;
} else if (p === 38) {
if (params[i + 1] === 2) {
i += 2;
fg = "#" + params[i] & 0xff + params[i + 1] & 0xff + params[i + 2] & 0xff;
this.curAttr.fg = "rgb(" + params[i] + ", " + params[i + 1] + ", " + params[i + 2] + ")";
i += 2;
} else if (params[i + 1] === 5) {
i += 2;
fg = params[i] & 0xff;
this.curAttr.fg = params[i] & 0xff;
}
} else if (p === 48) {
if (params[i + 1] === 2) {
i += 2;
bg = "#" + params[i] & 0xff + params[i + 1] & 0xff + params[i + 2] & 0xff;
this.curAttr.bg = "rgb(" + params[i] + ", " + params[i + 1] + ", " + params[i + 2] + ")";
i += 2;
} else if (params[i + 1] === 5) {
i += 2;
bg = params[i] & 0xff;
this.curAttr.bg = params[i] & 0xff;
}
} else if (p === 100) {
fg = (this.defAttr >> 9) & 0x1ff;
bg = this.defAttr & 0x1ff;
this.curAttr.fg = 0;
this.curAttr.bg = 256;
} else {
console.error("Unknown SGR attribute: %d.", p);
}
i++;
results.push(i++);
}
return this.curAttr = (flags << 18) | (fg << 9) | bg;
return results;
};
Terminal.prototype.deviceStatus = function(params) {

View File

@@ -118,6 +118,29 @@ class Terminal
setTimeout(@resize.bind(@), 100)
getDefAttr: ->
bg: 256
fg: 0
bold: false
underline: false
blink: false
inverse: false
invisible: false
cloneAttr: (a) ->
bg: a.bg
fg: a.fg
bold: a.bold
underline: a.underline
blink: a.blink
inverse: a.inverse
invisible: a.invisible
equalAttr: (a, b) ->
(a.bg is b.bg and a.fg is b.fg and a.bold is b.bold and
a.underline is b.underline and a.blink is b.blink and
a.inverse is b.inverse and a.invisible is b.invisible)
reset_vars: ->
@x = 0
@y = 0
@@ -144,8 +167,9 @@ class Terminal
@charsets = [null]
# stream
@defAttr = (0 << 18) | (257 << 9) | (256 << 0)
@curAttr = @defAttr
@defAttr = @getDefAttr()
@curAttr = @getDefAttr()
@params = []
@currentParam = 0
@prefix = ""
@@ -397,37 +421,50 @@ class Terminal
else
x = -Infinity
attr = @defAttr
attr = @getDefAttr()
for i in [0..@cols - 1]
data = line[i][0]
ch = line[i][1]
if data isnt attr
out += "</span>" if attr isnt @defAttr
if data isnt @defAttr
unless @equalAttr data, attr
out += "</span>" unless @equalAttr attr, @getDefAttr()
unless @equalAttr data, @getDefAttr()
classes = []
styles = []
out += "<span "
bg = data & 0x1ff
fg = (data >> 9) & 0x1ff
flags = data >> 18
# bold
classes.push "bold" if flags & 1
classes.push "bold" if data.bold
# underline
classes.push "underline" if flags & 2
classes.push "underline" if data.underline
# blink
classes.push "blink" if flags & 4
classes.push "blink" if data.blink
# inverse
classes.push "reverse-video" if flags & 8
classes.push "reverse-video" if data.inverse
# invisible
classes.push "invisible" if flags & 16
classes.push "invisible" if data.invisible
fg += 8 if flags & 1 and fg < 8
classes.push "bg-color-" + bg
classes.push "fg-color-" + fg
if typeof data.fg is 'number'
fg = data.fg
if data.bold and fg < 8
fg += 8
classes.push "fg-color-" + fg
if typeof data.fg is 'string'
styles.push "color: " + data.fg
if typeof data.bg is 'number'
classes.push "bg-color-" + data.bg
if typeof data.bg is 'string'
styles.push "background-color: " + data.bg
out += "class=\""
out += classes.join(" ")
out += "\">"
out += "\""
if styles.length
out += " style=\"" + styles.join("; ") + "\""
out += ">"
out += "<span class=\"" + (
if @cursorState then "reverse-video " else ""
) + "cursor\">" if i is x
@@ -453,7 +490,7 @@ class Terminal
out += ch
out += "</span>" if i is x
attr = data
out += "</span>" if attr isnt @defAttr
out += "</span>" unless @equalAttr attr, @getDefAttr()
@children[j].innerHTML = out
parent?.appendChild @element
@@ -625,20 +662,20 @@ class Terminal
if ch >= " "
ch = @charset[ch] if @charset?[ch]
if @x >= @cols
@screen[@y + @ybase][@x] = [@curAttr, '\u23CE']
@screen[@y + @ybase][@x] = [@cloneAttr(@curAttr), '\u23CE']
@x = 0
@next_line()
@updateRange @y
@screen[@y + @ybase][@x] = [@curAttr, ch]
@screen[@y + @ybase][@x] = [@cloneAttr(@curAttr), ch]
@x++
if "\uff00" < ch < "\uffef"
if @cols < 2 or @x >= @cols
@screen[@y + @ybase][@x - 1] = [@curAttr, " "]
@screen[@y + @ybase][@x - 1] = [@cloneAttr(@curAttr), " "]
break
@screen[@y + @ybase][@x] = [@curAttr, " "]
@screen[@y + @ybase][@x] = [@cloneAttr(@curAttr), " "]
@x++
when State.escaped
@@ -1079,7 +1116,7 @@ class Terminal
else
html = "<div class=\"inline-html\">" + content + "</div>"
@screen[@y + @ybase][@x] = [
@curAttr
@cloneAttr(@curAttr)
html
]
line = 0
@@ -1778,7 +1815,7 @@ class Terminal
# Ps = 7 -> Inverse.
# Ps = 8 -> Invisible, i.e., hidden (VT300).
# Ps = 2 2 -> Normal (neither bold nor faint).
# Ps = 2 4 -> Not underlined.
# Ps = 2 4 -> Not underline.
# Ps = 2 5 -> Steady (not blinking).
# Ps = 2 7 -> Positive (not inverse).
# Ps = 2 8 -> Visible, i.e., not hidden (VT300).
@@ -1835,113 +1872,96 @@ class Terminal
charAttributes: (params) ->
# Optimize a single SGR0.
if params.length is 1 and params[0] is 0
@curAttr = @defAttr
@curAttr = @getDefAttr()
return
flags = @curAttr >> 18
fg = (@curAttr >> 9) & 0x1ff
bg = @curAttr & 0x1ff
l = params.length
i = 0
while i < l
p = params[i]
if p >= 30 and p <= 37
# fg color 8
fg = p - 30
@curAttr.fg = p - 30
else if p >= 40 and p <= 47
# bg color 8
bg = p - 40
@curAttr.bg = p - 40
else if p >= 90 and p <= 97
# fg color 16
p += 8
fg = p - 90
@curAttr.fg = p - 90
else if p >= 100 and p <= 107
# bg color 16
p += 8
bg = p - 100
@curAttr.bg = p - 100
else if p is 0
# default
flags = @defAttr >> 18
fg = (@defAttr >> 9) & 0x1ff
bg = @defAttr & 0x1ff
# flags = 0;
# fg = 0x1ff;
# bg = 0x1ff;
@curAttr = @getDefAttr()
else if p is 1
# bold text
flags |= 1
@curAttr.bold = true
else if p is 4
# underlined text
flags |= 2
# underline text
@curAttr.underline = true
else if p is 5
# blink
flags |= 4
@curAttr.blink = true
else if p is 7
# inverse and positive
# test with: echo -e '\e[31m\e[42mhello\e[7mworld\e[27mhi\e[m'
flags |= 8
@curAttr.inverse = true
else if p is 8
# invisible
flags |= 16
@curAttr.invisible = true
else if p is 10
# Primary Font
# ignoring
else if p is 22
# not bold
flags &= ~1
@curAttr.bold = false
else if p is 24
# not underlined
flags &= ~2
# not underline
@curAttr.underline = false
else if p is 25
# not blink
flags &= ~4
@curAttr.blink = false
else if p is 27
# not inverse
flags &= ~8
@curAttr.inverse = false
else if p is 28
# not invisible
flags &= ~16
@curAttr.invisible = false
else if p is 39
# reset fg
fg = (@defAttr >> 9) & 0x1ff
@curAttr.fg = 0
else if p is 49
# reset bg
bg = @defAttr & 0x1ff
@curAttr.bg = 256
else if p is 38
if params[i + 1] is 2
# fg color 2^24
i += 2
fg = "#" + params[i] & 0xff +
params[i + 1] & 0xff +
params[i + 2] & 0xff
@curAttr.fg = "rgb(#{params[i]}, #{params[i+1]}, #{params[i+2]})"
i += 2
else if params[i + 1] is 5
# fg color 256
i += 2
fg = params[i] & 0xff
@curAttr.fg = params[i] & 0xff
else if p is 48
if params[i + 1] is 2
# bg color 2^24
i += 2
bg = "#" + params[i] & 0xff +
params[i + 1] & 0xff +
params[i + 2] & 0xff
@curAttr.bg = "rgb(#{params[i]}, #{params[i+1]}, #{params[i+2]})"
i += 2
else if params[i + 1] is 5
# bg color 256
i += 2
bg = params[i] & 0xff
@curAttr.bg = params[i] & 0xff
else if p is 100
# reset fg/bg
fg = (@defAttr >> 9) & 0x1ff
bg = @defAttr & 0x1ff
@curAttr.fg = 0
@curAttr.bg = 256
else
console.error "Unknown SGR attribute: %d.", p
i++
@curAttr = (flags << 18) | (fg << 9) | bg
# CSI Ps n Device Status Report (DSR).
# Ps = 5 -> Status Report. Result (``OK'') is