Adding many, but not all ansi escape codes to web.

This commit is contained in:
Brad Nelson
2022-08-09 23:23:56 -07:00
parent b479df0140
commit 5277b6dbbb
3 changed files with 164 additions and 45 deletions

View File

@ -277,6 +277,7 @@ $(GEN)/web_sys.js: $(GEN)/dump_web_opcodes | $(GEN)
WEB_BOOT = $(COMMON_PHASE1e) \ WEB_BOOT = $(COMMON_PHASE1e) \
web/platform.fs \ web/platform.fs \
common/ansi.fs \
$(COMMON_PHASE2) \ $(COMMON_PHASE2) \
web/fini.fs web/fini.fs
$(GEN)/web_boot.js: tools/source_to_string.js $(WEB_BOOT) | $(GEN) $(GEN)/web_boot.js: tools/source_to_string.js $(WEB_BOOT) | $(GEN)

View File

@ -16,6 +16,10 @@ internals definitions
( TODO: Figure out why this has to happen so late. ) ( TODO: Figure out why this has to happen so late. )
transfer internals-builtins transfer internals-builtins
forth definitions internals forth definitions internals
( For now include color list here. )
: colors 256 0 do i fg i . loop normal cr ;
( Bring a forth to the top of the vocabulary. ) ( Bring a forth to the top of the vocabulary. )
: ok ." uEforth" raw-ok ; : ok ." uEforth" raw-ok ;
transfer forth transfer forth

View File

@ -29,7 +29,6 @@ r|
r~ r~
context.inbuffer = []; context.inbuffer = [];
context.outbuffer = [];
if (!globalObj.write) { if (!globalObj.write) {
function AddMeta(name, content) { function AddMeta(name, content) {
var meta = document.createElement('meta'); var meta = document.createElement('meta');
@ -63,36 +62,173 @@ if (!globalObj.write) {
context.screen.appendChild(context.canvas); context.screen.appendChild(context.canvas);
context.ctx = context.canvas.getContext('2d'); context.ctx = context.canvas.getContext('2d');
context.AddLine = function() {
if (context.last_line) {
context.Update(true);
}
context.outbuffer = [];
var line = document.createElement('pre');
line.style.width = '100%';
line.style.whiteSpace = 'pre-wrap';
line.style.margin = '0px';
context.terminal.appendChild(line);
context.lines.push(line);
context.last_line = line;
};
context.terminal = document.createElement('div'); context.terminal = document.createElement('div');
context.terminal.style.width = '100%'; context.terminal.style.width = '100%';
context.terminal.style.whiteSpace = 'pre-wrap'; context.terminal.style.whiteSpace = 'pre-wrap';
context.screen.appendChild(context.terminal); context.screen.appendChild(context.terminal);
const DEFAULT_FG = 0x000000;
const DEFAULT_BG = 0xFFFFFF;
context.attrib = [DEFAULT_FG, DEFAULT_BG];
context.lines = []; context.lines = [];
context.last_line = null; context.escaping = [];
context.outbuffer = [];
context.LineFeed = function() {
var line = document.createElement('pre');
line.style.width = '100%';
line.style.whiteSpace = 'pre-wrap';
line.style.margin = '0px';
if (context.cy < 0) {
context.terminal.appendChild(line);
} else {
context.terminal.insertBefore(line, context.lines[context.cy].nextSibling);
}
context.cx = 0; // implicit cr
if (context.cy >= 0) {
context.dirty[context.cy] = 1;
}
++context.cy;
context.lines.splice(context.cy, 0, [line, []]);
context.dirty[context.cy] = 1;
};
context.ResetTerminal = function() { context.ResetTerminal = function() {
for (var i = 0; i < context.lines.length; ++i) { for (var i = 0; i < context.lines.length; ++i) {
context.terminal.removeChild(context.lines[i]); context.terminal.removeChild(context.lines[i][0]);
} }
context.lines = []; context.lines = [];
context.last_line = null; context.cx = 0;
context.outbuffer = []; context.cy = -1;
context.AddLine(); context.dirty = {};
context.LineFeed();
};
context.ResetTerminal();
context.TermColor = function(n) {
n = n & 0xff;
if (n < 16) {
var i = n & 8;
var r = (n & 1) ? (i ? 255 : 192) : (i ? 128 : 0);
var g = (n & 2) ? (i ? 255 : 192) : (i ? 128 : 0);
var b = (n & 4) ? (i ? 255 : 192) : (i ? 128 : 0);
return (r << 16) | (g << 8) | b;
} else if (n < 232) {
n -= 16;
var r = Math.round((Math.floor(n / 36) % 6) * 255 / 5);
var g = Math.round((Math.floor(n / 6) % 6) * 255 / 5);
var b = Math.round((n % 6) * 255 / 5);
return (r << 16) | (g << 8) | b;
} else {
n = Math.round((n - 232) * 255 / 23);
return (n << 16) | (n << 8) | n;
}
};
context.EscapeCode = function(code) {
var m;
if (code == '[2J') {
context.ResetTerminal();
} else if (code == '[H') {
context.cx = 0;
context.cy = 0;
} else if (code == '[0m') {
context.attrib = [DEFAULT_FG, DEFAULT_BG];
} else if (m = code.match(/\[38;5;([0-9]+)m/)) {
context.attrib[0] = context.TermColor(parseInt(m[1]));
} else if (m = code.match(/\[48;5;([0-9]+)m/)) {
context.attrib[1] = context.TermColor(parseInt(m[1]));
} else {
console.log('Unknown escape code: ' + code);
}
};
context.Emit = function(ch) {
if (ch === 27) {
context.escaping = [27];
return;
}
if (context.escaping.length) {
context.escaping.push(ch);
if ((ch >= 65 && ch <= 90) || (ch >= 97 && ch <= 122)) { // [A-Za-z]
context.EscapeCode(new TextDecoder('utf-8').decode(new Uint8Array(context.escaping)).slice(1));
context.escaping = [];
}
return;
}
if (ch === 12) {
context.ResetTerminal();
context.dirty = {};
return;
} else if (ch == 10) {
context.LineFeed();
return;
}
context.dirty[context.cy] = 1;
if (ch === 8) {
context.cx = Math.max(0, context.cx - 1);
} else if (ch === 13) {
context.cx = 0;
} else {
context.lines[context.cy][1].splice(
context.cx++, 1, [context.attrib[0], context.attrib[1], ch]);
}
};
context.toRGB = function(col) {
var r = (col >> 16) & 0xff;
var g = (col >> 8) & 0xff;
var b = col & 0xff;
return 'rgb(' + r + ',' + g + ',' + b + ')';
};
context.Update = function() {
const cursor = String.fromCharCode(0x2592);
var count = 0;
for (var y in context.dirty) {
++count;
var tag = context.lines[y][0];
var line = context.lines[y][1];
var parts = [];
var p = null;
for (var x = 0; x < line.length; ++x) {
if (x == 0 ||
(x == context.cx && y == context.cy) ||
p[0] != line[x][0] || p[1] != line[x][1]) {
parts.push([line[x][0], line[x][1], []]);
p = parts[parts.length - 1];
if (x == context.cx && y == context.cy) {
p[0] |= 0x1000000;
}
}
p[2].push(line[x][2]);
}
if (x == context.cx && y == context.cy) {
parts.push([DEFAULT_FG | 0x1000000, DEFAULT_BG, []]);
}
var ntag = document.createElement('pre');
ntag.style.width = '100%';
ntag.style.whiteSpace = 'pre-wrap';
ntag.style.margin = '0px';
for (var i = 0; i < parts.length; ++i) {
if (parts[i][0] & 0x1000000) {
var span = document.createElement('span');
span.innerText = '|';
ntag.appendChild(span);
}
var span = document.createElement('span');
span.innerText = new TextDecoder('utf-8').decode(new Uint8Array(parts[i][2]));
span.style.color = context.toRGB(parts[i][0]);
span.style.backgroundColor = context.toRGB(parts[i][1]);
ntag.appendChild(span);
}
context.terminal.replaceChild(ntag, tag);
context.lines[y][0] = ntag;
}
context.dirty = {};
var newline = count > 1;
if (newline) {
window.scrollTo(0, document.body.scrollHeight + 100);
}
return newline;
}; };
context.keyboard = document.createElement('div'); context.keyboard = document.createElement('div');
@ -282,12 +418,6 @@ if (!globalObj.write) {
} }
} }
window.onkeydown = KeyDown; window.onkeydown = KeyDown;
context.Update = function(newline) {
var cursor = String.fromCharCode(0x2592);
context.last_line.innerText = new TextDecoder('utf-8').decode(
new Uint8Array(context.outbuffer)) + (newline ? '' : cursor);
};
context.ResetTerminal();
window.addEventListener('paste', function(e) { window.addEventListener('paste', function(e) {
context.Inject(e.clipboardData.getData('text')); context.Inject(e.clipboardData.getData('text'));
}); });
@ -305,26 +435,11 @@ r|
write(text); write(text);
sp += 4; i32[sp>>2] = 0; sp += 4; i32[sp>>2] = 0;
} else { } else {
var newline = false;
for (var i = 0; i < n; ++i) { for (var i = 0; i < n; ++i) {
var ch = u8[a + i]; var ch = u8[a + i];
if (ch == 12) { context.Emit(ch);
context.ResetTerminal();
context.outbuffer = [];
} else if (ch == 8) {
context.outbuffer = context.outbuffer.slice(0, -1);
} else if (ch == 10) {
context.AddLine();
newline = true;
} else if (ch == 13) {
} else {
context.outbuffer.push(ch);
}
}
context.Update();
if (newline) {
window.scrollTo(0, document.body.scrollHeight);
} }
var newline = context.Update();
sp += 4; i32[sp>>2] = newline ? -1 : 0; sp += 4; i32[sp>>2] = newline ? -1 : 0;
} }
return sp; return sp;
@ -479,7 +594,6 @@ r|
forth definitions web forth definitions web
: bye 0 terminate ; : bye 0 terminate ;
: page 12 emit ;
: gr 1 7 call ; : gr 1 7 call ;
: text 0 7 call ; : text 0 7 call ;
: mobile ( -- f ) 12 call ; : mobile ( -- f ) 12 call ;