diff --git a/build.zig b/build.zig
index f4d27a29..b833d2eb 100644
--- a/build.zig
+++ b/build.zig
@@ -362,12 +362,13 @@ pub const App = struct {
if (app.platform == .web) {
const address = std.process.getEnvVarOwned(app.b.allocator, "MACH_ADDRESS") catch app.b.allocator.dupe(u8, "127.0.0.1") catch unreachable;
const port = std.process.getEnvVarOwned(app.b.allocator, "MACH_PORT") catch app.b.allocator.dupe(u8, "8080") catch unreachable;
- const address_parsed = std.net.Address.parseIp4(address, std.fmt.parseInt(u16, port, 10) catch unreachable) catch unreachable;
+ const address_parsed = std.net.Address.resolveIp(address, std.fmt.parseInt(u16, port, 10) catch unreachable) catch unreachable;
const wasmserve = @import("tools/wasmserve/wasmserve.zig");
const serve_step = wasmserve.serve(
app.step,
.{
+ .install_step_name = app.step.name,
.install_dir = web_install_dir,
.watch_paths = &.{"tools/wasmserve/wasmserve.zig"},
.listen_address = address_parsed,
diff --git a/tools/wasmserve/mime.zig b/tools/wasmserve/mime.zig
index b836848e..be35d099 100644
--- a/tools/wasmserve/mime.zig
+++ b/tools/wasmserve/mime.zig
@@ -15,7 +15,7 @@ pub const mime_list = [_]struct { ext: []const []const u8, mime: []const u8 }{
.{ .ext = &.{".ico"}, .mime = "image/vnd.microsoft.icon" },
.{ .ext = &.{".ics"}, .mime = "text/calendar" },
.{ .ext = &.{".jar"}, .mime = "application/java-archive" },
- .{ .ext = &.{ "..jpeg", "..jpg" }, .mime = "image/jpeg" },
+ .{ .ext = &.{ ".jpeg", ".jpg" }, .mime = "image/jpeg" },
.{ .ext = &.{".js"}, .mime = "text/javascript" },
.{ .ext = &.{".json"}, .mime = "application/json" },
.{ .ext = &.{".md"}, .mime = "text/x-markdown" },
diff --git a/tools/wasmserve/wasmserve.zig b/tools/wasmserve/wasmserve.zig
index 4932082e..ff554cd0 100644
--- a/tools/wasmserve/wasmserve.zig
+++ b/tools/wasmserve/wasmserve.zig
@@ -5,8 +5,7 @@ const mem = std.mem;
const fs = std.fs;
const build = std.build;
-const js_path = "/www/wasmserve.js";
-const default_mime = "text/plain";
+const www_dir_path = thisDir() ++ "/www";
const buffer_size = 2048;
const esc = struct {
pub const reset = "\x1b[0m";
@@ -19,6 +18,7 @@ const esc = struct {
};
pub const Options = struct {
+ install_step_name: []const u8 = "install",
install_dir: ?build.InstallDir = null,
watch_paths: []const []const u8 = &.{},
listen_address: net.Address = net.Address.initIp4([4]u8{ 127, 0, 0, 1 }, 8080),
@@ -31,14 +31,16 @@ pub fn serve(step: *build.LibExeObjStep, options: Options) !*Wasmserve {
.step = build.Step.init(.run, "wasmserve", step.builder.allocator, Wasmserve.make),
.b = step.builder,
.exe_step = step,
+ .install_step_name = options.install_step_name,
.install_dir = install_dir,
.install_dir_iter = try fs.cwd().makeOpenPathIterable(step.builder.getInstallPath(install_dir, ""), .{}),
.address = options.listen_address,
.subscriber = null,
.watch_paths = options.watch_paths,
.mtimes = std.AutoHashMap(fs.File.INode, i128).init(step.builder.allocator),
+ .status = .idle,
+ .notify_msg = try step.builder.allocator.alloc(u8, 0),
};
- self.step.dependOn(&step.install_step.?.step);
return self;
}
@@ -46,15 +48,20 @@ const Wasmserve = struct {
step: build.Step,
b: *build.Builder,
exe_step: *build.LibExeObjStep,
+ install_step_name: []const u8,
install_dir: build.InstallDir,
install_dir_iter: fs.IterableDir,
address: net.Address,
subscriber: ?*net.StreamServer.Connection,
watch_paths: []const []const u8,
mtimes: std.AutoHashMap(fs.File.INode, i128),
+ status: Status,
+ notify_msg: []u8,
- const NotifyMessage = enum {
- reload,
+ const Status = enum {
+ idle,
+ built,
+ build_error,
};
pub fn make(step: *build.Step) !void {
@@ -63,12 +70,19 @@ const Wasmserve = struct {
self.compile();
std.debug.assert(mem.eql(u8, fs.path.extension(self.exe_step.out_filename), ".wasm"));
- const install_js = self.b.addInstallFileWithDir(
- .{ .path = comptime thisDir() ++ js_path },
- self.install_dir,
- fs.path.basename(js_path),
- );
- try install_js.step.make();
+ var www_dir = try fs.cwd().openIterableDir(www_dir_path, .{});
+ defer www_dir.close();
+ var www_dir_iter = www_dir.iterate();
+ while (try www_dir_iter.next()) |file| {
+ const path = try fs.path.join(self.b.allocator, &.{ www_dir_path, file.name });
+ defer self.b.allocator.free(path);
+ const install_www = self.b.addInstallFileWithDir(
+ .{ .path = path },
+ self.install_dir,
+ file.name,
+ );
+ try install_www.step.make();
+ }
const watch_thread = try std.Thread.spawn(.{}, watch, .{self});
defer watch_thread.detach();
@@ -118,6 +132,7 @@ const Wasmserve = struct {
_ = try conn.stream.write("HTTP/1.1 200 OK\r\nConnection: Keep-Alive\r\nContent-Type: text/event-stream\r\nCache-Control: No-Cache\r\n\r\n");
self.subscriber = try self.b.allocator.create(net.StreamServer.Connection);
self.subscriber.?.* = conn;
+ self.notify();
return;
}
if (self.researchPath(url)) |file_path| {
@@ -240,19 +255,38 @@ const Wasmserve = struct {
return false;
}
- fn notify(self: *Wasmserve, msg: NotifyMessage) void {
- if (self.subscriber) |s|
- _ = s.stream.writer().print("data: {s}\n\n", .{@tagName(msg)}) catch |err| logErr(err, @src());
+ fn notify(self: *Wasmserve) void {
+ if (self.subscriber) |s| {
+ s.stream.writer().print("event: {s}\n", .{@tagName(self.status)}) catch |err| logErr(err, @src());
+ var lines = std.mem.split(u8, self.notify_msg, "\n");
+ while (lines.next()) |line|
+ s.stream.writer().print("data: {s}\n", .{line}) catch |err| logErr(err, @src());
+ _ = s.stream.write("\n") catch |err| logErr(err, @src());
+ if (self.status == .built) self.status = .idle;
+ }
}
fn compile(self: *Wasmserve) void {
std.log.info("Compiling...", .{});
- self.exe_step.install_step.?.step.done_flag = false;
- if (self.exe_step.install_step.?.step.make()) {
- self.notify(.reload);
- } else |err| {
+ const res = std.ChildProcess.exec(.{
+ .allocator = self.b.allocator,
+ .argv = &.{ self.b.zig_exe, "build", self.install_step_name, "--prominent-compile-errors", "--color", "on" },
+ }) catch |err| {
logErr(err, @src());
+ return;
+ };
+ self.b.allocator.free(res.stdout);
+ self.b.allocator.free(self.notify_msg);
+ std.debug.print("{s}", .{res.stderr});
+ self.notify_msg = res.stderr;
+ switch (res.term) {
+ .Exited => |code| {
+ self.status = if (code == 0) .built else .build_error;
+ },
+ // TODO: separate status and message
+ else => {},
}
+ self.notify();
}
};
diff --git a/tools/wasmserve/www/ansi_up.js b/tools/wasmserve/www/ansi_up.js
new file mode 100644
index 00000000..0e18da51
--- /dev/null
+++ b/tools/wasmserve/www/ansi_up.js
@@ -0,0 +1,416 @@
+/* ansi_up.js
+ * author : Dru Nelson
+ * license : MIT
+ * http://github.com/drudru/ansi_up
+ *
+ * NOTE: modifed to work with browser JS modules
+ */
+var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) {
+ if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
+ return cooked;
+};
+var PacketKind;
+(function (PacketKind) {
+ PacketKind[PacketKind["EOS"] = 0] = "EOS";
+ PacketKind[PacketKind["Text"] = 1] = "Text";
+ PacketKind[PacketKind["Incomplete"] = 2] = "Incomplete";
+ PacketKind[PacketKind["ESC"] = 3] = "ESC";
+ PacketKind[PacketKind["Unknown"] = 4] = "Unknown";
+ PacketKind[PacketKind["SGR"] = 5] = "SGR";
+ PacketKind[PacketKind["OSCURL"] = 6] = "OSCURL";
+})(PacketKind || (PacketKind = {}));
+export default (function () {
+ function AnsiUp() {
+ this.VERSION = "5.1.0";
+ this.setup_palettes();
+ this._use_classes = false;
+ this.bold = false;
+ this.italic = false;
+ this.underline = false;
+ this.fg = this.bg = null;
+ this._buffer = '';
+ this._url_whitelist = { 'http': 1, 'https': 1 };
+ }
+ Object.defineProperty(AnsiUp.prototype, "use_classes", {
+ get: function () {
+ return this._use_classes;
+ },
+ set: function (arg) {
+ this._use_classes = arg;
+ },
+ enumerable: false,
+ configurable: true
+ });
+ Object.defineProperty(AnsiUp.prototype, "url_whitelist", {
+ get: function () {
+ return this._url_whitelist;
+ },
+ set: function (arg) {
+ this._url_whitelist = arg;
+ },
+ enumerable: false,
+ configurable: true
+ });
+ AnsiUp.prototype.setup_palettes = function () {
+ var _this = this;
+ this.ansi_colors =
+ [
+ [
+ { rgb: [0, 0, 0], class_name: "ansi-black" },
+ { rgb: [187, 0, 0], class_name: "ansi-red" },
+ { rgb: [0, 187, 0], class_name: "ansi-green" },
+ { rgb: [187, 187, 0], class_name: "ansi-yellow" },
+ { rgb: [0, 0, 187], class_name: "ansi-blue" },
+ { rgb: [187, 0, 187], class_name: "ansi-magenta" },
+ { rgb: [0, 187, 187], class_name: "ansi-cyan" },
+ { rgb: [255, 255, 255], class_name: "ansi-white" }
+ ],
+ [
+ { rgb: [85, 85, 85], class_name: "ansi-bright-black" },
+ { rgb: [255, 85, 85], class_name: "ansi-bright-red" },
+ { rgb: [0, 255, 0], class_name: "ansi-bright-green" },
+ { rgb: [255, 255, 85], class_name: "ansi-bright-yellow" },
+ { rgb: [85, 85, 255], class_name: "ansi-bright-blue" },
+ { rgb: [255, 85, 255], class_name: "ansi-bright-magenta" },
+ { rgb: [85, 255, 255], class_name: "ansi-bright-cyan" },
+ { rgb: [255, 255, 255], class_name: "ansi-bright-white" }
+ ]
+ ];
+ this.palette_256 = [];
+ this.ansi_colors.forEach(function (palette) {
+ palette.forEach(function (rec) {
+ _this.palette_256.push(rec);
+ });
+ });
+ var levels = [0, 95, 135, 175, 215, 255];
+ for (var r = 0; r < 6; ++r) {
+ for (var g = 0; g < 6; ++g) {
+ for (var b = 0; b < 6; ++b) {
+ var col = { rgb: [levels[r], levels[g], levels[b]], class_name: 'truecolor' };
+ this.palette_256.push(col);
+ }
+ }
+ }
+ var grey_level = 8;
+ for (var i = 0; i < 24; ++i, grey_level += 10) {
+ var gry = { rgb: [grey_level, grey_level, grey_level], class_name: 'truecolor' };
+ this.palette_256.push(gry);
+ }
+ };
+ AnsiUp.prototype.escape_txt_for_html = function (txt) {
+ return txt.replace(/[&<>"']/gm, function (str) {
+ if (str === "&")
+ return "&";
+ if (str === "<")
+ return "<";
+ if (str === ">")
+ return ">";
+ if (str === "\"")
+ return """;
+ if (str === "'")
+ return "'";
+ });
+ };
+ AnsiUp.prototype.append_buffer = function (txt) {
+ var str = this._buffer + txt;
+ this._buffer = str;
+ };
+ AnsiUp.prototype.get_next_packet = function () {
+ var pkt = {
+ kind: PacketKind.EOS,
+ text: '',
+ url: ''
+ };
+ var len = this._buffer.length;
+ if (len == 0)
+ return pkt;
+ var pos = this._buffer.indexOf("\x1B");
+ if (pos == -1) {
+ pkt.kind = PacketKind.Text;
+ pkt.text = this._buffer;
+ this._buffer = '';
+ return pkt;
+ }
+ if (pos > 0) {
+ pkt.kind = PacketKind.Text;
+ pkt.text = this._buffer.slice(0, pos);
+ this._buffer = this._buffer.slice(pos);
+ return pkt;
+ }
+ if (pos == 0) {
+ if (len == 1) {
+ pkt.kind = PacketKind.Incomplete;
+ return pkt;
+ }
+ var next_char = this._buffer.charAt(1);
+ if ((next_char != '[') && (next_char != ']')) {
+ pkt.kind = PacketKind.ESC;
+ pkt.text = this._buffer.slice(0, 1);
+ this._buffer = this._buffer.slice(1);
+ return pkt;
+ }
+ if (next_char == '[') {
+ if (!this._csi_regex) {
+ this._csi_regex = rgx(__makeTemplateObject(["\n ^ # beginning of line\n #\n # First attempt\n (?: # legal sequence\n \u001B[ # CSI\n ([<-?]?) # private-mode char\n ([d;]*) # any digits or semicolons\n ([ -/]? # an intermediate modifier\n [@-~]) # the command\n )\n | # alternate (second attempt)\n (?: # illegal sequence\n \u001B[ # CSI\n [ -~]* # anything legal\n ([\0-\u001F:]) # anything illegal\n )\n "], ["\n ^ # beginning of line\n #\n # First attempt\n (?: # legal sequence\n \\x1b\\[ # CSI\n ([\\x3c-\\x3f]?) # private-mode char\n ([\\d;]*) # any digits or semicolons\n ([\\x20-\\x2f]? # an intermediate modifier\n [\\x40-\\x7e]) # the command\n )\n | # alternate (second attempt)\n (?: # illegal sequence\n \\x1b\\[ # CSI\n [\\x20-\\x7e]* # anything legal\n ([\\x00-\\x1f:]) # anything illegal\n )\n "]));
+ }
+ var match = this._buffer.match(this._csi_regex);
+ if (match === null) {
+ pkt.kind = PacketKind.Incomplete;
+ return pkt;
+ }
+ if (match[4]) {
+ pkt.kind = PacketKind.ESC;
+ pkt.text = this._buffer.slice(0, 1);
+ this._buffer = this._buffer.slice(1);
+ return pkt;
+ }
+ if ((match[1] != '') || (match[3] != 'm'))
+ pkt.kind = PacketKind.Unknown;
+ else
+ pkt.kind = PacketKind.SGR;
+ pkt.text = match[2];
+ var rpos = match[0].length;
+ this._buffer = this._buffer.slice(rpos);
+ return pkt;
+ }
+ if (next_char == ']') {
+ if (len < 4) {
+ pkt.kind = PacketKind.Incomplete;
+ return pkt;
+ }
+ if ((this._buffer.charAt(2) != '8')
+ || (this._buffer.charAt(3) != ';')) {
+ pkt.kind = PacketKind.ESC;
+ pkt.text = this._buffer.slice(0, 1);
+ this._buffer = this._buffer.slice(1);
+ return pkt;
+ }
+ if (!this._osc_st) {
+ this._osc_st = rgxG(__makeTemplateObject(["\n (?: # legal sequence\n (\u001B\\) # ESC | # alternate\n (\u0007) # BEL (what xterm did)\n )\n | # alternate (second attempt)\n ( # illegal sequence\n [\0-\u0006] # anything illegal\n | # alternate\n [\b-\u001A] # anything illegal\n | # alternate\n [\u001C-\u001F] # anything illegal\n )\n "], ["\n (?: # legal sequence\n (\\x1b\\\\) # ESC \\\n | # alternate\n (\\x07) # BEL (what xterm did)\n )\n | # alternate (second attempt)\n ( # illegal sequence\n [\\x00-\\x06] # anything illegal\n | # alternate\n [\\x08-\\x1a] # anything illegal\n | # alternate\n [\\x1c-\\x1f] # anything illegal\n )\n "]));
+ }
+ this._osc_st.lastIndex = 0;
+ {
+ var match_1 = this._osc_st.exec(this._buffer);
+ if (match_1 === null) {
+ pkt.kind = PacketKind.Incomplete;
+ return pkt;
+ }
+ if (match_1[3]) {
+ pkt.kind = PacketKind.ESC;
+ pkt.text = this._buffer.slice(0, 1);
+ this._buffer = this._buffer.slice(1);
+ return pkt;
+ }
+ }
+ {
+ var match_2 = this._osc_st.exec(this._buffer);
+ if (match_2 === null) {
+ pkt.kind = PacketKind.Incomplete;
+ return pkt;
+ }
+ if (match_2[3]) {
+ pkt.kind = PacketKind.ESC;
+ pkt.text = this._buffer.slice(0, 1);
+ this._buffer = this._buffer.slice(1);
+ return pkt;
+ }
+ }
+ if (!this._osc_regex) {
+ this._osc_regex = rgx(__makeTemplateObject(["\n ^ # beginning of line\n #\n \u001B]8; # OSC Hyperlink\n [ -:<-~]* # params (excluding ;)\n ; # end of params\n ([!-~]{0,512}) # URL capture\n (?: # ST\n (?:\u001B\\) # ESC | # alternate\n (?:\u0007) # BEL (what xterm did)\n )\n ([ -~]+) # TEXT capture\n \u001B]8;; # OSC Hyperlink End\n (?: # ST\n (?:\u001B\\) # ESC | # alternate\n (?:\u0007) # BEL (what xterm did)\n )\n "], ["\n ^ # beginning of line\n #\n \\x1b\\]8; # OSC Hyperlink\n [\\x20-\\x3a\\x3c-\\x7e]* # params (excluding ;)\n ; # end of params\n ([\\x21-\\x7e]{0,512}) # URL capture\n (?: # ST\n (?:\\x1b\\\\) # ESC \\\n | # alternate\n (?:\\x07) # BEL (what xterm did)\n )\n ([\\x20-\\x7e]+) # TEXT capture\n \\x1b\\]8;; # OSC Hyperlink End\n (?: # ST\n (?:\\x1b\\\\) # ESC \\\n | # alternate\n (?:\\x07) # BEL (what xterm did)\n )\n "]));
+ }
+ var match = this._buffer.match(this._osc_regex);
+ if (match === null) {
+ pkt.kind = PacketKind.ESC;
+ pkt.text = this._buffer.slice(0, 1);
+ this._buffer = this._buffer.slice(1);
+ return pkt;
+ }
+ pkt.kind = PacketKind.OSCURL;
+ pkt.url = match[1];
+ pkt.text = match[2];
+ var rpos = match[0].length;
+ this._buffer = this._buffer.slice(rpos);
+ return pkt;
+ }
+ }
+ };
+ AnsiUp.prototype.ansi_to_html = function (txt) {
+ this.append_buffer(txt);
+ var blocks = [];
+ while (true) {
+ var packet = this.get_next_packet();
+ if ((packet.kind == PacketKind.EOS)
+ || (packet.kind == PacketKind.Incomplete))
+ break;
+ if ((packet.kind == PacketKind.ESC)
+ || (packet.kind == PacketKind.Unknown))
+ continue;
+ if (packet.kind == PacketKind.Text)
+ blocks.push(this.transform_to_html(this.with_state(packet)));
+ else if (packet.kind == PacketKind.SGR)
+ this.process_ansi(packet);
+ else if (packet.kind == PacketKind.OSCURL)
+ blocks.push(this.process_hyperlink(packet));
+ }
+ return blocks.join("");
+ };
+ AnsiUp.prototype.with_state = function (pkt) {
+ return { bold: this.bold, italic: this.italic, underline: this.underline, fg: this.fg, bg: this.bg, text: pkt.text };
+ };
+ AnsiUp.prototype.process_ansi = function (pkt) {
+ var sgr_cmds = pkt.text.split(';');
+ while (sgr_cmds.length > 0) {
+ var sgr_cmd_str = sgr_cmds.shift();
+ var num = parseInt(sgr_cmd_str, 10);
+ if (isNaN(num) || num === 0) {
+ this.fg = this.bg = null;
+ this.bold = false;
+ this.italic = false;
+ this.underline = false;
+ }
+ else if (num === 1) {
+ this.bold = true;
+ }
+ else if (num === 3) {
+ this.italic = true;
+ }
+ else if (num === 4) {
+ this.underline = true;
+ }
+ else if (num === 22) {
+ this.bold = false;
+ }
+ else if (num === 23) {
+ this.italic = false;
+ }
+ else if (num === 24) {
+ this.underline = false;
+ }
+ else if (num === 39) {
+ this.fg = null;
+ }
+ else if (num === 49) {
+ this.bg = null;
+ }
+ else if ((num >= 30) && (num < 38)) {
+ this.fg = this.ansi_colors[0][(num - 30)];
+ }
+ else if ((num >= 40) && (num < 48)) {
+ this.bg = this.ansi_colors[0][(num - 40)];
+ }
+ else if ((num >= 90) && (num < 98)) {
+ this.fg = this.ansi_colors[1][(num - 90)];
+ }
+ else if ((num >= 100) && (num < 108)) {
+ this.bg = this.ansi_colors[1][(num - 100)];
+ }
+ else if (num === 38 || num === 48) {
+ if (sgr_cmds.length > 0) {
+ var is_foreground = (num === 38);
+ var mode_cmd = sgr_cmds.shift();
+ if (mode_cmd === '5' && sgr_cmds.length > 0) {
+ var palette_index = parseInt(sgr_cmds.shift(), 10);
+ if (palette_index >= 0 && palette_index <= 255) {
+ if (is_foreground)
+ this.fg = this.palette_256[palette_index];
+ else
+ this.bg = this.palette_256[palette_index];
+ }
+ }
+ if (mode_cmd === '2' && sgr_cmds.length > 2) {
+ var r = parseInt(sgr_cmds.shift(), 10);
+ var g = parseInt(sgr_cmds.shift(), 10);
+ var b = parseInt(sgr_cmds.shift(), 10);
+ if ((r >= 0 && r <= 255) && (g >= 0 && g <= 255) && (b >= 0 && b <= 255)) {
+ var c = { rgb: [r, g, b], class_name: 'truecolor' };
+ if (is_foreground)
+ this.fg = c;
+ else
+ this.bg = c;
+ }
+ }
+ }
+ }
+ }
+ };
+ AnsiUp.prototype.transform_to_html = function (fragment) {
+ var txt = fragment.text;
+ if (txt.length === 0)
+ return txt;
+ txt = this.escape_txt_for_html(txt);
+ if (!fragment.bold && !fragment.italic && !fragment.underline && fragment.fg === null && fragment.bg === null)
+ return txt;
+ var styles = [];
+ var classes = [];
+ var fg = fragment.fg;
+ var bg = fragment.bg;
+ if (fragment.bold)
+ styles.push('font-weight:bold');
+ if (fragment.italic)
+ styles.push('font-style:italic');
+ if (fragment.underline)
+ styles.push('text-decoration:underline');
+ if (!this._use_classes) {
+ if (fg)
+ styles.push("color:rgb(" + fg.rgb.join(',') + ")");
+ if (bg)
+ styles.push("background-color:rgb(" + bg.rgb + ")");
+ }
+ else {
+ if (fg) {
+ if (fg.class_name !== 'truecolor') {
+ classes.push(fg.class_name + "-fg");
+ }
+ else {
+ styles.push("color:rgb(" + fg.rgb.join(',') + ")");
+ }
+ }
+ if (bg) {
+ if (bg.class_name !== 'truecolor') {
+ classes.push(bg.class_name + "-bg");
+ }
+ else {
+ styles.push("background-color:rgb(" + bg.rgb.join(',') + ")");
+ }
+ }
+ }
+ var class_string = '';
+ var style_string = '';
+ if (classes.length)
+ class_string = " class=\"" + classes.join(' ') + "\"";
+ if (styles.length)
+ style_string = " style=\"" + styles.join(';') + "\"";
+ return "" + txt + "";
+ };
+ ;
+ AnsiUp.prototype.process_hyperlink = function (pkt) {
+ var parts = pkt.url.split(':');
+ if (parts.length < 1)
+ return '';
+ if (!this._url_whitelist[parts[0]])
+ return '';
+ var result = "" + this.escape_txt_for_html(pkt.text) + "";
+ return result;
+ };
+ return AnsiUp;
+}());
+function rgx(tmplObj) {
+ var subst = [];
+ for (var _i = 1; _i < arguments.length; _i++) {
+ subst[_i - 1] = arguments[_i];
+ }
+ var regexText = tmplObj.raw[0];
+ var wsrgx = /^\s+|\s+\n|\s*#[\s\S]*?\n|\n/gm;
+ var txt2 = regexText.replace(wsrgx, '');
+ return new RegExp(txt2);
+}
+function rgxG(tmplObj) {
+ var subst = [];
+ for (var _i = 1; _i < arguments.length; _i++) {
+ subst[_i - 1] = arguments[_i];
+ }
+ var regexText = tmplObj.raw[0];
+ var wsrgx = /^\s+|\s+\n|\s*#[\s\S]*?\n|\n/gm;
+ var txt2 = regexText.replace(wsrgx, '');
+ return new RegExp(txt2, 'g');
+}
diff --git a/tools/wasmserve/www/wasmserve.js b/tools/wasmserve/www/wasmserve.js
index f26395f3..e9592bf9 100644
--- a/tools/wasmserve/www/wasmserve.js
+++ b/tools/wasmserve/www/wasmserve.js
@@ -1,11 +1,57 @@
+import AnsiUp from "./ansi_up.js";
+const ansiup = new AnsiUp;
+
let evtSource = new EventSource("/notify");
function setup() {
- evtSource.addEventListener("message", function (e) {
- if (e.data === "reload") {
- window.location.reload();
- }
- });
+ evtSource.addEventListener("built", function (e) {
+ window.location.reload();
+ });
+ evtSource.addEventListener("build_error", function (e) {
+ if (document.getElementById("error-screen") == null) {
+ let es = document.createElement("div");
+ es.id = "error-screen";
+ es.style.cssText = error_screen_css;
+ let h2 = document.createElement("h2");
+ let pre = document.createElement("pre");
+ h2.textContent = "An error occurred while building:";
+ h2.style.cssText = error_screen_h2_css;
+ pre.innerHTML = ansiup.ansi_to_html(e.data);
+ pre.style.cssText = error_screen_pre_css;
+ es.appendChild(h2);
+ es.appendChild(pre);
+ document.body.appendChild(es);
+ console.error(e.data);
+ } else {
+ document.getElementById("error-screen").
+ getElementsByTagName("pre").innerHTML = ansiup.ansi_to_html(e.data);
+ }
+ });
}
+const error_screen_css =
+ "position: absolute;" +
+ "width: 100vw;" +
+ "height: 100vh;" +
+ "top: 0;" +
+ "left: 0;" +
+ "background: rgba(0, 0, 0, 0.85);" +
+ "font-family: system-ui, monospace;" +
+ "font-size: 16pt;" +
+ "padding: 20px;" +
+ "box-sizing: border-box;";
+
+const error_screen_h2_css =
+ "color: white;" +
+ "margin-top: 0;";
+
+const error_screen_pre_css =
+ "border: 2px solid rgb(205, 92, 92);" +
+ "padding: 10px;" +
+ "background: rgba(0, 0, 0, 0.5);" +
+ "font-size: 12pt;" +
+ "white-space: pre-wrap;" +
+ "overflow: hidden;" +
+ "color: lightgray;";
+
export default setup;