diff --git a/build.zig b/build.zig index 15fed7ed6..b798308ce 100644 --- a/build.zig +++ b/build.zig @@ -716,7 +716,8 @@ pub fn build(b: *std.Build) !void { // Build our Wasm target. const wasm_crosstarget: std.Target.Query = .{ .cpu_arch = .wasm32, - .os_tag = .freestanding, + .os_tag = .wasi, + .abi = .musl, .cpu_model = .{ .explicit = &std.Target.wasm.cpu.mvp }, .cpu_features_add = std.Target.wasm.featureSet(&.{ // We use this to explicitly request shared memory. @@ -748,7 +749,7 @@ pub fn build(b: *std.Build) !void { break :config copy; }; - const wasm = b.addSharedLibrary(.{ + const wasm = b.addExecutable(.{ .name = "ghostty-wasm", .root_source_file = b.path("src/main_wasm.zig"), .target = b.resolveTargetQuery(wasm_crosstarget), @@ -757,9 +758,14 @@ pub fn build(b: *std.Build) !void { // So that we can use web workers with our wasm binary wasm.import_memory = true; - wasm.initial_memory = 65536 * 25; + wasm.initial_memory = 65536 * 512; + wasm.entry = .disabled; + wasm.wasi_exec_model = .reactor; + wasm.rdynamic = true; + wasm.import_symbols = true; wasm.max_memory = 65536 * 65536; // Maximum number of pages in wasm32 wasm.shared_memory = wasm_shared; + wasm.root_module.single_threaded = false; // Stack protector adds extern requirements that we don't satisfy. wasm.root_module.stack_protector = false; @@ -769,10 +775,11 @@ pub fn build(b: *std.Build) !void { // Install const wasm_install = b.addInstallArtifact(wasm, .{}); - wasm_install.dest_dir = .{ .prefix = {} }; + const install = b.addInstallFile(wasm.getEmittedBin(), "../example/ghostty-wasm.wasm"); + wasm_install.step.dependOn(&install.step); const step = b.step("wasm", "Build the wasm library"); - step.dependOn(&wasm_install.step); + step.dependOn(&install.step); // We support tests via wasmtime. wasmtime uses WASI so this // isn't an exact match to our freestanding target above but @@ -1073,81 +1080,82 @@ fn addDeps( try static_libs.append(fontconfig_dep.artifact("fontconfig").getEmittedBin()); } } + if (step.rootModuleTarget().cpu.arch != .wasm32) { + // Libpng - Ghostty doesn't actually use this directly, its only used + // through dependencies, so we only need to add it to our static + // libs list if we're not using system integration. The dependencies + // will handle linking it. + if (!b.systemIntegrationOption("libpng", .{})) { + const libpng_dep = b.dependency("libpng", .{ + .target = target, + .optimize = optimize, + }); + step.linkLibrary(libpng_dep.artifact("png")); + try static_libs.append(libpng_dep.artifact("png").getEmittedBin()); + } - // Libpng - Ghostty doesn't actually use this directly, its only used - // through dependencies, so we only need to add it to our static - // libs list if we're not using system integration. The dependencies - // will handle linking it. - if (!b.systemIntegrationOption("libpng", .{})) { - const libpng_dep = b.dependency("libpng", .{ + // Zlib - same as libpng, only used through dependencies. + if (!b.systemIntegrationOption("zlib", .{})) { + const zlib_dep = b.dependency("zlib", .{ + .target = target, + .optimize = optimize, + }); + step.linkLibrary(zlib_dep.artifact("z")); + try static_libs.append(zlib_dep.artifact("z").getEmittedBin()); + } + + // Oniguruma + const oniguruma_dep = b.dependency("oniguruma", .{ .target = target, .optimize = optimize, }); - step.linkLibrary(libpng_dep.artifact("png")); - try static_libs.append(libpng_dep.artifact("png").getEmittedBin()); - } + step.root_module.addImport("oniguruma", oniguruma_dep.module("oniguruma")); + if (b.systemIntegrationOption("oniguruma", .{})) { + // Oniguruma is compiled and distributed as libonig.so + step.linkSystemLibrary2("onig", dynamic_link_opts); + } else { + step.linkLibrary(oniguruma_dep.artifact("oniguruma")); + try static_libs.append(oniguruma_dep.artifact("oniguruma").getEmittedBin()); + } - // Zlib - same as libpng, only used through dependencies. - if (!b.systemIntegrationOption("zlib", .{})) { - const zlib_dep = b.dependency("zlib", .{ + // Glslang + const glslang_dep = b.dependency("glslang", .{ .target = target, .optimize = optimize, }); - step.linkLibrary(zlib_dep.artifact("z")); - try static_libs.append(zlib_dep.artifact("z").getEmittedBin()); - } + step.root_module.addImport("glslang", glslang_dep.module("glslang")); + if (b.systemIntegrationOption("glslang", .{})) { + step.linkSystemLibrary2("glslang", dynamic_link_opts); + step.linkSystemLibrary2("glslang-default-resource-limits", dynamic_link_opts); + } else { + step.linkLibrary(glslang_dep.artifact("glslang")); + try static_libs.append(glslang_dep.artifact("glslang").getEmittedBin()); + } - // Oniguruma - const oniguruma_dep = b.dependency("oniguruma", .{ - .target = target, - .optimize = optimize, - }); - step.root_module.addImport("oniguruma", oniguruma_dep.module("oniguruma")); - if (b.systemIntegrationOption("oniguruma", .{})) { - // Oniguruma is compiled and distributed as libonig.so - step.linkSystemLibrary2("onig", dynamic_link_opts); - } else { - step.linkLibrary(oniguruma_dep.artifact("oniguruma")); - try static_libs.append(oniguruma_dep.artifact("oniguruma").getEmittedBin()); - } - - // Glslang - const glslang_dep = b.dependency("glslang", .{ - .target = target, - .optimize = optimize, - }); - step.root_module.addImport("glslang", glslang_dep.module("glslang")); - if (b.systemIntegrationOption("glslang", .{})) { - step.linkSystemLibrary2("glslang", dynamic_link_opts); - step.linkSystemLibrary2("glslang-default-resource-limits", dynamic_link_opts); - } else { - step.linkLibrary(glslang_dep.artifact("glslang")); - try static_libs.append(glslang_dep.artifact("glslang").getEmittedBin()); - } - - // Spirv-cross - const spirv_cross_dep = b.dependency("spirv_cross", .{ - .target = target, - .optimize = optimize, - }); - step.root_module.addImport("spirv_cross", spirv_cross_dep.module("spirv_cross")); - if (b.systemIntegrationOption("spirv-cross", .{})) { - step.linkSystemLibrary2("spirv-cross", dynamic_link_opts); - } else { - step.linkLibrary(spirv_cross_dep.artifact("spirv_cross")); - try static_libs.append(spirv_cross_dep.artifact("spirv_cross").getEmittedBin()); - } - - // Simdutf - if (b.systemIntegrationOption("simdutf", .{})) { - step.linkSystemLibrary2("simdutf", dynamic_link_opts); - } else { - const simdutf_dep = b.dependency("simdutf", .{ + // Spirv-cross + const spirv_cross_dep = b.dependency("spirv_cross", .{ .target = target, .optimize = optimize, }); - step.linkLibrary(simdutf_dep.artifact("simdutf")); - try static_libs.append(simdutf_dep.artifact("simdutf").getEmittedBin()); + step.root_module.addImport("spirv_cross", spirv_cross_dep.module("spirv_cross")); + if (b.systemIntegrationOption("spirv-cross", .{})) { + step.linkSystemLibrary2("spirv-cross", dynamic_link_opts); + } else { + step.linkLibrary(spirv_cross_dep.artifact("spirv_cross")); + try static_libs.append(spirv_cross_dep.artifact("spirv_cross").getEmittedBin()); + } + + // Simdutf + if (b.systemIntegrationOption("simdutf", .{})) { + step.linkSystemLibrary2("simdutf", dynamic_link_opts); + } else { + const simdutf_dep = b.dependency("simdutf", .{ + .target = target, + .optimize = optimize, + }); + step.linkLibrary(simdutf_dep.artifact("simdutf")); + try static_libs.append(simdutf_dep.artifact("simdutf").getEmittedBin()); + } } // Sentry @@ -1157,7 +1165,7 @@ fn addDeps( .backend = .breakpad, }); step.root_module.addImport("sentry", sentry_dep.module("sentry")); - if (target.result.os.tag != .windows) { + if (target.result.os.tag != .windows and target.result.cpu.arch != .wasm32) { // Sentry step.linkLibrary(sentry_dep.artifact("sentry")); try static_libs.append(sentry_dep.artifact("sentry").getEmittedBin()); @@ -1177,6 +1185,83 @@ fn addDeps( .optimize = optimize, }); step.root_module.addImport("zig-js", js_dep.module("zig-js")); + step.root_module.addImport("ziglyph", b.dependency("ziglyph", .{ + .target = target, + .optimize = optimize, + }).module("ziglyph")); + step.root_module.addImport("z2d", b.addModule("z2d", .{ + .root_source_file = b.dependency("z2d", .{}).path("src/z2d.zig"), + .target = target, + .optimize = optimize, + })); + step.root_module.addImport("opengl", b.dependency( + "opengl", + .{}, + ).module("opengl")); + step.root_module.addImport("xev", b.dependency("libxev", .{ + .target = target, + .optimize = optimize, + }).module("xev")); + step.root_module.addImport("wuffs", b.dependency("wuffs", .{ + .target = target, + .optimize = optimize, + }).module("wuffs")); + const oniguruma_dep = b.dependency("oniguruma", .{ + .target = target, + .optimize = optimize, + }); + step.root_module.addImport("oniguruma", oniguruma_dep.module("oniguruma")); + step.linkLibrary(oniguruma_dep.artifact("oniguruma")); + try static_libs.append(oniguruma_dep.artifact("oniguruma").getEmittedBin()); + const simdutf_dep = b.dependency("simdutf", .{ + .target = target, + .optimize = optimize, + }); + const utfcpp_dep = b.dependency("utfcpp", .{ + .target = target, + .optimize = optimize, + }); + step.linkLibrary(utfcpp_dep.artifact("utfcpp")); + try static_libs.append(utfcpp_dep.artifact("utfcpp").getEmittedBin()); + step.linkLibrary(simdutf_dep.artifact("simdutf")); + try static_libs.append(simdutf_dep.artifact("simdutf").getEmittedBin()); + step.linkLibC(); + step.linkLibCpp(); + step.addIncludePath(b.path("src")); + { + // From hwy/detect_targets.h + const HWY_AVX3_SPR: c_int = 1 << 4; + const HWY_AVX3_ZEN4: c_int = 1 << 6; + const HWY_AVX3_DL: c_int = 1 << 7; + const HWY_AVX3: c_int = 1 << 8; + + // Zig 0.13 bug: https://github.com/ziglang/zig/issues/20414 + // To workaround this we just disable AVX512 support completely. + // The performance difference between AVX2 and AVX512 is not + // significant for our use case and AVX512 is very rare on consumer + // hardware anyways. + const HWY_DISABLED_TARGETS: c_int = HWY_AVX3_SPR | HWY_AVX3_ZEN4 | HWY_AVX3_DL | HWY_AVX3; + + step.addCSourceFiles(.{ + .files = &.{ + "src/simd/base64.cpp", + "src/simd/codepoint_width.cpp", + "src/simd/index_of.cpp", + "src/simd/vt.cpp", + }, + .flags = if (step.rootModuleTarget().cpu.arch == .x86_64) &.{ + b.fmt("-DHWY_DISABLED_TARGETS={}", .{HWY_DISABLED_TARGETS}), + } else &.{"-DSIMDUTF_NO_THREADS"}, + }); + } + const highway_dep = b.dependency("highway", .{ + .target = target, + .optimize = optimize, + }); + step.linkLibrary(highway_dep.artifact("highway")); + try static_libs.append(highway_dep.artifact("highway").getEmittedBin()); + + try addUnicodeTables(b, step); return static_libs; } diff --git a/build.zig.zon b/build.zig.zon index c5e2d8f70..b9a6773ec 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -4,10 +4,7 @@ .paths = .{""}, .dependencies = .{ // Zig libs - .libxev = .{ - .url = "https://github.com/mitchellh/libxev/archive/b8d1d93e5c899b27abbaa7df23b496c3e6a178c7.tar.gz", - .hash = "1220612bc023c21d75234882ec9a8c6a1cbd9d642da3dfb899297f14bb5bd7b6cd78", - }, + .libxev = .{ .path = "../xev" }, .mach_glfw = .{ .url = "https://github.com/mitchellh/mach-glfw/archive/37c2995f31abcf7e8378fba68ddcf4a3faa02de0.tar.gz", .hash = "12206ed982e709e565d536ce930701a8c07edfd2cfdce428683f3f2a601d37696a62", diff --git a/example/.proxyrc.js b/example/.proxyrc.js new file mode 100644 index 000000000..8e231b5df --- /dev/null +++ b/example/.proxyrc.js @@ -0,0 +1,10 @@ +module.exports = function (app) { + app.use( + (req, res, next) => { + res.setHeader('Cross-Origin-Opener-Policy', 'same-origin'); + res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp'); + res.setHeader('Cross-Origin-Resource-Policy', 'cross-origin'); + next(); + } + ); +}; diff --git a/example/app.ts b/example/app.ts index 5b426a333..ac7940b0f 100644 --- a/example/app.ts +++ b/example/app.ts @@ -1,65 +1,47 @@ -import { ZigJS } from "zig-js"; - -const zjs = new ZigJS(); -const importObject = { - module: {}, - env: { - memory: new WebAssembly.Memory({ - initial: 25, - maximum: 65536, - shared: true, - }), - log: (ptr: number, len: number) => { - const arr = new Uint8ClampedArray(zjs.memory.buffer, ptr, len); - const data = arr.slice(); - const str = new TextDecoder("utf-8").decode(data); - console.log(str); - }, - }, - - ...zjs.importObject(), -}; +import { importObject, setFiles, setStdin, setWasmModule, zjs } from "./imports"; +import { old } from "./old"; const url = new URL("ghostty-wasm.wasm", import.meta.url); fetch(url.href) .then((response) => response.arrayBuffer()) .then((bytes) => WebAssembly.instantiate(bytes, importObject)) - .then((results) => { + .then(async (results) => { const memory = importObject.env.memory; const { - malloc, - free, - config_new, + atlas_clear, + atlas_debug_canvas, + atlas_free, + atlas_grow, + atlas_new, + atlas_reserve, + atlas_set, + config_finalize, config_free, config_load_string, - config_finalize, - face_new, - face_free, - face_render_glyph, - face_debug_canvas, - deferred_face_new, + config_new, deferred_face_free, deferred_face_load, - deferred_face_face, - group_new, - group_free, - group_add_face, - group_init_sprite_face, - group_index_for_codepoint, - group_render_glyph, - group_cache_new, - group_cache_free, - group_cache_index_for_codepoint, - group_cache_render_glyph, - group_cache_atlas_grayscale, - group_cache_atlas_color, - atlas_new, - atlas_free, - atlas_debug_canvas, - shaper_new, + deferred_face_new, + face_debug_canvas, + face_free, + face_new, + face_render_glyph, + free, + malloc, shaper_free, + shaper_new, shaper_test, + collection_new, + collection_add_deferred_face, + shared_grid_new, + shared_grid_atlas_grayscale, + shared_grid_atlas_color, + shared_grid_index_for_codepoint, + shared_grid_render_glyph, + run, + draw, } = results.instance.exports; + // Give us access to the zjs value for debugging. globalThis.zjs = zjs; console.log(zjs); @@ -76,114 +58,41 @@ fetch(url.href) }; // Create our config - const config = config_new(); - const config_str = makeStr("font-family = monospace"); - config_load_string(config, config_str.ptr, config_str.len); - config_finalize(config); - free(config_str.ptr); - - // Create our atlas - // const atlas = atlas_new(512, 0 /* grayscale */); - - // Create some memory for our string - const font_name = makeStr("monospace"); - - // Initialize our deferred face - // const df = deferred_face_new(font_ptr, font.byteLength, 0 /* text */); - //deferred_face_load(df, 72 /* size */); - //const face = deferred_face_face(df); - - // Initialize our font face - //const face = face_new(font_ptr, font.byteLength, 72 /* size in px */); - //free(font_ptr); - - // Create our group - const group = group_new(32 /* size */); - group_add_face( - group, - 0 /* regular */, - deferred_face_new(font_name.ptr, font_name.len, 0 /* text */), - ); - group_add_face( - group, - 0 /* regular */, - deferred_face_new(font_name.ptr, font_name.len, 1 /* emoji */), - ); - - // Initialize our sprite font, without this we just use the browser. - group_init_sprite_face(group); - - // Create our group cache - const group_cache = group_cache_new(group); - - // Render a glyph - // for (let i = 33; i <= 126; i++) { - // const font_idx = group_cache_index_for_codepoint(group_cache, i, 0, -1); - // group_cache_render_glyph(group_cache, font_idx, i, 0); - // //face_render_glyph(face, atlas, i); - // } - // - // const emoji = ["π","π","π","π±","πΏ","π","π","π","π‘","π"]; - // for (let i = 0; i < emoji.length; i++) { - // const cp = emoji[i].codePointAt(0); - // const font_idx = group_cache_index_for_codepoint(group_cache, cp, 0, -1 /* best choice */); - // group_cache_render_glyph(group_cache, font_idx, cp, 0); - // } - - for (let i = 0x2500; i <= 0x257f; i++) { - const font_idx = group_cache_index_for_codepoint(group_cache, i, 0, -1); - group_cache_render_glyph(group_cache, font_idx, i, 0); + const config_str = makeStr("font-family = monospace\nfont-size = 32\n"); + // old(results); + setWasmModule(results.module); + const stdin = new SharedArrayBuffer(1024); + const files = { + nextFd: new SharedArrayBuffer(4), + polling: new SharedArrayBuffer(4), + has: new SharedArrayBuffer(1024), } - for (let i = 0x2580; i <= 0x259f; i++) { - const font_idx = group_cache_index_for_codepoint(group_cache, i, 0, -1); - group_cache_render_glyph(group_cache, font_idx, i, 0); + new Int32Array(files.nextFd)[0] = 4; + setFiles(files); + setStdin(stdin); + run(config_str.ptr, config_str.len); + await new Promise((resolve) => setTimeout(resolve, 500)) + const io = new Uint8ClampedArray(stdin, 4); + const text = new TextEncoder().encode("hello world\r\n"); + io.set(text); + const n = new Int32Array(stdin); + Atomics.store(n, 0, text.length) + Atomics.notify(n, 0); + function drawing() { + requestAnimationFrame(() => { + draw(); + drawing(); + }); + } - for (let i = 0x2800; i <= 0x28ff; i++) { - const font_idx = group_cache_index_for_codepoint(group_cache, i, 0, -1); - group_cache_render_glyph(group_cache, font_idx, i, 0); - } - for (let i = 0x1fb00; i <= 0x1fb3b; i++) { - const font_idx = group_cache_index_for_codepoint(group_cache, i, 0, -1); - group_cache_render_glyph(group_cache, font_idx, i, 0); - } - for (let i = 0x1fb3c; i <= 0x1fb6b; i++) { - const font_idx = group_cache_index_for_codepoint(group_cache, i, 0, -1); - group_cache_render_glyph(group_cache, font_idx, i, 0); - } - - //face_render_glyph(face, atlas, "ζ©".codePointAt(0)); - //face_render_glyph(face, atlas, "p".codePointAt(0)); - - // Debug our canvas - //face_debug_canvas(face); - - // Let's try shaping - const shaper = shaper_new(120); - //const input = makeStr("helloπ"); - const input = makeStr("helloπππ½"); - shaper_test(shaper, group_cache, input.ptr, input.len); - - const cp = 1114112; - const font_idx = group_cache_index_for_codepoint( - group_cache, - cp, - 0, - -1 /* best choice */, - ); - group_cache_render_glyph(group_cache, font_idx, cp, -1); - - // Debug our atlas canvas - { - const atlas = group_cache_atlas_grayscale(group_cache); - const id = atlas_debug_canvas(atlas); - document.getElementById("atlas-canvas").append(zjs.deleteValue(id)); - } - - { - const atlas = group_cache_atlas_color(group_cache); - const id = atlas_debug_canvas(atlas); - document.getElementById("atlas-color-canvas").append(zjs.deleteValue(id)); - } - - //face_free(face); - }); + drawing() + setInterval(() => { + // const text = new TextEncoder().encode("π\n\rππ½\n\rM_ghostty\033[2;2H\033[48;2;240;40;40m\033[38;2;23;255;80mhello"); + const text = new TextEncoder().encode("π\r\nππ½\r\nM_ghostty\033[48;2;240;40;40m\033[38;2;23;255;80mhello\r\n"); + const n = new Int32Array(stdin); + const place = Atomics.add(n, 0, text.length) + const io = new Uint8ClampedArray(stdin, 4 + place); + io.set(text); + Atomics.notify(n, 0); + }, 10000) + }) diff --git a/example/imports.ts b/example/imports.ts new file mode 100644 index 000000000..b7b86f5bb --- /dev/null +++ b/example/imports.ts @@ -0,0 +1,1076 @@ +import { ZigJS } from "zig-js/src/index.ts"; +import { + WASI_ESUCCESS, + WASI_EBADF, + WASI_EINVAL, + WASI_ENOSYS, + WASI_EPERM, + //WASI_ENOTCAPABLE, + WASI_FILETYPE_UNKNOWN, + WASI_FILETYPE_BLOCK_DEVICE, + WASI_FILETYPE_CHARACTER_DEVICE, + WASI_FILETYPE_DIRECTORY, + WASI_FILETYPE_REGULAR_FILE, + WASI_FILETYPE_SOCKET_STREAM, + WASI_FILETYPE_SYMBOLIC_LINK, + WASI_FILETYPE, + WASI_FDFLAG_APPEND, + WASI_FDFLAG_DSYNC, + WASI_FDFLAG_NONBLOCK, + WASI_FDFLAG_RSYNC, + WASI_FDFLAG_SYNC, + WASI_RIGHT_FD_DATASYNC, + WASI_RIGHT_FD_READ, + WASI_RIGHT_FD_SEEK, + WASI_RIGHT_FD_FDSTAT_SET_FLAGS, + WASI_RIGHT_FD_SYNC, + WASI_RIGHT_FD_TELL, + WASI_RIGHT_FD_WRITE, + WASI_RIGHT_FD_ADVISE, + WASI_RIGHT_FD_ALLOCATE, + WASI_RIGHT_PATH_CREATE_DIRECTORY, + WASI_RIGHT_PATH_CREATE_FILE, + WASI_RIGHT_PATH_LINK_SOURCE, + WASI_RIGHT_PATH_LINK_TARGET, + WASI_RIGHT_PATH_OPEN, + WASI_RIGHT_FD_READDIR, + WASI_RIGHT_PATH_READLINK, + WASI_RIGHT_PATH_RENAME_SOURCE, + WASI_RIGHT_PATH_RENAME_TARGET, + WASI_RIGHT_PATH_FILESTAT_GET, + WASI_RIGHT_PATH_FILESTAT_SET_SIZE, + WASI_RIGHT_PATH_FILESTAT_SET_TIMES, + WASI_RIGHT_FD_FILESTAT_GET, + WASI_RIGHT_FD_FILESTAT_SET_SIZE, + WASI_RIGHT_FD_FILESTAT_SET_TIMES, + WASI_RIGHT_PATH_SYMLINK, + WASI_RIGHT_PATH_REMOVE_DIRECTORY, + WASI_RIGHT_POLL_FD_READWRITE, + WASI_RIGHT_PATH_UNLINK_FILE, + RIGHTS_BLOCK_DEVICE_BASE, + RIGHTS_BLOCK_DEVICE_INHERITING, + RIGHTS_CHARACTER_DEVICE_BASE, + RIGHTS_CHARACTER_DEVICE_INHERITING, + RIGHTS_REGULAR_FILE_BASE, + RIGHTS_REGULAR_FILE_INHERITING, + RIGHTS_DIRECTORY_BASE, + RIGHTS_DIRECTORY_INHERITING, + RIGHTS_SOCKET_BASE, + RIGHTS_SOCKET_INHERITING, + RIGHTS_TTY_BASE, + RIGHTS_TTY_INHERITING, + WASI_CLOCK_MONOTONIC, + WASI_CLOCK_PROCESS_CPUTIME_ID, + WASI_CLOCK_REALTIME, + WASI_CLOCK_THREAD_CPUTIME_ID, + WASI_EVENTTYPE_CLOCK, + WASI_EVENTTYPE_FD_READ, + WASI_EVENTTYPE_FD_WRITE, + WASI_FILESTAT_SET_ATIM, + WASI_FILESTAT_SET_ATIM_NOW, + WASI_FILESTAT_SET_MTIM, + WASI_FILESTAT_SET_MTIM_NOW, + WASI_O_CREAT, + WASI_O_DIRECTORY, + WASI_O_EXCL, + WASI_O_TRUNC, + WASI_PREOPENTYPE_DIR, + WASI_STDIN_FILENO, + WASI_STDOUT_FILENO, + WASI_STDERR_FILENO, + ERROR_MAP, + SIGNAL_MAP, + WASI_WHENCE_CUR, + WASI_WHENCE_END, + WASI_WHENCE_SET, +} from "./wasi"; +const textDecoder = new TextDecoder("utf-8"); +let stdin = new SharedArrayBuffer(1024); +export function setStdin(buf: SharedArrayBuffer) { + stdin = buf; +} +let bytes: null | Uint8ClampedArray = null +function perfNow() { + return performance.now() + performance.timeOrigin; +} +function readStdin() { + const len = new Int32Array(stdin); + if (len[0] == 0) { + Atomics.wait(len, 0, 0, 1000); + } + const length = len[0]; + if (length === 0) { + bytes = null; + return; + } + bytes = new Uint8ClampedArray(stdin, 4, length).slice(); + console.log(textDecoder.decode(bytes)); + Atomics.store(len, 0, 0); + Atomics.notify(len, 0); +} +function sleep(ms: number) { + const buf = new SharedArrayBuffer(4); + const view = new Int32Array(buf); + view[0] = 1; + console.error("sleep", ms); + Atomics.wait(view, 0, 1, ms); + + +} +let wasmModule; +export function setWasmModule(mod) { + wasmModule = mod; +} +let mainThread = true; +export function setMainThread(isMain) { + mainThread = isMain; +} +let gl: WebGL2RenderingContext; +export function setGl(l) { + gl = l; +} + +export const zjs = new ZigJS(); +globalThis.fontCanvas = new OffscreenCanvas(0, 0); +// window.fontContext = () => { +// const ctx = fontCanvas.getContext("2d"); +// ctx.willReadFrequently = true; +// return ctx; +// } +try { + const $webgl = document.getElementById("main-canvas"); + let webgl2Supported = typeof WebGL2RenderingContext !== "undefined"; + + let webglOptions = { + alpha: false, + antialias: true, + depth: 32, + failIfMajorPerformanceCaveat: false, + powerPreference: "default", + premultipliedAlpha: true, + preserveDrawingBuffer: true, + }; + + if (webgl2Supported) { + gl = $webgl.getContext("webgl2", webglOptions); + if (!gl) { + throw new Error("The browser supports WebGL2, but initialization failed."); + } + } +} catch (e) { console.error(e) } + +// OpenGL operates on numeric IDs while WebGL on objects. The following is a +// hack made to allow keeping current API on the native side while resolving IDs +// to objects in JS. Because the values of those IDs don't really matter, there +// is a shared counter. +let id = 1; +const getId = () => { + id += 1; + return id; +}; + +const glShaders = new Map(); +const glPrograms = new Map(); +const glVertexArrays = new Map(); +const glBuffers = new Map(); +const glFrameBuffers = new Map(); +const glTextures = new Map(); +const glUniformLocations = new Map(); + +const glViewport = (x, y, width, height) => { + gl.viewport(x, y, width, height); +}; + +const glClearColor = (r, g, b, a) => { + gl.clearColor(r, g, b, a); +}; + +const glEnable = (value) => { + gl.enable(value); +}; + +const glDisable = (value) => { + gl.disable(value); +}; + +const glDepthFunc = (value) => { + gl.depthFunc(value); +}; + +const glBlendFunc = (sFactor, dFactor) => { + gl.blendFunc(sFactor, dFactor); +}; + +const glClear = (value) => { + gl.clear(value); +}; + +const glGetAttribLocation = (programId, pointer, length) => { + const name = zjs.loadString(pointer, length); + return gl.getAttribLocation(glPrograms.get(programId), name); +}; + +const glGetUniformLocation = (programId, pointer) => { + const str = new Uint8Array(zjs.memory.buffer, pointer); + let i = 0; + while (str[i] !== 0) i++; + const name = textDecoder.decode(str.slice(0, i)); + const value = gl.getUniformLocation(glPrograms.get(programId), name); + const id = getId(); + glUniformLocations.set(id, value); + return id; +}; + +const glUniform4fv = (locationId, x, y, z, w) => { + gl.uniform4fv(glUniformLocations.get(locationId), [x, y, z, w]); +}; + +const glUniform2f = (locationId, x, y) => { + gl.uniform2f(glUniformLocations.get(locationId), x, y); +}; + +const glUniformMatrix4fv = (locationId, length, transpose, pointer) => { + const floats = new Float32Array(zjs.memory.buffer, pointer, length * 16); + gl.uniformMatrix4fv(glUniformLocations.get(locationId), transpose, floats); +}; + +const glUniform1i = (locationId, value) => { + gl.uniform1i(glUniformLocations.get(locationId), value); +}; + +const glUniform1f = (locationId, value) => { + gl.uniform1f(glUniformLocations.get(locationId), value); +}; + +const glCreateBuffer = () => { + const id = getId(); + glBuffers.set(id, gl.createBuffer()); + return id; +}; + +const glGenBuffers = (number, pointer) => { + const buffers = new Uint32Array(zjs.memory.buffer, pointer, number); + for (let n = 0; n < number; n++) { + const b = glCreateBuffer(); + buffers[n] = b; + } +}; + +const glAttachShader = (program, shader) => { + gl.attachShader(glPrograms.get(program), glShaders.get(shader)); +}; + +const glDetachShader = (program, shader) => { + gl.detachShader(glPrograms.get(program), glShaders.get(shader)); +}; + +const glDeleteProgram = (id) => { + gl.deleteProgram(glPrograms.get(id)); + glPrograms.delete(id); +}; + +const glDeleteBuffer = (id) => { + gl.deleteBuffer(glBuffers.get(id)); + glBuffers.delete(id); +}; + +const glDeleteBuffers = (number, pointer) => { + const buffers = new Uint32Array(zjs.memory.buffer, pointer, number); + for (let n = 0; n < number; n++) { + gl.deleteBuffer(glBuffers.get(buffers[n])); + glBuffers.delete(buffers[n]); + } +}; + +const glDeleteShader = (id) => { + console.error("shader deleted"); + gl.deleteShader(glShaders.get(id)); + glShaders.delete(id); +}; + +const glCreateShader = (type) => { + const shader = gl.createShader(type); + const id = getId(); + glShaders.set(id, shader); + return id; +}; + +const glCompileShader = (id) => { + gl.compileShader(glShaders.get(id)); +}; + +// This differs from OpenGL version due to problems with reading strings till +// null termination. +const glShaderSource = (shader, amount, pointer) => { + const addr = new Uint32Array(zjs.memory.buffer, pointer)[0]; + const str = new Uint8Array(zjs.memory.buffer, addr); + let i = 0; + while (str[i] !== 0) i++; + const source = textDecoder.decode(str.slice(0, i)); + gl.shaderSource(glShaders.get(shader), source); +}; + +const glCreateProgram = () => { + const id = getId(); + const program = gl.createProgram(); + glPrograms.set(id, program); + return id; +}; + +const glGetShaderiv = (id, parameter, ptr) => { + const ret = gl.getShaderParameter(glShaders.get(id), parameter); + const data = new Int32Array(zjs.memory.buffer, ptr, 1); + data[0] = ret; +}; + +const glGetProgramiv = (id, parameter, ptr) => { + const ret = gl.getProgramParameter(glPrograms.get(id), parameter); + const data = new Int32Array(zjs.memory.buffer, ptr, 1); + data[0] = ret; +}; + +const glGetShaderInfoLog = (id, length, lengthPointer, messagePointer) => { + const message = new Uint8Array(zjs.memory.buffer, messagePointer, length); + const info = gl.getShaderInfoLog(glShaders.get(id)); + + for (let i = 0; i < info.length; i++) { + message[i] = info.charCodeAt(i); + } +}; + +const glGetProgramInfoLog = (id, length, lengthPointer, messagePointer) => { + const message = new Uint8Array(zjs.memory.buffer, messagePointer, length); + const info = gl.getProgramInfoLog(glPrograms.get(id)); + + for (let i = 0; i < info.length; i++) { + message[i] = info.charCodeAt(i); + } +}; + +const glLinkProgram = (id) => { + gl.linkProgram(glPrograms.get(id)); +}; + +const glBindBuffer = (type, bufferId) => { + gl.bindBuffer(type, glBuffers.get(bufferId)); +}; + +const glBufferData = (type, count, pointer, drawType) => { + // The Float32Array multiplies by size of float which is 4, and the call to + // this method, due to OpenGL compatibility, also receives already + // pre-multiplied value. + gl.bufferData(type, zjs.memory.buffer.slice(pointer, pointer + count), drawType); +}; + +const glBufferSubData = (target, offset, size, data) => { + // The Float32Array multiplies by size of float which is 4, and the call to + // this method, due to OpenGL compatibility, also receives already + // pre-multiplied value. + gl.bufferSubData(target, offset, zjs.memory.buffer.slice(data, data + size)); +}; + +const glUseProgram = (programId) => { + gl.useProgram(glPrograms.get(programId)); +}; + +const glEnableVertexAttribArray = (value) => { + gl.enableVertexAttribArray(value); +}; + +const glVertexAttribPointer = ( + attribLocation, + size, + type, + normalize, + stride, + offset +) => { + gl.vertexAttribPointer(attribLocation, size, type, normalize, stride, offset); +}; + +const glVertexAttribIPointer = ( + attribLocation, + size, + type, + stride, + offset +) => { + gl.vertexAttribIPointer(attribLocation, size, type, stride, offset); +}; + +const glVertexAttribDivisor = (index, divisor) => { + gl.vertexAttribDivisor(index, divisor); +} + +const glGenFramebuffers = (n, ptr) => { + const buffers = new Uint32Array(zjs.memory.buffer, ptr, n); + for (let i = 0; i < n; i++) { + const id = getId(); + const b = gl.createFramebuffer(); + glFrameBuffers.set(id, b); + buffers[i] = id; + } +} + +const glDeleteFramebuffers = (n, ptr) => { + const buffers = new Uint32Array(zjs.memory.buffer, ptr, n); + for (let i = 0; i < n; i++) { + const b = glFrameBuffers.get(buffers[i]); + gl.deleteFramebuffer(b); + } +} + +const glBindFramebuffer = (target, fb) => { + const b = glFrameBuffers.get(fb); + gl.bindFramebuffer(target, b); +} + +const glTexSubImage2D = (target, level, xoffset, yoffset, width, height, format, type, pixels) => { + let size = 1; + if (format === gl.RGBA) { + size = 4; + } else if (format === gl.RED) { + size = 1; + } else if (format == 32993) { + size = 4; + format = gl.RGBA + } else { + throw new Error("Add pixel count for this format."); + } + + const data = new Uint8Array(zjs.memory.buffer, pixels, width * height * size); + gl.texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, data) +} +const glGetIntegerv = (pname, ptr) => { + const data = new Uint32Array(zjs.memory?.buffer, ptr, 1); + data[0] = gl.getParameter(pname); +} + +const glUniform4f = (locationId, x, y, z, w) => { + gl.uniform4f(glUniformLocations.get(locationId), x, y, z, w); +}; +const glDrawElementsInstanced = (mode, count, type, indices, instancecount) => { + gl.drawElementsInstanced(mode, count, type, indices, instancecount); +}; +const glBindBufferBase = (target, index, buffer) => { + gl.bindBufferBase(target, index, glBuffers.get(buffer)) +} +const glDrawArrays = (type, offset, count) => { + gl.drawArrays(type, offset, count); +}; + +const glCreateTexture = () => { + const id = getId(); + glTextures.set(id, gl.createTexture()); + return id; +}; + +const glGenTextures = (number, pointer) => { + const textures = new Uint32Array(zjs.memory.buffer, pointer, number); + for (let n = 0; n < number; n++) { + const texture = glCreateTexture(); + textures[n] = texture; + } +}; + +const glDeleteTextures = (number, pointer) => { + const textures = new Uint32Array(zjs.memory.buffer, pointer, number); + for (let n = 0; n < number; n++) { + gl.deleteTexture(glBuffers[n]); + glTextures.delete(textures[n]); + } +}; + +const glDeleteTexture = (id) => { + gl.deleteTexture(glTextures.get(id)); + glTextures.delete(id); +}; + +const glBindTexture = (target, id) => { + return gl.bindTexture(target, glTextures.get(id)); +}; + +const glTexImage2D = ( + target, + level, + internalFormat, + width, + height, + border, + format, + type, + pointer +) => { + let size = 1; + if (format === gl.RGBA) { + size = 4; + } else if (format == gl.RED) { + size = 1; + internalFormat = gl.R8 + } else if (format == 32993) { + size = 4; + format = gl.RGBA + } else { + throw new Error("Add pixel count for this format."); + } + + const data = new Uint8Array(zjs.memory.buffer, pointer, width * height * size); + + gl.texImage2D( + target, + level, + internalFormat, + width, + height, + border, + format, + type, + data + ); +}; + +const glTexParameteri = (target, name, parameter) => { + gl.texParameteri(target, name, parameter); +}; + +const glActiveTexture = (target) => { + return gl.activeTexture(target); +}; + +const glGenerateMipmap = (value) => { + gl.generateMipmap(value); +}; + +const glCreateVertexArray = () => { + const id = getId(); + glVertexArrays.set(id, gl.createVertexArray()); + return id; +}; + +const glGenVertexArrays = (number, pointer) => { + const vaos = new Uint32Array(zjs.memory.buffer, pointer, number); + for (let n = 0; n < number; n++) { + const b = glCreateVertexArray(); + vaos[n] = b; + } +}; + +const glDeleteVertexArrays = (number, pointer) => { + const vaos = new Uint32Array(zjs.memory.buffer, pointer, number); + for (let n = 0; n < number; n++) { + glVertexArrays.delete(vaos[n]); + } +}; + +const glBindVertexArray = (id) => gl.bindVertexArray(glVertexArrays.get(id)); + +const glPixelStorei = (type, alignment) => gl.pixelStorei(type, alignment); + +const glGetError = () => { + return gl.getError(); +} + +const webgl = { + glViewport, + glClearColor, + glEnable, + glDisable, + glDepthFunc, + glBlendFunc, + glClear, + glGetAttribLocation, + glGetUniformLocation, + glUniform4fv, + glUniform2f, + glUniform1i, + glUniform1f, + glUniformMatrix4fv, + glCreateVertexArray, + glGenVertexArrays, + glDeleteVertexArrays, + glBindVertexArray, + glCreateBuffer, + glGenBuffers, + glDeleteBuffers, + glDeleteBuffer, + glBindBuffer, + glBufferData, + glBufferSubData, + glPixelStorei, + glAttachShader, + glDetachShader, + glDeleteShader, + glCreateShader, + glCompileShader, + glShaderSource, + glCreateProgram, + glGetShaderInfoLog, + glGetProgramInfoLog, + glLinkProgram, + glUseProgram, + glDeleteProgram, + glEnableVertexAttribArray, + glVertexAttribPointer, + glVertexAttribIPointer, + glDrawArrays, + glCreateTexture, + glGenTextures, + glDeleteTextures, + glDeleteTexture, + glBindTexture, + glTexImage2D, + glTexParameteri, + glActiveTexture, + glGenerateMipmap, + glGetError, + glGetShaderiv, + glGetProgramiv, + glVertexAttribDivisor, + glGenFramebuffers, + glDeleteFramebuffers, + glBindFramebuffer, + glTexSubImage2D, + glGetIntegerv, + glUniform4f, + glDrawElementsInstanced, + glBindBufferBase, +} +const nsToMs = (ns: number | bigint) => { + if (typeof ns === "number") { + ns = Math.trunc(ns); + } + const nsInt = BigInt(ns); + return Number(nsInt / BigInt(1000000)); +}; +const msToNs = (ms: number) => { + const msInt = Math.trunc(ms); + const decimal = BigInt(Math.round((ms - msInt) * 1000000)); + const ns = BigInt(msInt) * BigInt(1000000); + return ns + decimal; +}; +const CPUTIME_START = msToNs(perfNow()); +const now = (clockId?: number) => { + switch (clockId) { + case WASI_CLOCK_MONOTONIC: + return msToNs(perfNow()); + case WASI_CLOCK_REALTIME: + return msToNs(Date.now()); + case WASI_CLOCK_PROCESS_CPUTIME_ID: + case WASI_CLOCK_THREAD_CPUTIME_ID: // TODO -- this assumes 1 thread + return msToNs(perfNow()) - CPUTIME_START; + default: + return null; + } +}; +let files: { polling: SharedArrayBuffer, nextFd: SharedArrayBuffer, has: SharedArrayBuffer }; +export function setFiles(file) { + files = file; +} +const fdStart = 4; + +export const importObject = { + module: {}, + env: { + memory: new WebAssembly.Memory({ + initial: 512, + maximum: 65536, + shared: true, + }), + ...webgl, + log: (ptr: number, len: number) => { + const arr = new Uint8ClampedArray(zjs.memory.buffer, ptr, len); + const data = arr.slice(); + const str = textDecoder.decode(data); + console.error(str); + }, + eventFd() { + const next = new Int32Array(files.nextFd); + return Atomics.add(next, 0, 1); + + }, + fork: (...params) => { + console.error("fork", params); + }, + execve: (...params) => { + console.error("execve", params); + }, + pipe: (...params) => { + console.error("pipe", params); + }, + realpath: (...params) => { + console.error("realpath", params); + }, + pthread_mutex_lock: (...params) => { + console.error("pthread_mutex_lock", params); + }, + pthread_cond_wait: (...params) => { + console.error("pthread_cond_wait", params); + }, + pthread_mutex_unlock: (...params) => { + console.error("pthread_mutex_unlock", params); + }, + __cxa_allocate_exception: (...params) => { + console.error("__cxa_allocate_exception", params); + }, + pthread_cond_broadcast: (...params) => { + console.error("pthread_cond_broadcast", params); + }, + __cxa_throw: (...params) => { + console.error("__cxa_throw", params); + }, + + }, + wasi_snapshot_preview1: { + fd_write: (fd, iovs, iovs_len, nwritten_ptr) => { + if (fd >= fdStart) { + const memory = new DataView(zjs.memory.buffer); + let nwritten = 0; + for (let offset = iovs; offset < iovs + iovs_len * 8; offset += 8) { + const iov_len = memory.getUint32(offset + 4, true); + nwritten += iov_len; + } + const has = new Int32Array(files.has); + Atomics.store(has, fd - fdStart, 1); + Atomics.notify(has, fd - fdStart); + if (!mainThread) Atomics.wait(has, fd-fdStart, 1, 1000); + console.error("notify", fd); + memory.setUint32(nwritten_ptr, nwritten, true); + + } else { + const memory = new DataView(zjs.memory.buffer); + let buf = ""; + let nwritten = 0; + for (let offset = iovs; offset < iovs + iovs_len * 8; offset += 8) { + const iov_base = memory.getUint32(offset, true); + const iov_len = memory.getUint32(offset + 4, true); + buf += textDecoder.decode(new Uint8ClampedArray(memory.buffer.slice(iov_base, iov_base + iov_len)).slice()); + nwritten += iov_len; + } + memory.setUint32(nwritten_ptr, nwritten, true); + console.error(buf); + } + }, + fd_close: (...params) => { + console.error("fd_close", params); + }, + fd_fdstat_get: (...params) => { + console.error("fd_fdstat_get", params); + }, + fd_fdstat_set_flags: (...params) => { + console.error("fd_fdstat_set_flags", params); + }, + fd_filestat_get: (...params) => { + console.error("fd_filestat_get", params); + }, + fd_pread: (...params) => { + console.error("fd_pread", params); + }, + fd_prestat_get: (...params) => { + console.error("fd_prestat_get", params); + }, + fd_prestat_dir_name: (...params) => { + console.error("fd_prestat_dir_name", params); + }, + fd_pwrite: (...params) => { + console.error("fd_pwrite", params); + }, + fd_read(fd, iovs, iovsLen, nreadPtr) { + if (fd >= fdStart) { + const memory = new DataView(zjs.memory.buffer); + let nwritten = 0; + for (let offset = iovs; offset < iovs + iovsLen * 8; offset += 8) { + const iov_base = memory.getUint32(offset, true); + const iov_len = memory.getUint32(offset + 4, true); + // new Uint8ClampedArray(memory.buffer.slice(iov_base, iov_base + iov_len)).fill(1); + nwritten += iov_len; + memory.setUint32(nreadPtr, nwritten, true); + } + const has = new Int32Array(files.has); + Atomics.store(has, fd - fdStart, 0) + Atomics.notify(has, fd-fdStart); + console.error("read", fd); + } else { + const memory = new DataView(zjs.memory.buffer); + let nwritten = 0; + for (let offset = iovs; offset < iovs + iovsLen * 8; offset += 8) { + if (bytes == null) readStdin(); + if (bytes == null) break; + const iov_base = memory.getUint32(offset, true); + const iov_len = memory.getUint32(offset + 4, true); + const read = Math.min(iov_len, bytes.length); + const io = new Uint8ClampedArray(zjs.memory.buffer, iov_base, iov_len); + io.set(bytes.slice(0, read)); + bytes = bytes.slice(read); + if (bytes.length === 0) bytes = null; + nwritten += read; + if (read !== iov_len) break; + } + + memory.setUint32(nreadPtr, nwritten, true); + } + }, + fd_seek: (...params) => { + console.error("fd_seek", params); + }, + path_filestat_get: (...params) => { + console.error("path_filestat_get", params); + }, + path_open: (...params) => { + console.error("path_open", params); + }, + path_unlink_file: (...params) => { + console.error("path_unlink_file", params); + }, + poll_oneoff( + sin: number, + sout: number, + nsubscriptions: number, + neventsPtr: number + ) { + + let nevents = 0; + let name = ""; + + // May have to wait this long (this gets computed below in the WASI_EVENTTYPE_CLOCK case). + + let waitTimeNs = BigInt(0); + + let fd = -1; + let fd_type: "read" | "write" = "read"; + let fd_timeout_ms = 0; + + const startNs = BigInt(msToNs(perfNow())); + let view = new DataView(zjs.memory.buffer); + let last_sin = sin; + for (let i = 0; i < nsubscriptions; i += 1) { + const userdata = view.getBigUint64(sin, true); + sin += 8; + const type = view.getUint8(sin); + sin += 1; + sin += 7; // padding + if (type == WASI_EVENTTYPE_CLOCK) { + name = "poll_oneoff (type=WASI_EVENTTYPE_CLOCK): "; + } else if (type == WASI_EVENTTYPE_FD_READ) { + name = "poll_oneoff (type=WASI_EVENTTYPE_FD_READ): "; + } else { + name = "poll_oneoff (type=WASI_EVENTTYPE_FD_WRITE): "; + } + console.log(name); + switch (type) { + case WASI_EVENTTYPE_CLOCK: { + // see packages/zig/dist/lib/libc/include/wasm-wasi-musl/wasi/api.h + // for exactly how these values are encoded. I carefully looked + // at that header and **this is definitely right**. Same with the fd + // in the other case below. + const clockid = view.getUint32(sin, true); + sin += 4; + sin += 4; // padding + let timeout = view.getBigUint64(sin, true); + console.log(timeout); + sin += 8; + // const precision = view.getBigUint64(sin, true); + sin += 8; + const subclockflags = view.getUint16(sin, true); + sin += 2; + sin += 6; // padding + + const absolute = subclockflags === 1; + console.log(name, { clockid, timeout, absolute }); + if (!absolute) { + fd_timeout_ms = Number(timeout / BigInt(1000000)); + } + + let e = WASI_ESUCCESS; + const t = now(clockid); + // logToFile(t, clockid, timeout, subclockflags, absolute); + if (t == null) { + e = WASI_EINVAL; + } else { + const end = absolute ? timeout : t + timeout; + const waitNs = end - t; + if (waitNs > waitTimeNs) { + waitTimeNs = waitNs; + } + } + + view = new DataView(zjs.memory.buffer); + view.setBigUint64(sout, userdata, true); + sout += 8; + view.setUint16(sout, e, true); // error + sout += 8; // pad offset 2 + view.setUint8(sout, WASI_EVENTTYPE_CLOCK); + sout += 8; // pad offset 1 + sout += 8; // padding to 8 + + nevents += 1; + + break; + } + case WASI_EVENTTYPE_FD_READ: + case WASI_EVENTTYPE_FD_WRITE: { + /* + Look at + lib/libc/wasi/libc-bottom-half/cloudlibc/src/libc/sys/select/pselect.c + to see how poll_oneoff is actually used by wasi to implement pselect. + It's also used in + lib/libc/wasi/libc-bottom-half/cloudlibc/src/libc/poll/poll.c + + "If none of the selected descriptors are ready for the + requested operation, the pselect() or select() function shall + block until at least one of the requested operations becomes + ready, until the timeout occurs, or until interrupted by a signal." + Thus what is supposed to happen below is supposed + to block until the fd is ready to read from or write + to, etc. + + For now at least if reading from stdin then we block for a short amount + of time if getStdin defined; otherwise, we at least *pause* for a moment + (to avoid cpu burn) if this.sleep is available. + */ + fd = view.getUint32(sin, true); + fd_type = type == WASI_EVENTTYPE_FD_READ ? "read" : "write"; + sin += 4; + console.log(name, "fd =", fd); + sin += 28; + let notify = true; + if (fd >= fdStart) { + const has = new Int32Array(files.has); + Atomics.wait(has, fd - fdStart, 0, 500); + if (has[fd - fdStart] == 0) { + console.warn("not notify"); + notify = false; + } else { + console.warn("notify"); + notify = true; + } + } + + if (notify) { + view = new DataView(zjs.memory.buffer); + view.setBigUint64(sout, userdata, true); + sout += 8; + view.setUint16(sout, WASI_ENOSYS, true); // error + sout += 8; // pad offset 2 + view.setUint8(sout, type); + sout += 8; // pad offset 3 + sout += 8; // padding to 8 + + nevents += 1; + } + /* + TODO: for now for stdin we are just doing a dumb hack. + + We just do something really naive, which is "pause for a little while". + It seems to work for every application I have so far, from Python to + to ncurses, etc. This also makes it easy to have non-blocking sleep + in node.js at the terminal without a worker thread, which is very nice! + + Before I had it block here via getStdin when available, but that does not work + in general; in particular, it breaks ncurses completely. In + ncurses/tty/tty_update.c + the following call is assumed not to block, and if it does, then ncurses + interaction becomes totally broken: + + select(SP_PARM->_checkfd + 1, &fdset, NULL, NULL, &ktimeout) + + */ + // if (fd == WASI_STDIN_FILENO && WASI_EVENTTYPE_FD_READ == type) { + // sleep(5000); + // } + + break; + } + default: + return WASI_EINVAL; + } + + // Consistency check that we consumed exactly the right amount + // of the __wasi_subscription_t. See zig/lib/libc/include/wasm-wasi-musl/wasi/api.h + if (sin - last_sin != 48) { + console.warn("*** BUG in wasi-js in poll_oneoff ", { + i, + sin, + last_sin, + diff: sin - last_sin, + }); + } + last_sin = sin; + } + + view = new DataView(zjs.memory.buffer); + view.setUint32(neventsPtr, nevents, true); + + // if (nevents == 2 && fd >= 0) { + // const r = this.wasiImport.sock_pollSocket(fd, fd_type, fd_timeout_ms); + // if (r != WASI_ENOSYS) { + // // special implementation from outside + // return r; + // } + // // fall back to below + // } + + // Account for the time it took to do everything above, which + // can be arbitrarily long: + if (waitTimeNs > 0) { + waitTimeNs -= msToNs(perfNow()) - startNs; + // logToFile("waitTimeNs", waitTimeNs); + if (waitTimeNs >= 1000000) { + const ms = nsToMs(waitTimeNs); + sleep(ms); + } + } + + return WASI_ESUCCESS; + }, + proc_exit: (...params) => { + console.error("proc_exit", params); + }, + sock_shutdown: (...params) => { + console.error("sock_shutdown", params); + }, + sock_accept: (...params) => { + console.error("sock_accept", params); + }, + sock_recv: (...params) => { + console.error("sock_recv", params); + }, + sock_send: (...params) => { + console.error("sock_send", params); + }, + random_get: (ptr, len) => { + const memory = new Uint8Array(zjs.memory.buffer, ptr, len).slice(); + crypto.getRandomValues(memory); + }, + environ_get: (...params) => { + console.error("environ_get", params); + }, + clock_time_get: (_clock, _precision, ptr) => { + const data = new DataView(zjs.memory.buffer); + data.setBigUint64(ptr, msToNs(perfNow()), true) + }, + environ_sizes_get: (...params) => { + console.error("environ_sizes_get", params); + }, + }, + wasi: { + "thread-spawn": (instance) => { + if (mainThread) { + spawnWorker(instance) + } else { + postMessage([instance]) + } + + } + }, + + ...zjs.importObject(), +}; +let pid = 100; +function spawnWorker(instance) { + const worker = new Worker(new URL("worker.ts", import.meta.url), { type: "module" }); + worker.postMessage([zjs.memory, instance, stdin, wasmModule, files, pid++]); + worker.onmessage = (event) => { + const [instance] = event.data; + spawnWorker(instance); + } +} diff --git a/example/index.html b/example/index.html index 2e66f92d1..e74e55717 100644 --- a/example/index.html +++ b/example/index.html @@ -7,6 +7,8 @@
Open your console, we are just debugging here.
+The current grayscale font atlas is rendered below.
The current color font atlas is rendered below.
diff --git a/example/old.ts b/example/old.ts new file mode 100644 index 000000000..d1976753b --- /dev/null +++ b/example/old.ts @@ -0,0 +1,158 @@ +import { zjs } from "./imports"; + +export function old(results) { + const { + atlas_clear, + atlas_debug_canvas, + atlas_free, + atlas_grow, + atlas_new, + atlas_reserve, + atlas_set, + config_finalize, + config_free, + config_load_string, + config_new, + deferred_face_free, + deferred_face_load, + deferred_face_new, + face_debug_canvas, + face_free, + face_new, + face_render_glyph, + free, + malloc, + shaper_free, + shaper_new, + shaper_test, + collection_new, + collection_add_deferred_face, + shared_grid_new, + shared_grid_atlas_grayscale, + shared_grid_atlas_color, + shared_grid_index_for_codepoint, + shared_grid_render_glyph, + run, + } = results.instance.exports; + + + // Helpers + const makeStr = (str) => { + const utf8 = new TextEncoder().encode(str); + const ptr = malloc(utf8.byteLength); + new Uint8Array(zjs.memory.buffer, ptr).set(utf8); + return { ptr: ptr, len: utf8.byteLength }; + }; + // Create our config + const config_str = makeStr("font-family = monospace"); + + const config = config_new(); + config_load_string(config, config_str); + config_finalize(config); + free(config_str.ptr); + // Create our atlas + // const atlas = atlas_new(512, 0 /* grayscale */); + + // Create some memory for our string + const font_name = makeStr("monospace"); + + // Initialize our deferred face + // const df = deferred_face_new(font_ptr, font.byteLength, 0 /* text */); + //deferred_face_load(df, 72 /* size */); + //const face = deferred_face_face(df); + + // Initialize our font face + //const face = face_new(font_ptr, font.byteLength, 72 /* size in px */); + //free(font_ptr); + + // Create our group + const collection = collection_new(32); + collection_add_deferred_face( + collection, + 0 /* regular */, + deferred_face_new(font_name.ptr, font_name.len, 0 /* text */), + ); + collection_add_deferred_face( + collection, + 0 /* regular */, + deferred_face_new(font_name.ptr, font_name.len, 1 /* emoji */), + ); + const grid = shared_grid_new(collection); + + // Initialize our sprite font, without this we just use the browser. + // group_init_sprite_face(group); + + // // Create our group cache + // const group_cache = group_cache_new(group); + + // Render a glyph + for (let i = 33; i <= 126; i++) { + const font_idx = shared_grid_index_for_codepoint(grid, i, 0, -1); + shared_grid_render_glyph(grid, font_idx, i, 0); + //face_render_glyph(face, atlas, i); + } + // + const emoji = ["π", "π", "π", "π±", "πΏ", "π", "π", "π", "π‘", "π"]; + for (let i = 0; i < emoji.length; i++) { + const cp = emoji[i].codePointAt(0); + const font_idx = shared_grid_index_for_codepoint(grid, cp, 0, -1 /* best choice */); + shared_grid_render_glyph(grid, font_idx, cp, 0); + } + + for (let i = 0x2500; i <= 0x257f; i++) { + const font_idx = shared_grid_index_for_codepoint(grid, i, 0, -1); + shared_grid_render_glyph(grid, font_idx, i, 0); + } + for (let i = 0x2580; i <= 0x259f; i++) { + const font_idx = shared_grid_index_for_codepoint(grid, i, 0, -1); + shared_grid_render_glyph(grid, font_idx, i, 0); + } + for (let i = 0x2800; i <= 0x28ff; i++) { + const font_idx = shared_grid_index_for_codepoint(grid, i, 0, -1); + shared_grid_render_glyph(grid, font_idx, i, 0); + } + for (let i = 0x1fb00; i <= 0x1fb3b; i++) { + const font_idx = shared_grid_index_for_codepoint(grid, i, 0, -1); + shared_grid_render_glyph(grid, font_idx, i, 0); + } + for (let i = 0x1fb3c; i <= 0x1fb6b; i++) { + const font_idx = shared_grid_index_for_codepoint(grid, i, 0, -1); + shared_grid_render_glyph(grid, font_idx, i, 0); + } + + //face_render_glyph(face, atlas, "ζ©".codePointAt(0)); + //face_render_glyph(face, atlas, "p".codePointAt(0)); + + // Debug our canvas + //face_debug_canvas(face); + + // Let's try shaping + const shaper = shaper_new(120); + //const input = makeStr("helloπ"); + const input = makeStr("M_yhelloaaaaaaaaa\nπ\nππ½\nM_ghostty"); + shaper_test(shaper, grid, input.ptr, input.len); + + const cp = 1114112; + const font_idx = shared_grid_index_for_codepoint( + grid, + cp, + 0, + -1 /* best choice */, + ); + shared_grid_render_glyph(grid, font_idx, cp, -1); + + // Debug our atlas canvas + { + const atlas = shared_grid_atlas_grayscale(grid); + const id = atlas_debug_canvas(atlas); + document.getElementById("atlas-canvas").append(zjs.deleteValue(id)); + } + + { + const atlas = shared_grid_atlas_color(grid); + const id = atlas_debug_canvas(atlas); + document.getElementById("atlas-color-canvas").append(zjs.deleteValue(id)); + } + + //face_free(face); +} diff --git a/example/package-lock.json b/example/package-lock.json index 3cb4de6f0..bfeb345be 100644 --- a/example/package-lock.json +++ b/example/package-lock.json @@ -9,31 +9,27 @@ "version": "0.1.0", "license": "MIT", "dependencies": { - "zig-js": "file:../vendor/zig-js/js" + "glslog": "^0.0.10", + "zig-js": "https://gitpkg.vercel.app/mitchellh/zig-js/js?main" }, "devDependencies": { "@parcel/transformer-inline-string": "^2.8.0", + "buffer": "^5.7.1", + "crypto-browserify": "^3.12.1", + "events": "^3.3.0", + "os-browserify": "^0.3.0", "parcel": "^2.8.0", - "typescript": "^4.9.3" + "path-browserify": "^1.0.1", + "process": "^0.11.10", + "stream-browserify": "^3.0.0", + "string_decoder": "^1.3.0", + "typescript": "^4.9.3", + "vm-browserify": "^1.1.2" } }, "../js": { "extraneous": true }, - "../vendor/zig-js/js": { - "name": "zig-js-glue", - "version": "0.1.2", - "license": "MIT", - "devDependencies": { - "@parcel/packager-ts": "^2.8.0", - "@parcel/transformer-typescript-types": "^2.8.0", - "@types/jest": "^29.2.3", - "jest": "^29.3.1", - "parcel": "^2.8.0", - "ts-jest": "^29.0.3", - "typescript": "^4.9.3" - } - }, "node_modules/@babel/code-frame": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", @@ -1501,6 +1497,25 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/asn1.js": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/asn1.js/node_modules/bn.js": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", + "dev": true, + "license": "MIT" + }, "node_modules/base-x": { "version": "3.0.9", "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", @@ -1510,12 +1525,124 @@ "safe-buffer": "^5.0.1" } }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", + "dev": true, + "license": "MIT" + }, "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", "dev": true }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", + "dev": true, + "license": "MIT" + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "node_modules/browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/browserify-rsa": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.1.tgz", + "integrity": "sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^5.2.1", + "randombytes": "^2.1.0", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/browserify-sign": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.3.tgz", + "integrity": "sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw==", + "dev": true, + "license": "ISC", + "dependencies": { + "bn.js": "^5.2.1", + "browserify-rsa": "^4.1.0", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.5", + "hash-base": "~3.0", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.7", + "readable-stream": "^2.3.8", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.12" + } + }, "node_modules/browserslist": { "version": "4.21.4", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", @@ -1544,12 +1671,44 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", + "dev": true, + "license": "MIT" + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -1600,6 +1759,20 @@ "node": ">=6.0" } }, + "node_modules/cipher-base": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.5.tgz", + "integrity": "sha512-xq7ICKB4TMHUx7Tz1L9O2SGKOhYMOTR32oir45Bq28/AQTpHogKgHcoYFSdRbMtddl+ozNXfXY9jWcgYKmde0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/clone": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", @@ -1636,6 +1809,13 @@ "node": ">= 10" } }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true, + "license": "MIT" + }, "node_modules/cosmiconfig": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", @@ -1652,6 +1832,80 @@ "node": ">=10" } }, + "node_modules/create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + } + }, + "node_modules/create-ecdh/node_modules/bn.js": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", + "dev": true, + "license": "MIT" + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/crypto-browserify": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.1.tgz", + "integrity": "sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserify-cipher": "^1.0.1", + "browserify-sign": "^4.2.3", + "create-ecdh": "^4.0.4", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "diffie-hellman": "^5.0.3", + "hash-base": "~3.0.4", + "inherits": "^2.0.4", + "pbkdf2": "^3.1.2", + "public-encrypt": "^4.0.3", + "randombytes": "^2.1.0", + "randomfill": "^1.0.4" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/css-select": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", @@ -1705,6 +1959,17 @@ "node": ">=8.0.0" } }, + "node_modules/des.js": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", + "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, "node_modules/detect-libc": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", @@ -1717,6 +1982,25 @@ "node": ">=0.10" } }, + "node_modules/diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "node_modules/diffie-hellman/node_modules/bn.js": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", + "dev": true, + "license": "MIT" + }, "node_modules/dom-serializer": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", @@ -1802,6 +2086,29 @@ "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==", "dev": true }, + "node_modules/elliptic": { + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", + "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", + "dev": true, + "license": "MIT" + }, "node_modules/entities": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", @@ -1841,6 +2148,27 @@ "node": ">=0.8.0" } }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, "node_modules/get-port": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/get-port/-/get-port-4.2.0.tgz", @@ -1865,6 +2193,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/glslog": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/glslog/-/glslog-0.0.10.tgz", + "integrity": "sha512-RJn15AQAH0qYvGZNtRdAN4KCsGNUC6ArIn5EJIbWMo96vjf+ZEHk7jStNa12mWNQIPZ6S7kPKsK/pBqt9GDChA==", + "license": "MIT" + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -1874,6 +2208,43 @@ "node": ">=8" } }, + "node_modules/hash-base": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", + "integrity": "sha512-EeeoJKjTyt868liAlVmcv2ZsUfGHlE3Q+BICOXcZiwN3osr5Q/zFGYmTJpoIzuaSTAwndFy+GqhEwlU4L3j4Ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, "node_modules/htmlnano": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/htmlnano/-/htmlnano-2.0.3.tgz", @@ -1940,6 +2311,27 @@ "entities": "^3.0.1" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -1956,6 +2348,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -1968,6 +2367,13 @@ "integrity": "sha512-6BEnpVn1rcf3ngfmViLM6vjUjGErbdrL4rwlv+u1NO1XO8kqT4YGL8+19Q+Z/bas8tY90BTWMk2+fW1g6hQjbA==", "dev": true }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -2212,12 +2618,59 @@ "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==", "dev": true }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, "node_modules/mdn-data": { "version": "2.0.14", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", "dev": true }, + "node_modules/miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "bin": { + "miller-rabin": "bin/miller-rabin" + } + }, + "node_modules/miller-rabin/node_modules/bn.js": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", + "dev": true, + "license": "MIT" + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true, + "license": "ISC" + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "dev": true, + "license": "MIT" + }, "node_modules/msgpackr": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.8.1.tgz", @@ -2307,6 +2760,13 @@ "integrity": "sha512-EHQ/jk4/a9hLupIKxTfUsQRej1Yd/0QLQs3vGvIqg5ZtCYSzNhkzHoZc7Zf4e4kUlDaC3Uw8Q/1opOLNN2OKRQ==", "dev": true }, + "node_modules/os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==", + "dev": true, + "license": "MIT" + }, "node_modules/parcel": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/parcel/-/parcel-2.8.0.tgz", @@ -2351,6 +2811,24 @@ "node": ">=6" } }, + "node_modules/parse-asn1": { + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.7.tgz", + "integrity": "sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg==", + "dev": true, + "license": "ISC", + "dependencies": { + "asn1.js": "^4.10.1", + "browserify-aes": "^1.2.0", + "evp_bytestokey": "^1.0.3", + "hash-base": "~3.0", + "pbkdf2": "^3.1.2", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", @@ -2369,6 +2847,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true, + "license": "MIT" + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -2378,6 +2863,23 @@ "node": ">=8" } }, + "node_modules/pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + }, + "engines": { + "node": ">=0.12" + } + }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -2439,6 +2941,66 @@ "node": ">=12" } }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/public-encrypt/node_modules/bn.js": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", + "dev": true, + "license": "MIT" + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, "node_modules/react-error-overlay": { "version": "6.0.9", "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.9.tgz", @@ -2454,6 +3016,39 @@ "node": ">=0.10.0" } }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/readable-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/regenerator-runtime": { "version": "0.13.11", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", @@ -2469,6 +3064,17 @@ "node": ">=4" } }, + "node_modules/ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -2498,6 +3104,20 @@ "semver": "bin/semver" } }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "license": "(MIT AND BSD-3-Clause)", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -2524,6 +3144,42 @@ "deprecated": "Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility", "dev": true }, + "node_modules/stream-browserify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", + "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" + } + }, + "node_modules/stream-browserify/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -2656,6 +3312,13 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, "node_modules/utility-types": { "version": "3.10.0", "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.10.0.tgz", @@ -2671,6 +3334,13 @@ "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", "dev": true }, + "node_modules/vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", + "dev": true, + "license": "MIT" + }, "node_modules/weak-lru-cache": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz", @@ -2693,8 +3363,11 @@ } }, "node_modules/zig-js": { - "resolved": "../vendor/zig-js/js", - "link": true + "name": "zig-js-glue", + "version": "0.1.3", + "resolved": "https://gitpkg.vercel.app/mitchellh/zig-js/js?main", + "integrity": "sha512-CdM4TmAINU1fsZMm0S3dH4XzQgCIC4AWfztA2eGRD9Tfk/2LfCZ7RgOED7i26P1Jf2+BCQIBMbxXocV7oxR3Ig==", + "license": "MIT" } }, "dependencies": { @@ -3647,6 +4320,25 @@ "color-convert": "^2.0.1" } }, + "asn1.js": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", + "dev": true + } + } + }, "base-x": { "version": "3.0.9", "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", @@ -3656,12 +4348,96 @@ "safe-buffer": "^5.0.1" } }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true + }, + "bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", + "dev": true + }, "boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", "dev": true }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", + "dev": true + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dev": true, + "requires": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "browserify-rsa": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.1.tgz", + "integrity": "sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==", + "dev": true, + "requires": { + "bn.js": "^5.2.1", + "randombytes": "^2.1.0", + "safe-buffer": "^5.2.1" + } + }, + "browserify-sign": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.3.tgz", + "integrity": "sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw==", + "dev": true, + "requires": { + "bn.js": "^5.2.1", + "browserify-rsa": "^4.1.0", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.5", + "hash-base": "~3.0", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.7", + "readable-stream": "^2.3.8", + "safe-buffer": "^5.2.1" + } + }, "browserslist": { "version": "4.21.4", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", @@ -3674,12 +4450,28 @@ "update-browserslist-db": "^1.0.9" } }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", + "dev": true + }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -3708,6 +4500,16 @@ "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", "dev": true }, + "cipher-base": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.5.tgz", + "integrity": "sha512-xq7ICKB4TMHUx7Tz1L9O2SGKOhYMOTR32oir45Bq28/AQTpHogKgHcoYFSdRbMtddl+ozNXfXY9jWcgYKmde0w==", + "dev": true, + "requires": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1" + } + }, "clone": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", @@ -3735,6 +4537,12 @@ "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", "dev": true }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, "cosmiconfig": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", @@ -3748,6 +4556,71 @@ "yaml": "^1.10.0" } }, + "create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + }, + "dependencies": { + "bn.js": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", + "dev": true + } + } + }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "crypto-browserify": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.1.tgz", + "integrity": "sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==", + "dev": true, + "requires": { + "browserify-cipher": "^1.0.1", + "browserify-sign": "^4.2.3", + "create-ecdh": "^4.0.4", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "diffie-hellman": "^5.0.3", + "hash-base": "~3.0.4", + "inherits": "^2.0.4", + "pbkdf2": "^3.1.2", + "public-encrypt": "^4.0.3", + "randombytes": "^2.1.0", + "randomfill": "^1.0.4" + } + }, "css-select": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", @@ -3786,12 +4659,41 @@ "css-tree": "^1.1.2" } }, + "des.js": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", + "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, "detect-libc": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", "dev": true }, + "diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", + "dev": true + } + } + }, "dom-serializer": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", @@ -3855,6 +4757,29 @@ "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==", "dev": true }, + "elliptic": { + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", + "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", + "dev": true, + "requires": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", + "dev": true + } + } + }, "entities": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", @@ -3882,6 +4807,22 @@ "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, "get-port": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/get-port/-/get-port-4.2.0.tgz", @@ -3897,12 +4838,48 @@ "type-fest": "^0.20.2" } }, + "glslog": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/glslog/-/glslog-0.0.10.tgz", + "integrity": "sha512-RJn15AQAH0qYvGZNtRdAN4KCsGNUC6ArIn5EJIbWMo96vjf+ZEHk7jStNa12mWNQIPZ6S7kPKsK/pBqt9GDChA==" + }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "hash-base": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", + "integrity": "sha512-EeeoJKjTyt868liAlVmcv2ZsUfGHlE3Q+BICOXcZiwN3osr5Q/zFGYmTJpoIzuaSTAwndFy+GqhEwlU4L3j4Ow==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dev": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, "htmlnano": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/htmlnano/-/htmlnano-2.0.3.tgz", @@ -3926,6 +4903,12 @@ "entities": "^3.0.1" } }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true + }, "import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -3936,6 +4919,12 @@ "resolve-from": "^4.0.0" } }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -3948,6 +4937,12 @@ "integrity": "sha512-6BEnpVn1rcf3ngfmViLM6vjUjGErbdrL4rwlv+u1NO1XO8kqT4YGL8+19Q+Z/bas8tY90BTWMk2+fW1g6hQjbA==", "dev": true }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -4072,12 +5067,53 @@ } } }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, "mdn-data": { "version": "2.0.14", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", "dev": true }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", + "dev": true + } + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "dev": true + }, "msgpackr": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.8.1.tgz", @@ -4148,6 +5184,12 @@ "integrity": "sha512-EHQ/jk4/a9hLupIKxTfUsQRej1Yd/0QLQs3vGvIqg5ZtCYSzNhkzHoZc7Zf4e4kUlDaC3Uw8Q/1opOLNN2OKRQ==", "dev": true }, + "os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==", + "dev": true + }, "parcel": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/parcel/-/parcel-2.8.0.tgz", @@ -4179,6 +5221,20 @@ "callsites": "^3.0.0" } }, + "parse-asn1": { + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.7.tgz", + "integrity": "sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg==", + "dev": true, + "requires": { + "asn1.js": "^4.10.1", + "browserify-aes": "^1.2.0", + "evp_bytestokey": "^1.0.3", + "hash-base": "~3.0", + "pbkdf2": "^3.1.2", + "safe-buffer": "^5.2.1" + } + }, "parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", @@ -4191,12 +5247,31 @@ "lines-and-columns": "^1.1.6" } }, + "path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true + }, "path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true }, + "pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "dev": true, + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, "picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -4248,6 +5323,59 @@ "is-json": "^2.0.1" } }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + }, + "dependencies": { + "bn.js": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", + "dev": true + } + } + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dev": true, + "requires": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, "react-error-overlay": { "version": "6.0.9", "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.9.tgz", @@ -4260,6 +5388,38 @@ "integrity": "sha512-Gvzk7OZpiqKSkxsQvO/mbTN1poglhmAV7gR/DdIrRrSMXraRQQlfikRJOr3Nb9GTMPC5kof948Zy6jJZIFtDvQ==", "dev": true }, + "readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, "regenerator-runtime": { "version": "0.13.11", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", @@ -4272,6 +5432,16 @@ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -4284,6 +5454,16 @@ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -4306,6 +5486,38 @@ "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", "dev": true }, + "stream-browserify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", + "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", + "dev": true, + "requires": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + } + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -4390,6 +5602,12 @@ "picocolors": "^1.0.0" } }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, "utility-types": { "version": "3.10.0", "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.10.0.tgz", @@ -4402,6 +5620,12 @@ "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", "dev": true }, + "vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", + "dev": true + }, "weak-lru-cache": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz", @@ -4421,16 +5645,8 @@ "dev": true }, "zig-js": { - "version": "file:../vendor/zig-js/js", - "requires": { - "@parcel/packager-ts": "^2.8.0", - "@parcel/transformer-typescript-types": "^2.8.0", - "@types/jest": "^29.2.3", - "jest": "^29.3.1", - "parcel": "^2.8.0", - "ts-jest": "^29.0.3", - "typescript": "^4.9.3" - } + "version": "https://gitpkg.vercel.app/mitchellh/zig-js/js?main", + "integrity": "sha512-CdM4TmAINU1fsZMm0S3dH4XzQgCIC4AWfztA2eGRD9Tfk/2LfCZ7RgOED7i26P1Jf2+BCQIBMbxXocV7oxR3Ig==" } } } diff --git a/example/package.json b/example/package.json index e884e5c6c..2619b96a6 100644 --- a/example/package.json +++ b/example/package.json @@ -13,10 +13,20 @@ "license": "MIT", "devDependencies": { "@parcel/transformer-inline-string": "^2.8.0", + "buffer": "^5.7.1", + "crypto-browserify": "^3.12.1", + "events": "^3.3.0", + "os-browserify": "^0.3.0", "parcel": "^2.8.0", - "typescript": "^4.9.3" + "path-browserify": "^1.0.1", + "process": "^0.11.10", + "stream-browserify": "^3.0.0", + "string_decoder": "^1.3.0", + "typescript": "^4.9.3", + "vm-browserify": "^1.1.2" }, "dependencies": { - "zig-js": "file:../vendor/zig-js/js" + "glslog": "^0.0.10", + "zig-js": "https://gitpkg.vercel.app/mitchellh/zig-js/js?main" } } diff --git a/example/wasi.ts b/example/wasi.ts new file mode 100644 index 000000000..84526b75a --- /dev/null +++ b/example/wasi.ts @@ -0,0 +1,431 @@ +/* + +This project is based from the Node implementation made by Gus Caplan +https://github.com/devsnek/node-wasi +However, JavaScript WASI is focused on: + * Bringing WASI to the Browsers + * Make easy to plug different filesystems + * Provide a type-safe api using Typescript + + +Copyright 2019 Gus Caplan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. + + */ + +export const WASI_ESUCCESS = 0; +export const WASI_E2BIG = 1; +export const WASI_EACCES = 2; +export const WASI_EADDRINUSE = 3; +export const WASI_EADDRNOTAVAIL = 4; +export const WASI_EAFNOSUPPORT = 5; +export const WASI_EAGAIN = 6; +export const WASI_EALREADY = 7; +export const WASI_EBADF = 8; +export const WASI_EBADMSG = 9; +export const WASI_EBUSY = 10; +export const WASI_ECANCELED = 11; +export const WASI_ECHILD = 12; +export const WASI_ECONNABORTED = 13; +export const WASI_ECONNREFUSED = 14; +export const WASI_ECONNRESET = 15; +export const WASI_EDEADLK = 16; +export const WASI_EDESTADDRREQ = 17; +export const WASI_EDOM = 18; +export const WASI_EDQUOT = 19; +export const WASI_EEXIST = 20; +export const WASI_EFAULT = 21; +export const WASI_EFBIG = 22; +export const WASI_EHOSTUNREACH = 23; +export const WASI_EIDRM = 24; +export const WASI_EILSEQ = 25; +export const WASI_EINPROGRESS = 26; +export const WASI_EINTR = 27; +export const WASI_EINVAL = 28; +export const WASI_EIO = 29; +export const WASI_EISCONN = 30; +export const WASI_EISDIR = 31; +export const WASI_ELOOP = 32; +export const WASI_EMFILE = 33; +export const WASI_EMLINK = 34; +export const WASI_EMSGSIZE = 35; +export const WASI_EMULTIHOP = 36; +export const WASI_ENAMETOOLONG = 37; +export const WASI_ENETDOWN = 38; +export const WASI_ENETRESET = 39; +export const WASI_ENETUNREACH = 40; +export const WASI_ENFILE = 41; +export const WASI_ENOBUFS = 42; +export const WASI_ENODEV = 43; +export const WASI_ENOENT = 44; +export const WASI_ENOEXEC = 45; +export const WASI_ENOLCK = 46; +export const WASI_ENOLINK = 47; +export const WASI_ENOMEM = 48; +export const WASI_ENOMSG = 49; +export const WASI_ENOPROTOOPT = 50; +export const WASI_ENOSPC = 51; +export const WASI_ENOSYS = 52; +export const WASI_ENOTCONN = 53; +export const WASI_ENOTDIR = 54; +export const WASI_ENOTEMPTY = 55; +export const WASI_ENOTRECOVERABLE = 56; +export const WASI_ENOTSOCK = 57; +export const WASI_ENOTSUP = 58; +export const WASI_ENOTTY = 59; +export const WASI_ENXIO = 60; +export const WASI_EOVERFLOW = 61; +export const WASI_EOWNERDEAD = 62; +export const WASI_EPERM = 63; +export const WASI_EPIPE = 64; +export const WASI_EPROTO = 65; +export const WASI_EPROTONOSUPPORT = 66; +export const WASI_EPROTOTYPE = 67; +export const WASI_ERANGE = 68; +export const WASI_EROFS = 69; +export const WASI_ESPIPE = 70; +export const WASI_ESRCH = 71; +export const WASI_ESTALE = 72; +export const WASI_ETIMEDOUT = 73; +export const WASI_ETXTBSY = 74; +export const WASI_EXDEV = 75; +export const WASI_ENOTCAPABLE = 76; + +export const WASI_SIGABRT = 0; +export const WASI_SIGALRM = 1; +export const WASI_SIGBUS = 2; +export const WASI_SIGCHLD = 3; +export const WASI_SIGCONT = 4; +export const WASI_SIGFPE = 5; +export const WASI_SIGHUP = 6; +export const WASI_SIGILL = 7; +export const WASI_SIGINT = 8; +export const WASI_SIGKILL = 9; +export const WASI_SIGPIPE = 10; +export const WASI_SIGQUIT = 11; +export const WASI_SIGSEGV = 12; +export const WASI_SIGSTOP = 13; +export const WASI_SIGTERM = 14; +export const WASI_SIGTRAP = 15; +export const WASI_SIGTSTP = 16; +export const WASI_SIGTTIN = 17; +export const WASI_SIGTTOU = 18; +export const WASI_SIGURG = 19; +export const WASI_SIGUSR1 = 20; +export const WASI_SIGUSR2 = 21; +export const WASI_SIGVTALRM = 22; +export const WASI_SIGXCPU = 23; +export const WASI_SIGXFSZ = 24; + +export const WASI_FILETYPE_UNKNOWN = 0; +export const WASI_FILETYPE_BLOCK_DEVICE = 1; +export const WASI_FILETYPE_CHARACTER_DEVICE = 2; +export const WASI_FILETYPE_DIRECTORY = 3; +export const WASI_FILETYPE_REGULAR_FILE = 4; +export const WASI_FILETYPE_SOCKET_DGRAM = 5; +export const WASI_FILETYPE_SOCKET_STREAM = 6; +export const WASI_FILETYPE_SYMBOLIC_LINK = 7; + +export type WASI_FILETYPE = + | typeof WASI_FILETYPE_UNKNOWN + | typeof WASI_FILETYPE_BLOCK_DEVICE + | typeof WASI_FILETYPE_CHARACTER_DEVICE + | typeof WASI_FILETYPE_DIRECTORY + | typeof WASI_FILETYPE_REGULAR_FILE + | typeof WASI_FILETYPE_SOCKET_DGRAM + | typeof WASI_FILETYPE_SOCKET_STREAM + | typeof WASI_FILETYPE_SYMBOLIC_LINK; + +export const WASI_FDFLAG_APPEND = 0x0001; +export const WASI_FDFLAG_DSYNC = 0x0002; +export const WASI_FDFLAG_NONBLOCK = 0x0004; +export const WASI_FDFLAG_RSYNC = 0x0008; +export const WASI_FDFLAG_SYNC = 0x0010; + +export const WASI_RIGHT_FD_DATASYNC = BigInt(0x0000000000000001); +export const WASI_RIGHT_FD_READ = BigInt(0x0000000000000002); +export const WASI_RIGHT_FD_SEEK = BigInt(0x0000000000000004); +export const WASI_RIGHT_FD_FDSTAT_SET_FLAGS = BigInt(0x0000000000000008); +export const WASI_RIGHT_FD_SYNC = BigInt(0x0000000000000010); +export const WASI_RIGHT_FD_TELL = BigInt(0x0000000000000020); +export const WASI_RIGHT_FD_WRITE = BigInt(0x0000000000000040); +export const WASI_RIGHT_FD_ADVISE = BigInt(0x0000000000000080); +export const WASI_RIGHT_FD_ALLOCATE = BigInt(0x0000000000000100); +export const WASI_RIGHT_PATH_CREATE_DIRECTORY = BigInt(0x0000000000000200); +export const WASI_RIGHT_PATH_CREATE_FILE = BigInt(0x0000000000000400); +export const WASI_RIGHT_PATH_LINK_SOURCE = BigInt(0x0000000000000800); +export const WASI_RIGHT_PATH_LINK_TARGET = BigInt(0x0000000000001000); +export const WASI_RIGHT_PATH_OPEN = BigInt(0x0000000000002000); +export const WASI_RIGHT_FD_READDIR = BigInt(0x0000000000004000); +export const WASI_RIGHT_PATH_READLINK = BigInt(0x0000000000008000); +export const WASI_RIGHT_PATH_RENAME_SOURCE = BigInt(0x0000000000010000); +export const WASI_RIGHT_PATH_RENAME_TARGET = BigInt(0x0000000000020000); +export const WASI_RIGHT_PATH_FILESTAT_GET = BigInt(0x0000000000040000); +export const WASI_RIGHT_PATH_FILESTAT_SET_SIZE = BigInt(0x0000000000080000); +export const WASI_RIGHT_PATH_FILESTAT_SET_TIMES = BigInt(0x0000000000100000); +export const WASI_RIGHT_FD_FILESTAT_GET = BigInt(0x0000000000200000); +export const WASI_RIGHT_FD_FILESTAT_SET_SIZE = BigInt(0x0000000000400000); +export const WASI_RIGHT_FD_FILESTAT_SET_TIMES = BigInt(0x0000000000800000); +export const WASI_RIGHT_PATH_SYMLINK = BigInt(0x0000000001000000); +export const WASI_RIGHT_PATH_REMOVE_DIRECTORY = BigInt(0x0000000002000000); +export const WASI_RIGHT_PATH_UNLINK_FILE = BigInt(0x0000000004000000); +export const WASI_RIGHT_POLL_FD_READWRITE = BigInt(0x0000000008000000); +export const WASI_RIGHT_SOCK_SHUTDOWN = BigInt(0x0000000010000000); + +export const RIGHTS_ALL = + WASI_RIGHT_FD_DATASYNC | + WASI_RIGHT_FD_READ | + WASI_RIGHT_FD_SEEK | + WASI_RIGHT_FD_FDSTAT_SET_FLAGS | + WASI_RIGHT_FD_SYNC | + WASI_RIGHT_FD_TELL | + WASI_RIGHT_FD_WRITE | + WASI_RIGHT_FD_ADVISE | + WASI_RIGHT_FD_ALLOCATE | + WASI_RIGHT_PATH_CREATE_DIRECTORY | + WASI_RIGHT_PATH_CREATE_FILE | + WASI_RIGHT_PATH_LINK_SOURCE | + WASI_RIGHT_PATH_LINK_TARGET | + WASI_RIGHT_PATH_OPEN | + WASI_RIGHT_FD_READDIR | + WASI_RIGHT_PATH_READLINK | + WASI_RIGHT_PATH_RENAME_SOURCE | + WASI_RIGHT_PATH_RENAME_TARGET | + WASI_RIGHT_PATH_FILESTAT_GET | + WASI_RIGHT_PATH_FILESTAT_SET_SIZE | + WASI_RIGHT_PATH_FILESTAT_SET_TIMES | + WASI_RIGHT_FD_FILESTAT_GET | + WASI_RIGHT_FD_FILESTAT_SET_TIMES | + WASI_RIGHT_FD_FILESTAT_SET_SIZE | + WASI_RIGHT_PATH_SYMLINK | + WASI_RIGHT_PATH_UNLINK_FILE | + WASI_RIGHT_PATH_REMOVE_DIRECTORY | + WASI_RIGHT_POLL_FD_READWRITE | + WASI_RIGHT_SOCK_SHUTDOWN; + +export const RIGHTS_BLOCK_DEVICE_BASE = RIGHTS_ALL; +export const RIGHTS_BLOCK_DEVICE_INHERITING = RIGHTS_ALL; + +export const RIGHTS_CHARACTER_DEVICE_BASE = RIGHTS_ALL; +export const RIGHTS_CHARACTER_DEVICE_INHERITING = RIGHTS_ALL; + +export const RIGHTS_REGULAR_FILE_BASE = + WASI_RIGHT_FD_DATASYNC | + WASI_RIGHT_FD_READ | + WASI_RIGHT_FD_SEEK | + WASI_RIGHT_FD_FDSTAT_SET_FLAGS | + WASI_RIGHT_FD_SYNC | + WASI_RIGHT_FD_TELL | + WASI_RIGHT_FD_WRITE | + WASI_RIGHT_FD_ADVISE | + WASI_RIGHT_FD_ALLOCATE | + WASI_RIGHT_FD_FILESTAT_GET | + WASI_RIGHT_FD_FILESTAT_SET_SIZE | + WASI_RIGHT_FD_FILESTAT_SET_TIMES | + WASI_RIGHT_POLL_FD_READWRITE; +export const RIGHTS_REGULAR_FILE_INHERITING = BigInt(0); + +export const RIGHTS_DIRECTORY_BASE = + WASI_RIGHT_FD_FDSTAT_SET_FLAGS | + WASI_RIGHT_FD_SYNC | + WASI_RIGHT_FD_ADVISE | + WASI_RIGHT_PATH_CREATE_DIRECTORY | + WASI_RIGHT_PATH_CREATE_FILE | + WASI_RIGHT_PATH_LINK_SOURCE | + WASI_RIGHT_PATH_LINK_TARGET | + WASI_RIGHT_PATH_OPEN | + WASI_RIGHT_FD_READDIR | + WASI_RIGHT_PATH_READLINK | + WASI_RIGHT_PATH_RENAME_SOURCE | + WASI_RIGHT_PATH_RENAME_TARGET | + WASI_RIGHT_PATH_FILESTAT_GET | + WASI_RIGHT_PATH_FILESTAT_SET_SIZE | + WASI_RIGHT_PATH_FILESTAT_SET_TIMES | + WASI_RIGHT_FD_FILESTAT_GET | + WASI_RIGHT_FD_FILESTAT_SET_TIMES | + WASI_RIGHT_PATH_SYMLINK | + WASI_RIGHT_PATH_UNLINK_FILE | + WASI_RIGHT_PATH_REMOVE_DIRECTORY | + WASI_RIGHT_POLL_FD_READWRITE; +export const RIGHTS_DIRECTORY_INHERITING = + RIGHTS_DIRECTORY_BASE | RIGHTS_REGULAR_FILE_BASE; + +export const RIGHTS_SOCKET_BASE = + WASI_RIGHT_FD_READ | + WASI_RIGHT_FD_FDSTAT_SET_FLAGS | + WASI_RIGHT_FD_WRITE | + WASI_RIGHT_FD_FILESTAT_GET | + WASI_RIGHT_POLL_FD_READWRITE | + WASI_RIGHT_SOCK_SHUTDOWN; +export const RIGHTS_SOCKET_INHERITING = RIGHTS_ALL; + +export const RIGHTS_TTY_BASE = + WASI_RIGHT_FD_READ | + WASI_RIGHT_FD_FDSTAT_SET_FLAGS | + WASI_RIGHT_FD_WRITE | + WASI_RIGHT_FD_FILESTAT_GET | + WASI_RIGHT_POLL_FD_READWRITE; +export const RIGHTS_TTY_INHERITING = BigInt(0); + +export const WASI_CLOCK_REALTIME = 0; +export const WASI_CLOCK_MONOTONIC = 1; +export const WASI_CLOCK_PROCESS_CPUTIME_ID = 2; +export const WASI_CLOCK_THREAD_CPUTIME_ID = 3; + +export const WASI_EVENTTYPE_CLOCK = 0; +export const WASI_EVENTTYPE_FD_READ = 1; +export const WASI_EVENTTYPE_FD_WRITE = 2; + +export const WASI_FILESTAT_SET_ATIM = 1 << 0; +export const WASI_FILESTAT_SET_ATIM_NOW = 1 << 1; +export const WASI_FILESTAT_SET_MTIM = 1 << 2; +export const WASI_FILESTAT_SET_MTIM_NOW = 1 << 3; + +export const WASI_O_CREAT = 1 << 0; +export const WASI_O_DIRECTORY = 1 << 1; +export const WASI_O_EXCL = 1 << 2; +export const WASI_O_TRUNC = 1 << 3; + +export const WASI_PREOPENTYPE_DIR = 0; + +export const WASI_DIRCOOKIE_START = 0; + +export const WASI_STDIN_FILENO = 0; +export const WASI_STDOUT_FILENO = 1; +export const WASI_STDERR_FILENO = 2; + +export const WASI_WHENCE_SET = 0; +export const WASI_WHENCE_CUR = 1; +export const WASI_WHENCE_END = 2; + +// http://man7.org/linux/man-pages/man3/errno.3.html +export const ERROR_MAP: { [key: string]: number } = { + E2BIG: WASI_E2BIG, + EACCES: WASI_EACCES, + EADDRINUSE: WASI_EADDRINUSE, + EADDRNOTAVAIL: WASI_EADDRNOTAVAIL, + EAFNOSUPPORT: WASI_EAFNOSUPPORT, + EALREADY: WASI_EALREADY, + EAGAIN: WASI_EAGAIN, + // EBADE: WASI_EBADE, + EBADF: WASI_EBADF, + // EBADFD: WASI_EBADFD, + EBADMSG: WASI_EBADMSG, + // EBADR: WASI_EBADR, + // EBADRQC: WASI_EBADRQC, + // EBADSLT: WASI_EBADSLT, + EBUSY: WASI_EBUSY, + ECANCELED: WASI_ECANCELED, + ECHILD: WASI_ECHILD, + // ECHRNG: WASI_ECHRNG, + // ECOMM: WASI_ECOMM, + ECONNABORTED: WASI_ECONNABORTED, + ECONNREFUSED: WASI_ECONNREFUSED, + ECONNRESET: WASI_ECONNRESET, + EDEADLOCK: WASI_EDEADLK, + EDESTADDRREQ: WASI_EDESTADDRREQ, + EDOM: WASI_EDOM, + EDQUOT: WASI_EDQUOT, + EEXIST: WASI_EEXIST, + EFAULT: WASI_EFAULT, + EFBIG: WASI_EFBIG, + EHOSTDOWN: WASI_EHOSTUNREACH, + EHOSTUNREACH: WASI_EHOSTUNREACH, + // EHWPOISON: WASI_EHWPOISON, + EIDRM: WASI_EIDRM, + EILSEQ: WASI_EILSEQ, + EINPROGRESS: WASI_EINPROGRESS, + EINTR: WASI_EINTR, + EINVAL: WASI_EINVAL, + EIO: WASI_EIO, + EISCONN: WASI_EISCONN, + EISDIR: WASI_EISDIR, + ELOOP: WASI_ELOOP, + EMFILE: WASI_EMFILE, + EMLINK: WASI_EMLINK, + EMSGSIZE: WASI_EMSGSIZE, + EMULTIHOP: WASI_EMULTIHOP, + ENAMETOOLONG: WASI_ENAMETOOLONG, + ENETDOWN: WASI_ENETDOWN, + ENETRESET: WASI_ENETRESET, + ENETUNREACH: WASI_ENETUNREACH, + ENFILE: WASI_ENFILE, + ENOBUFS: WASI_ENOBUFS, + ENODEV: WASI_ENODEV, + ENOENT: WASI_ENOENT, + ENOEXEC: WASI_ENOEXEC, + ENOLCK: WASI_ENOLCK, + ENOLINK: WASI_ENOLINK, + ENOMEM: WASI_ENOMEM, + ENOMSG: WASI_ENOMSG, + ENOPROTOOPT: WASI_ENOPROTOOPT, + ENOSPC: WASI_ENOSPC, + ENOSYS: WASI_ENOSYS, + ENOTCONN: WASI_ENOTCONN, + ENOTDIR: WASI_ENOTDIR, + ENOTEMPTY: WASI_ENOTEMPTY, + ENOTRECOVERABLE: WASI_ENOTRECOVERABLE, + ENOTSOCK: WASI_ENOTSOCK, + ENOTTY: WASI_ENOTTY, + ENXIO: WASI_ENXIO, + EOVERFLOW: WASI_EOVERFLOW, + EOWNERDEAD: WASI_EOWNERDEAD, + EPERM: WASI_EPERM, + EPIPE: WASI_EPIPE, + EPROTO: WASI_EPROTO, + EPROTONOSUPPORT: WASI_EPROTONOSUPPORT, + EPROTOTYPE: WASI_EPROTOTYPE, + ERANGE: WASI_ERANGE, + EROFS: WASI_EROFS, + ESPIPE: WASI_ESPIPE, + ESRCH: WASI_ESRCH, + ESTALE: WASI_ESTALE, + ETIMEDOUT: WASI_ETIMEDOUT, + ETXTBSY: WASI_ETXTBSY, + EXDEV: WASI_EXDEV +}; + +export const SIGNAL_MAP: { [key: string]: string } = { + [WASI_SIGHUP]: "SIGHUP", + [WASI_SIGINT]: "SIGINT", + [WASI_SIGQUIT]: "SIGQUIT", + [WASI_SIGILL]: "SIGILL", + [WASI_SIGTRAP]: "SIGTRAP", + [WASI_SIGABRT]: "SIGABRT", + [WASI_SIGBUS]: "SIGBUS", + [WASI_SIGFPE]: "SIGFPE", + [WASI_SIGKILL]: "SIGKILL", + [WASI_SIGUSR1]: "SIGUSR1", + [WASI_SIGSEGV]: "SIGSEGV", + [WASI_SIGUSR2]: "SIGUSR2", + [WASI_SIGPIPE]: "SIGPIPE", + [WASI_SIGALRM]: "SIGALRM", + [WASI_SIGTERM]: "SIGTERM", + [WASI_SIGCHLD]: "SIGCHLD", + [WASI_SIGCONT]: "SIGCONT", + [WASI_SIGSTOP]: "SIGSTOP", + [WASI_SIGTSTP]: "SIGTSTP", + [WASI_SIGTTIN]: "SIGTTIN", + [WASI_SIGTTOU]: "SIGTTOU", + [WASI_SIGURG]: "SIGURG", + [WASI_SIGXCPU]: "SIGXCPU", + [WASI_SIGXFSZ]: "SIGXFSZ", + [WASI_SIGVTALRM]: "SIGVTALRM" +}; diff --git a/example/worker.ts b/example/worker.ts new file mode 100644 index 000000000..9c167e7f3 --- /dev/null +++ b/example/worker.ts @@ -0,0 +1,14 @@ +import { importObject, setFiles, setMainThread, setStdin, zjs } from "./imports"; + +onmessage = async (e) => { + console.log("module received from main thread"); + const [memory, instance, stdin, wasmModule, files, pid] = e.data; + console.log(wasmModule) + setStdin(stdin); + setMainThread(false); + setFiles(files); + importObject.env.memory = memory; + const results = await WebAssembly.instantiate(wasmModule, importObject); + zjs.memory = memory; + results.exports.wasi_thread_start(pid, instance); +}; diff --git a/pkg/opengl/c.zig b/pkg/opengl/c.zig index fc95ee94c..60c13cf6b 100644 --- a/pkg/opengl/c.zig +++ b/pkg/opengl/c.zig @@ -1,3 +1,284 @@ -pub const c = @cImport({ +const builtin = @import("builtin"); +pub const c = if (builtin.cpu.arch != .wasm32) @cImport({ @cInclude("glad/gl.h"); -}); +}) else struct { + pub extern fn glBindBufferBase(_: c_uint, _: c_uint, _: c_uint) void; + pub extern fn glDrawElementsInstanced(_: GLenum, _: GLsizei, _: GLenum, _: ?*const anyopaque, _: GLsizei) void; + pub extern fn glUniform4f(_: c_int, _: f32, _: f32, _: f32, _: f32) void; + pub extern fn glUniform4fv(_: c_int, _: f32, _: f32, _: f32, _: f32) void; + pub extern fn glBindFramebuffer(_: c_uint, _: c_uint) void; + pub extern fn glGetIntegerv(_: GLenum, _: *GLint) void; + pub extern fn glTexSubImage2D(_: c_uint, _: c_int, _: c_int, _: isize, _: isize, _: c_int, _: c_uint, _: c_uint, _: ?*const anyopaque) void; + pub extern fn glDeleteFramebuffers(_: c_int, _: [*c]const c_uint) void; + pub extern fn glGenFramebuffers(_: c_int, _: [*c]c_uint) void; + pub extern fn glVertexAttribDivisor(_: c_uint, _: c_uint) void; + pub extern fn glVertexAttribIPointer(_: c_uint, _: c_int, _: c_uint, _: isize, _: ?*const anyopaque) void; + pub extern fn glBufferSubData(_: GLenum, _: isize, _: isize, _: ?*const anyopaque) void; + pub extern fn glViewport(_: c_int, _: c_int, _: isize, _: isize) void; + pub extern fn glClearColor(_: f32, _: f32, _: f32, _: f32) void; + pub extern fn glEnable(_: c_uint) void; + pub extern fn glDisable(_: c_uint) void; + pub extern fn glDepthFunc(_: c_uint) void; + pub extern fn glBlendFunc(_: c_uint, _: c_uint) void; + pub extern fn glClear(_: c_uint) void; + pub extern fn glGetAttribLocation(_: c_uint, _: [*]const u8, _: c_uint) c_int; + pub extern fn glGetUniformLocation(_: c_uint, _: [*]const u8) c_int; + pub extern fn glUniform1i(_: c_int, _: c_int) void; + pub extern fn glUniform1f(_: c_int, _: f32) void; + pub extern fn glUniformMatrix4fv(_: c_int, _: c_int, _: c_uint, _: *const f32) void; + pub extern fn glCreateVertexArray() c_uint; + pub extern fn glGenVertexArrays(_: c_int, [*c]c_uint) void; + pub extern fn glDeleteVertexArrays(_: c_int, [*c]const c_uint) void; + pub extern fn glBindVertexArray(_: c_uint) void; + pub extern fn glCreateBuffer() c_uint; + pub extern fn glGenBuffers(_: c_int, _: [*c]c_uint) void; + pub extern fn glDeleteBuffers(_: c_int, _: [*c]const c_uint) void; + pub extern fn glDeleteBuffer(_: c_uint) void; + pub extern fn glBindBuffer(_: c_uint, _: c_uint) void; + pub extern fn glBufferData(_: c_uint, _: isize, _: ?*const anyopaque, _: c_uint) void; + pub extern fn glPixelStorei(_: c_uint, _: c_int) void; + pub extern fn glAttachShader(_: c_uint, _: c_uint) void; + pub extern fn glDetachShader(_: c_uint, _: c_uint) void; + pub extern fn glDeleteShader(_: c_uint) void; + pub extern fn glCreateShader(_: c_uint) c_uint; + pub extern fn glCompileShader(_: c_uint) void; + pub extern fn glShaderSource(_: c_uint, _: c_uint, _: *const [*c]const u8, _: ?*GLint) void; + pub extern fn glCreateProgram() c_uint; + pub extern fn glGetShaderiv(_: c_uint, _: c_uint, _: [*c]c_int) void; + pub extern fn glGetShaderInfoLog(_: c_uint, _: c_int, _: [*c]c_int, _: [*c]u8) void; + pub extern fn glGetProgramiv(_: c_uint, _: c_uint, _: [*c]c_int) void; + pub extern fn glLinkProgram(_: c_uint) void; + pub extern fn glUseProgram(_: c_uint) void; + pub extern fn glGetProgramInfoLog(_: c_uint, _: c_int, _: [*c]c_int, _: [*c]u8) void; + pub extern fn glDeleteProgram(_: c_uint) void; + pub extern fn glEnableVertexAttribArray(_: c_uint) void; + pub extern fn glVertexAttribPointer(_: c_uint, _: c_int, _: c_uint, _: c_uint, _: isize, _: ?*const anyopaque) void; + pub extern fn glDrawArrays(_: c_uint, _: c_uint, _: c_int) void; + pub extern fn glCreateTexture() c_uint; + pub extern fn glGenTextures(_: c_int, _: [*c]c_uint) void; + pub extern fn glDeleteTextures(_: c_int, _: [*c]const c_uint) void; + pub extern fn glDeleteTexture(_: c_uint) void; + pub extern fn glBindTexture(_: c_uint, _: c_uint) void; + pub extern fn glTexImage2D(_: GLenum, _: GLint, _: c_int, _: c_int, _: c_int, _: c_int, _: c_uint, _: c_uint, _: ?*const anyopaque) void; + pub extern fn glTexParameteri(_: c_uint, _: c_uint, _: c_int) void; + pub extern fn glActiveTexture(_: c_uint) void; + pub extern fn glGenerateMipmap(_: c_uint) void; + pub extern fn glGetError() c_int; + pub extern fn glGetString(_: c_int) c_int; + pub extern fn glGetShaderParameter(_: c_uint, _: c_uint) c_int; + pub extern fn glUniform2f(_: c_int, _: f32, _: f32) void; + + // Types. + pub const GLuint = c_uint; + pub const GLenum = c_uint; + pub const GLbitfield = c_uint; + pub const GLint = c_int; + pub const GLsizei = isize; + pub const GLfloat = f32; + pub const GLboolean = u8; + + // https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Constants + pub const GL_FALSE = 0; + pub const GL_TRUE = 1; + pub const GL_TRIANGLES = 4; + pub const GL_DEPTH_BUFFER_BIT = 256; + pub const GL_SRC_ALPHA = 770; + pub const GL_ONE_MINUS_SRC_ALPHA = 771; + pub const GL_FLOAT = 5126; + pub const GL_CULL_FACE = 2884; + pub const GL_DEPTH_TEST = 2929; + pub const GL_BLEND = 3042; + pub const GL_TEXTURE_2D = 3553; + pub const GL_UNSIGNED_BYTE = 5121; + pub const GL_RED = 6403; + pub const GL_RGBA = 6408; + pub const GL_VERSION = 7938; + pub const GL_LINEAR: GLint = 9729; + pub const GL_TEXTURE_MAG_FILTER = 10240; + pub const GL_TEXTURE_MIN_FILTER = 10241; + pub const GL_TEXTURE_WRAP_S = 10242; + pub const GL_TEXTURE_WRAP_T = 10243; + pub const GL_COLOR_BUFFER_BIT = 16384; + pub const GL_CLAMP_TO_EDGE: GLint = 33071; + pub const GL_RG = 33319; + pub const GL_RG32F = 33327; + pub const GL_TEXTURE0 = 33984; + pub const GL_TEXTURE1 = 33985; + pub const GL_TEXTURE2 = 33986; + pub const GL_TEXTURE3 = 33987; + pub const GL_TEXTURE4 = 33988; + pub const GL_TEXTURE5 = 33989; + pub const GL_RGBA32F = 34836; + pub const GL_ARRAY_BUFFER = 34962; + pub const GL_STATIC_DRAW = 35044; + pub const GL_FRAGMENT_SHADER = 35632; + pub const GL_VERTEX_SHADER = 35633; + pub const GL_COMPILE_STATUS = 35713; + pub const GL_LINK_STATUS = 35714; + pub const GL_FRAMEBUFFER_COMPLETE = 36053; + pub const GL_COLOR_ATTACHMENT0 = 36064; + pub const GL_COLOR_ATTACHMENT1 = 36065; + pub const GL_COLOR_ATTACHMENT2 = 36066; + pub const GL_DEPTH_ATTACHMENT = 36096; + pub const GL_FRAMEBUFFER = 36160; + pub const GL_RENDERBUFFER = 36161; + + pub const GL_NO_ERROR = 0; + pub const GL_INVALID_ENUM = 0x0500; + pub const GL_INVALID_FRAMEBUFFER_OPERATION = 0x0506; + pub const GL_INVALID_OPERATION = 0x0502; + pub const GL_INVALID_VALUE = 0x0501; + pub const GL_OUT_OF_MEMORY = 0x0505; + pub const GL_ONE = 1; + + pub const GL_TEXTURE_1D = 0x0DE0; + pub const GL_TEXTURE_2D_ARRAY = 0x8C1A; + pub const GL_TEXTURE_1D_ARRAY = 0x8C18; + pub const GL_TEXTURE_3D = 0x806F; + pub const GL_TEXTURE_RECTANGLE = 0x84F5; + pub const GL_TEXTURE_CUBE_MAP = 0x8513; + pub const GL_TEXTURE_BUFFER = 0x8C2A; + pub const GL_TEXTURE_2D_MULTISAMPLE = 0x9100; + pub const GL_TEXTURE_2D_MULTISAMPLE_ARRAY = 0x9102; + pub const GL_TEXTURE_BASE_LEVEL = 0x813C; + pub const GL_TEXTURE_SWIZZLE_A = 0x8E45; + pub const GL_TEXTURE_SWIZZLE_B = 0x8E44; + pub const GL_TEXTURE_SWIZZLE_G = 0x8E43; + pub const GL_TEXTURE_SWIZZLE_R = 0x8E42; + pub const GL_TEXTURE_COMPARE_FUNC = 0x884D; + pub const GL_TEXTURE_COMPARE_MODE = 0x884C; + pub const GL_TEXTURE_LOD_BIAS = 0x8501; + pub const GL_TEXTURE_MIN_LOD = 0x813A; + pub const GL_TEXTURE_MAX_LOD = 0x813B; + pub const GL_TEXTURE_MAX_LEVEL = 0x813D; + pub const GL_TEXTURE_WRAP_R = 0x8072; + pub const GL_RGB = 0x1907; + pub const GL_BGRA = 0x80E1; + pub const GL_ELEMENT_ARRAY_BUFFER = 0x8893; + pub const GL_UNIFORM_BUFFER = 0x8A11; + pub const GL_STREAM_COPY = 0x88E2; + pub const GL_STREAM_DRAW = 0x88E0; + pub const GL_STREAM_READ = 0x88E1; + pub const GL_STATIC_COPY = 0x88E6; + pub const GL_STATIC_READ = 0x88E5; + pub const GL_DYNAMIC_COPY = 0x88EA; + pub const GL_DYNAMIC_DRAW = 0x88E8; + pub const GL_DYNAMIC_READ = 0x88E9; + pub const GL_UNSIGNED_SHORT = 0x1403; + pub const GL_INT = 0x1404; + pub const GL_UNSIGNED_INT = 0x1405; + pub const GL_DRAW_FRAMEBUFFER = 0x8CA9; + pub const GL_READ_FRAMEBUFFER_BINDING = 0x8CAA; + pub const GL_READ_FRAMEBUFFER = 0x8CA8; + pub const GL_FRAMEBUFFER_BINDING = 0x8CA6; + pub const GladGLContext = struct { + pub fn init(self: *GladGLContext) void { + self.* = .{ + .Enable = glEnable, + .GetError = glGetError, + .BlendFunc = glBlendFunc, + .BindTexture = glBindTexture, + .GenTextures = glGenTextures, + .DeleteTextures = glDeleteTextures, + .TexImage2D = glTexImage2D, + .CreateShader = glCreateShader, + .CompileShader = glCompileShader, + .DeleteShader = glDeleteShader, + .AttachShader = glAttachShader, + .ShaderSource = glShaderSource, + .GetShaderiv = glGetShaderiv, + .GetShaderInfoLog = glGetShaderInfoLog, + .CreateProgram = glCreateProgram, + .LinkProgram = glLinkProgram, + .GetProgramiv = glGetProgramiv, + .GetProgramInfoLog = glGetProgramInfoLog, + .UseProgram = glUseProgram, + .DeleteProgram = glDeleteProgram, + .GetUniformLocation = glGetUniformLocation, + .Uniform4fv = glUniform4fv, + .Uniform1i = glUniform1i, + .Uniform1f = glUniform1f, + .Uniform2f = glUniform2f, + .UniformMatrix4fv = glUniformMatrix4fv, + .GenVertexArrays = glGenVertexArrays, + .DeleteVertexArrays = glDeleteVertexArrays, + .BindVertexArray = glBindVertexArray, + .GenBuffers = glGenBuffers, + .DeleteBuffers = glDeleteBuffers, + .DeleteBuffer = glDeleteBuffer, + .BindBuffer = glBindBuffer, + .BufferData = glBufferData, + .BufferSubData = glBufferSubData, + .VertexAttribPointer = glVertexAttribPointer, + .VertexAttribIPointer = glVertexAttribIPointer, + .EnableVertexAttribArray = glEnableVertexAttribArray, + .VertexAttribDivisor = glVertexAttribDivisor, + .GenFramebuffers = glGenFramebuffers, + .DeleteFramebuffers = glDeleteFramebuffers, + .TexSubImage2D = glTexSubImage2D, + .GetIntegerv = glGetIntegerv, + .BindFramebuffer = glBindFramebuffer, + .ClearColor = glClearColor, + .Clear = glClear, + .Viewport = glViewport, + .Uniform4f = glUniform4f, + .ActiveTexture = glActiveTexture, + .DrawElementsInstanced = glDrawElementsInstanced, + .BindBufferBase = glBindBufferBase, + .TexParameteri = glTexParameteri, + }; + } + Enable: ?*const fn (_: GLenum) callconv(.C) void, + GetError: ?*const fn () callconv(.C) c_int, + BlendFunc: ?*const fn (_: c_uint, _: c_uint) callconv(.C) void, + BindTexture: ?*const fn (_: c_uint, _: c_uint) callconv(.C) void, + GenTextures: ?*const fn (_: c_int, _: [*c]c_uint) callconv(.C) void, + DeleteTextures: ?*const fn (_: c_int, _: [*c]const c_uint) callconv(.C) void, + TexImage2D: ?*const fn (_: GLenum, _: GLint, _: c_int, _: c_int, _: c_int, _: c_int, _: c_uint, _: c_uint, _: ?*const anyopaque) callconv(.C) void, + CreateShader: ?*const fn (_: GLenum) callconv(.C) GLuint, + CompileShader: ?*const fn (_: c_uint) callconv(.C) void, + DeleteShader: ?*const fn (_: c_uint) callconv(.C) void, + AttachShader: ?*const fn (_: c_uint, _: c_uint) callconv(.C) void, + ShaderSource: ?*const fn (_: c_uint, _: c_uint, _: *const [*c]const u8, _: ?*GLint) callconv(.C) void, + GetShaderiv: ?*const fn (_: c_uint, _: c_uint, _: [*c]c_int) callconv(.C) void, + GetShaderInfoLog: ?*const fn (_: c_uint, _: c_int, _: [*c]c_int, _: [*c]u8) callconv(.C) void, + CreateProgram: ?*const fn () callconv(.C) c_uint, + LinkProgram: ?*const fn (_: c_uint) callconv(.C) void, + GetProgramiv: ?*const fn (_: c_uint, _: c_uint, _: [*c]c_int) callconv(.C) void, + GetProgramInfoLog: ?*const fn (_: c_uint, _: c_int, _: [*c]c_int, _: [*c]u8) callconv(.C) void, + UseProgram: ?*const fn (_: c_uint) callconv(.C) void, + DeleteProgram: ?*const fn (_: c_uint) callconv(.C) void, + GetUniformLocation: ?*const fn (_: c_uint, _: [*]const u8) callconv(.C) c_int, + Uniform4fv: ?*const fn (_: c_int, _: f32, _: f32, _: f32, _: f32) callconv(.C) void, + Uniform1i: ?*const fn (_: c_int, _: c_int) callconv(.C) void, + Uniform1f: ?*const fn (_: c_int, _: f32) callconv(.C) void, + Uniform2f: ?*const fn (_: c_int, _: f32, _: f32) callconv(.C) void, + UniformMatrix4fv: ?*const fn (_: c_int, _: c_int, _: c_uint, _: *const f32) callconv(.C) void, + GenVertexArrays: ?*const fn (_: c_int, [*c]c_uint) callconv(.C) void, + DeleteVertexArrays: ?*const fn (_: c_int, [*c]const c_uint) callconv(.C) void, + BindVertexArray: ?*const fn (_: c_uint) callconv(.C) void, + GenBuffers: ?*const fn (_: c_int, _: [*c]c_uint) callconv(.C) void, + DeleteBuffers: ?*const fn (_: c_int, _: [*c]const c_uint) callconv(.C) void, + DeleteBuffer: ?*const fn (_: c_uint) callconv(.C) void, + BindBuffer: ?*const fn (_: c_uint, _: c_uint) callconv(.C) void, + BufferData: ?*const fn (_: c_uint, _: isize, _: ?*const anyopaque, _: c_uint) callconv(.C) void, + BufferSubData: ?*const fn (_: GLenum, _: isize, _: isize, _: ?*const anyopaque) callconv(.C) void, + VertexAttribPointer: ?*const fn (_: c_uint, _: c_int, _: c_uint, _: c_uint, _: isize, _: ?*const anyopaque) callconv(.C) void, + VertexAttribIPointer: ?*const fn (_: c_uint, _: c_int, _: c_uint, _: isize, _: ?*const anyopaque) callconv(.C) void, + EnableVertexAttribArray: ?*const fn (_: c_uint) callconv(.C) void, + VertexAttribDivisor: ?*const fn (_: c_uint, _: c_uint) callconv(.C) void, + GenFramebuffers: ?*const fn (_: c_int, _: [*c]c_uint) callconv(.C) void, + DeleteFramebuffers: ?*const fn (_: c_int, _: [*c]const c_uint) callconv(.C) void, + TexSubImage2D: ?*const fn (_: c_uint, _: c_int, _: c_int, _: isize, _: isize, _: c_int, _: c_uint, _: c_uint, _: ?*const anyopaque) callconv(.C) void, + GetIntegerv: ?*const fn (_: GLenum, _: *GLint) callconv(.C) void, + BindFramebuffer: ?*const fn (_: c_uint, _: c_uint) callconv(.C) void, + ClearColor: ?*const fn (_: f32, _: f32, _: f32, _: f32) callconv(.C) void, + Clear: ?*const fn (_: c_uint) callconv(.C) void, + Viewport: ?*const fn (_: c_int, _: c_int, _: isize, _: isize) callconv(.C) void, + Uniform4f: ?*const fn (_: c_int, _: f32, _: f32, _: f32, _: f32) callconv(.C) void, + ActiveTexture: ?*const fn (_: c_uint) callconv(.C) void, + DrawElementsInstanced: ?*const fn (_: GLenum, _: GLsizei, _: GLenum, _: ?*const anyopaque, _: GLsizei) callconv(.C) void, + BindBufferBase: ?*const fn (_: c_uint, _: c_uint, _: c_uint) callconv(.C) void, + TexParameteri: ?*const fn (_: c_uint, _: c_uint, _: c_int) callconv(.C) void, + }; +}; diff --git a/pkg/sentry/build.zig b/pkg/sentry/build.zig index 855490c0a..c3e360b48 100644 --- a/pkg/sentry/build.zig +++ b/pkg/sentry/build.zig @@ -116,7 +116,7 @@ pub fn build(b: *std.Build) !void { .flags = flags.items, }), - .freestanding => {}, + .freestanding, .wasi => {}, else => { std.log.warn("target={} not supported", .{target.result.os.tag}); diff --git a/pkg/simdutf/build.zig b/pkg/simdutf/build.zig index 1532e4a33..123d8f903 100644 --- a/pkg/simdutf/build.zig +++ b/pkg/simdutf/build.zig @@ -22,6 +22,7 @@ pub fn build(b: *std.Build) !void { // Zig 0.13 bug: https://github.com/ziglang/zig/issues/20414 // (See root Ghostty build.zig on why we do this) try flags.appendSlice(&.{"-DSIMDUTF_IMPLEMENTATION_ICELAKE=0"}); + try flags.appendSlice(&.{"-DSIMDUTF_NO_THREADS"}); lib.addCSourceFiles(.{ .flags = flags.items, diff --git a/src/Command.zig b/src/Command.zig index daca54f94..6c5066716 100644 --- a/src/Command.zig +++ b/src/Command.zig @@ -73,7 +73,8 @@ pseudo_console: if (builtin.os.tag == .windows) ?windows.exp.HPCON else void = data: ?*anyopaque = null, /// Process ID is set after start is called. -pid: ?posix.pid_t = null, +pid: ?PidT = null, +pub const PidT = if (builtin.cpu.arch != .wasm32) posix.pid_t else i32; /// LinuxCGroup type depends on our target OS pub const LinuxCgroup = if (builtin.os.tag == .linux) ?[]const u8 else void; @@ -122,6 +123,7 @@ pub fn start(self: *Command, alloc: Allocator) !void { switch (builtin.os.tag) { .windows => try self.startWindows(arena), + .wasi => try self.startWasi(arena), else => try self.startPosix(arena), } } @@ -187,6 +189,26 @@ fn startPosix(self: *Command, arena: Allocator) !void { return error.ExecFailedInChild; } +fn startWasi(self: *Command, arena: Allocator) !void { + // Null-terminate all our arguments + const pathZ = try arena.dupeZ(u8, self.path); + const argsZ = try arena.allocSentinel(?[*:0]u8, self.args.len, null); + for (self.args, 0..) |arg, i| argsZ[i] = (try arena.dupeZ(u8, arg)).ptr; + + // Determine our env vars + const envp = if (self.env) |env_map| + (try createNullDelimitedEnvMap(arena, env_map)).ptr + else if (builtin.link_libc) + std.c.environ + else + @compileError("missing env vars"); + + self.pid = 100; + + std.log.err("need to fork {s} {*}", .{ pathZ, envp }); + return; +} + fn startWindows(self: *Command, arena: Allocator) !void { const application_w = try std.unicode.utf8ToUtf16LeWithNull(arena, self.path); const cwd_w = if (self.cwd) |cwd| try std.unicode.utf8ToUtf16LeWithNull(arena, cwd) else null; @@ -324,6 +346,7 @@ fn setupFd(src: File.Handle, target: i32) !void { try posix.dup2(src, target); }, + .wasi => {}, else => @compileError("unsupported platform"), } } diff --git a/src/Surface.zig b/src/Surface.zig index eef2eb8b3..77b6449b9 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -592,7 +592,7 @@ pub fn init( // Start our renderer thread self.renderer_thr = try std.Thread.spawn( - .{}, + .{ .allocator = alloc }, renderer.Thread.threadMain, .{&self.renderer_thread}, ); @@ -600,7 +600,7 @@ pub fn init( // Start our IO thread self.io_thr = try std.Thread.spawn( - .{}, + .{ .allocator = alloc }, termio.Thread.threadMain, .{ &self.io_thread, &self.io }, ); diff --git a/src/apprt/browser.zig b/src/apprt/browser.zig index d60776a6a..f7a290672 100644 --- a/src/apprt/browser.zig +++ b/src/apprt/browser.zig @@ -1,2 +1,101 @@ -pub const App = struct {}; +const CoreSurface = @import("../Surface.zig"); +const CoreApp = @import("../App.zig"); +const apprt = @import("../apprt.zig"); +const std = @import("std"); +const log = std.log; + +pub const App = struct { + app: *CoreApp, + + pub const Options = struct {}; + pub fn init(core_app: *CoreApp, _: Options) !App { + return .{ .app = core_app }; + } + pub fn performAction( + self: *App, + target: apprt.Target, + comptime action: apprt.Action.Key, + value: apprt.Action.Value(action), + ) !void { + switch (action) { + .new_window => _ = try self.newSurface(switch (target) { + .app => null, + .surface => |v| v, + }), + + .new_tab => try self.newTab(switch (target) { + .app => null, + .surface => |v| v, + }), + + .initial_size => switch (target) { + .app => {}, + .surface => |surface| try surface.rt_surface.setInitialWindowSize( + value.width, + value.height, + ), + }, + + // Unimplemented + .size_limit, + .toggle_fullscreen, + .set_title, + .mouse_shape, + .mouse_visibility, + .open_config, + .new_split, + .goto_split, + .resize_split, + .equalize_splits, + .toggle_split_zoom, + .present_terminal, + .close_all_windows, + .toggle_tab_overview, + .toggle_window_decorations, + .toggle_quick_terminal, + .toggle_visibility, + .goto_tab, + .move_tab, + .inspector, + .render_inspector, + .quit_timer, + .secure_input, + .key_sequence, + .desktop_notification, + .mouse_over_link, + .cell_size, + .renderer_health, + .color_change, + .pwd, + .reload_config, + .config_change, + => log.info("unimplemented action={}", .{action}), + } + } + pub fn wakeup(self: *const App) void { + _ = self; + } +}; pub const Window = struct {}; +pub const Surface = struct { + pub const opengl_single_threaded_draw = true; + /// The app we're part of + app: *App, + + /// A core surface + core_surface: CoreSurface, + pub fn init(self: *Surface, app: *App) !void { + self.app = app; + } + pub fn getContentScale(_: *const Surface) !apprt.ContentScale { + return apprt.ContentScale{ .x = 1, .y = 1 }; + } + pub fn getSize(_: *const Surface) !apprt.SurfaceSize { + return apprt.SurfaceSize{ .width = 500, .height = 500 }; + } + fn setInitialWindowSize(self: *const Surface, width: u32, height: u32) !void { + _ = height; // autofix + _ = self; // autofix + _ = width; // autofix + } +}; diff --git a/src/build_config.zig b/src/build_config.zig index 715552e03..8f9df129c 100644 --- a/src/build_config.zig +++ b/src/build_config.zig @@ -128,8 +128,8 @@ pub const Artifact = enum { pub fn detect() Artifact { if (builtin.target.isWasm()) { - assert(builtin.output_mode == .Obj); - assert(builtin.link_mode == .Static); + // assert(builtin.output_mode == .Obj); + // assert(builtin.link_mode == .Static); return .wasm_module; } diff --git a/src/cli/args.zig b/src/cli/args.zig index 3e378f347..466404500 100644 --- a/src/cli/args.zig +++ b/src/cli/args.zig @@ -1275,7 +1275,7 @@ pub fn LineIterator(comptime ReaderType: type) type { } // Constructs a LineIterator (see docs for that). -fn lineIterator(reader: anytype) LineIterator(@TypeOf(reader)) { +pub fn lineIterator(reader: anytype) LineIterator(@TypeOf(reader)) { return .{ .r = reader }; } diff --git a/src/config/Config.zig b/src/config/Config.zig index 55cd55606..4cca68474 100644 --- a/src/config/Config.zig +++ b/src/config/Config.zig @@ -2638,6 +2638,7 @@ pub fn changeConditionalState( /// Expand the relative paths in config-files to be absolute paths /// relative to the base directory. fn expandPaths(self: *Config, base: []const u8) !void { + if (builtin.cpu.arch == .wasm32) return error.WasmCannotExpandPaths; const arena_alloc = self._arena.?.allocator(); // Keep track of this step for replays @@ -2752,19 +2753,21 @@ fn loadTheme(self: *Config, theme: Theme) !void { pub fn finalize(self: *Config) !void { // We always load the theme first because it may set other fields // in our config. - if (self.theme) |theme| { - const different = !std.mem.eql(u8, theme.light, theme.dark); + if (builtin.cpu.arch != .wasm32) { + if (self.theme) |theme| { + const different = !std.mem.eql(u8, theme.light, theme.dark); - // Warning: loadTheme will deinit our existing config and replace - // it so all memory from self prior to this point will be freed. - try self.loadTheme(theme); + // Warning: loadTheme will deinit our existing config and replace + // it so all memory from self prior to this point will be freed. + try self.loadTheme(theme); - // If we have different light vs dark mode themes, disable - // window-theme = auto since that breaks it. - if (different) { - // This setting doesn't make sense with different light/dark themes - // because it'll force the theme based on the Ghostty theme. - if (self.@"window-theme" == .auto) self.@"window-theme" = .system; + // If we have different light vs dark mode themes, disable + // window-theme = auto since that breaks it. + if (different) { + // This setting doesn't make sense with different light/dark themes + // because it'll force the theme based on the Ghostty theme. + if (self.@"window-theme" == .auto) self.@"window-theme" = .system; + } } } diff --git a/src/config/theme.zig b/src/config/theme.zig index b851ec3d4..2ad5cd76d 100644 --- a/src/config/theme.zig +++ b/src/config/theme.zig @@ -39,7 +39,7 @@ pub const Location = enum { // error set since some platforms don't support some // error types. const Error = @TypeOf(err) || switch (builtin.os.tag) { - .ios => error{BufferTooSmall}, + .ios, .wasi => error{BufferTooSmall}, else => error{}, }; diff --git a/src/font/Collection.zig b/src/font/Collection.zig index f79c80936..5168b2dc8 100644 --- a/src/font/Collection.zig +++ b/src/font/Collection.zig @@ -659,6 +659,27 @@ pub const Index = packed struct(Index.Backing) { } }; +/// The wasm-compatible API. +pub const Wasm = struct { + const wasm = @import("../os/wasm.zig"); + const alloc = wasm.alloc; + export fn collection_new(points: f32) ?*Collection { + const result = alloc.create(Collection) catch |err| { + log.warn("error creating collection err={}", .{err}); + return null; + }; + result.* = Collection.init(); + result.load_options = .{ .library = Library.init() catch unreachable, .size = .{ .points = points } }; + return result; + } + export fn collection_add_deferred_face(self: *Collection, style: u8, face: *DeferredFace) u16 { + return @bitCast(self.add(alloc, @enumFromInt(style), .{ .deferred = face.* }) catch |err| { + log.warn("error adding deferred face to collection err={}", .{err}); + return 0; + }); + } +}; + test init { const testing = std.testing; const alloc = testing.allocator; diff --git a/src/font/DeferredFace.zig b/src/font/DeferredFace.zig index 3ee104386..757347cdf 100644 --- a/src/font/DeferredFace.zig +++ b/src/font/DeferredFace.zig @@ -163,6 +163,7 @@ pub fn load( lib: Library, opts: font.face.Options, ) !Face { + log.err("load {}", .{opts.size}); return switch (options.backend) { .fontconfig_freetype => try self.loadFontconfig(lib, opts), .coretext, .coretext_harfbuzz, .coretext_noshape => try self.loadCoreText(lib, opts), @@ -254,7 +255,7 @@ fn loadWebCanvas( opts: font.face.Options, ) !Face { const wc = self.wc.?; - return try Face.initNamed(wc.alloc, wc.font_str, opts, wc.presentation); + return try Face.initNamed(wc.alloc, wc.font_str, opts.size, wc.presentation); } /// Returns true if this face can satisfy the given codepoint and @@ -392,7 +393,7 @@ pub const Wasm = struct { } export fn deferred_face_load(self: *DeferredFace, pts: f32) void { - self.load(.{}, .{ .points = pts }) catch |err| { + _ = self.load(.{}, .{ .size = .{ .points = pts } }) catch |err| { log.warn("error loading deferred face err={}", .{err}); return; }; diff --git a/src/font/SharedGrid.zig b/src/font/SharedGrid.zig index 8af385b84..40a4f877b 100644 --- a/src/font/SharedGrid.zig +++ b/src/font/SharedGrid.zig @@ -322,6 +322,54 @@ const GlyphKey = struct { const TestMode = enum { normal }; +/// The wasm-compatible API. +pub const Wasm = struct { + const wasm = @import("../os/wasm.zig"); + const alloc = wasm.alloc; + export fn shared_grid_new(c: *Collection) ?*SharedGrid { + const result = alloc.create(SharedGrid) catch |err| { + log.warn("error creating SharedGrid err={}", .{err}); + return null; + }; + result.* = SharedGrid.init(wasm.alloc, .{ .collection = c.* }) catch |err| { + log.warn("error initializing SharedGrid err={}", .{err}); + return null; + }; + return result; + } + export fn shared_grid_atlas_grayscale(self: *SharedGrid) ?*Atlas { + return &self.atlas_grayscale; + } + export fn shared_grid_atlas_color(self: *SharedGrid) ?*Atlas { + return &self.atlas_color; + } + export fn shared_grid_index_for_codepoint(self: *SharedGrid, code: u32, style: u8, presentation: i8) ?*Collection.Index { + const get = self.getIndex(wasm.alloc, code, @enumFromInt(style), if (presentation < 0) null else @enumFromInt(presentation)) catch |err| { + log.warn("error getting SharedGrid index for codepoint err={}", .{err}); + return null; + }; + if (get) |thing| { + const index = wasm.alloc.create(Collection.Index) catch unreachable; + index.* = thing; + return index; + } + return null; + } + + export fn shared_grid_render_glyph(self: *SharedGrid, font_idx: *Collection.Index, code: u32, _: u8) void { + const glyph_index = glyph_index: { + if (font_idx.special()) |special| break :glyph_index switch (special) { + .sprite => code, + }; + self.lock.lockShared(); + defer self.lock.unlockShared(); + const face = self.resolver.collection.getFace(font_idx.*) catch unreachable; + break :glyph_index face.glyphIndex(code) orelse return; + }; + _ = self.renderGlyph(wasm.alloc, font_idx.*, glyph_index, .{}) catch unreachable; + } +}; + fn testGrid(mode: TestMode, alloc: Allocator, lib: Library) !SharedGrid { const testFont = font.embedded.regular; diff --git a/src/font/SharedGridSet.zig b/src/font/SharedGridSet.zig index ac2fcbf8a..a6bc66d63 100644 --- a/src/font/SharedGridSet.zig +++ b/src/font/SharedGridSet.zig @@ -255,42 +255,67 @@ fn collection( try c.completeStyles(self.alloc, config.@"font-synthetic-style"); // Our built-in font will be used as a backup - _ = try c.add( - self.alloc, - .regular, - .{ .fallback_loaded = try Face.init( - self.font_lib, - font.embedded.regular, - load_options.faceOptions(), - ) }, - ); - _ = try c.add( - self.alloc, - .bold, - .{ .fallback_loaded = try Face.init( - self.font_lib, - font.embedded.bold, - load_options.faceOptions(), - ) }, - ); - _ = try c.add( - self.alloc, - .italic, - .{ .fallback_loaded = try Face.init( - self.font_lib, - font.embedded.italic, - load_options.faceOptions(), - ) }, - ); - _ = try c.add( - self.alloc, - .bold_italic, - .{ .fallback_loaded = try Face.init( - self.font_lib, - font.embedded.bold_italic, - load_options.faceOptions(), - ) }, - ); + if (builtin.cpu.arch != .wasm32) { + _ = try c.add( + self.alloc, + .regular, + .{ .fallback_loaded = try Face.init( + self.font_lib, + font.embedded.regular, + load_options.faceOptions(), + ) }, + ); + _ = try c.add( + self.alloc, + .bold, + .{ .fallback_loaded = try Face.init( + self.font_lib, + font.embedded.bold, + load_options.faceOptions(), + ) }, + ); + _ = try c.add( + self.alloc, + .italic, + .{ .fallback_loaded = try Face.init( + self.font_lib, + font.embedded.italic, + load_options.faceOptions(), + ) }, + ); + _ = try c.add( + self.alloc, + .bold_italic, + .{ .fallback_loaded = try Face.init( + self.font_lib, + font.embedded.bold_italic, + load_options.faceOptions(), + ) }, + ); + } else { + const family = if (config.@"font-family".list.items.len > 0) config.@"font-family".list.items[0] else "monospace"; + + _ = try c.add( + self.alloc, + .regular, + .{ .fallback_loaded = try Face.initNamed( + self.alloc, + family, + load_options.size, + .text, + ) }, + ); + _ = try c.add( + self.alloc, + .regular, + .{ .fallback_loaded = try Face.initNamed( + self.alloc, + family, + load_options.size, + .emoji, + ) }, + ); + } // On macOS, always search for and add the Apple Emoji font // as our preferred emoji font for fallback. We do this in case @@ -314,7 +339,7 @@ fn collection( // Emoji fallback. We don't include this on Mac since Mac is expected // to always have the Apple Emoji available on the system. - if (comptime !builtin.target.isDarwin() or Discover == void) { + if (builtin.cpu.arch != .wasm32 and comptime !builtin.target.isDarwin() or Discover == void) { _ = try c.add( self.alloc, .regular, diff --git a/src/font/face/web_canvas.zig b/src/font/face/web_canvas.zig index 60846f350..48717eadc 100644 --- a/src/font/face/web_canvas.zig +++ b/src/font/face/web_canvas.zig @@ -29,9 +29,6 @@ pub const Face = struct { /// Metrics for this font face. These are useful for renderers. metrics: font.face.Metrics, - /// The canvas element that we will reuse to render glyphs - canvas: js.Object, - /// The map to store multi-codepoint grapheme clusters that are rendered. /// We use 1 above the maximum unicode codepoint up to the max 32-bit /// unsigned integer to store the "glyph index" for graphemes. @@ -58,20 +55,12 @@ pub const Face = struct { const font_str = try alloc.dupe(u8, raw); errdefer alloc.free(font_str); - // Create our canvas that we're going to continue to reuse. - const doc = try js.global.get(js.Object, "document"); - defer doc.deinit(); - const canvas = try doc.call(js.Object, "createElement", .{js.string("canvas")}); - errdefer canvas.deinit(); - var result = Face{ .alloc = alloc, .font_str = font_str, .size = size, .presentation = presentation, - .canvas = canvas, - // We're going to calculate these right after initialization. .metrics = undefined, }; @@ -89,7 +78,6 @@ pub const Face = struct { while (it.next()) |value| self.alloc.free(value.*); self.glyph_to_grapheme.deinit(self.alloc); } - self.canvas.deinit(); self.* = undefined; } @@ -232,7 +220,7 @@ pub const Face = struct { .height = render.height, // TODO: this can't be right .offset_x = 0, - .offset_y = 0, + .offset_y = render.y_offset, .atlas_x = region.x, .atlas_y = region.y, .advance_x = 0, @@ -262,8 +250,8 @@ pub const Face = struct { // pixel height but this is a more surefire way to get it. const height_metrics = try ctx.call(js.Object, "measureText", .{js.string("M_")}); defer height_metrics.deinit(); - const asc = try height_metrics.get(f32, "actualBoundingBoxAscent"); - const desc = try height_metrics.get(f32, "actualBoundingBoxDescent"); + const asc = try height_metrics.get(f32, "fontBoundingBoxAscent"); + const desc = try height_metrics.get(f32, "fontBoundingBoxDescent"); const cell_height = asc + desc; const cell_baseline = desc; @@ -291,13 +279,15 @@ pub const Face = struct { fn context(self: Face) !js.Object { // This will return the same context on subsequent calls so it // is important to reset it. - const ctx = try self.canvas.call(js.Object, "getContext", .{js.string("2d")}); + const canvas = try js.global.get(js.Object, "fontCanvas"); + defer canvas.deinit(); + const ctx = try canvas.call(js.Object, "getContext", .{js.string("2d")}); errdefer ctx.deinit(); // Clear the canvas { - const width = try self.canvas.get(f64, "width"); - const height = try self.canvas.get(f64, "height"); + const width = try canvas.get(f64, "width"); + const height = try canvas.get(f64, "height"); try ctx.call(void, "clearRect", .{ 0, 0, width, height }); } @@ -325,6 +315,27 @@ pub const Face = struct { return ctx; } + pub fn hasColor(_: *const Face) bool { + return true; + } + + pub fn isColorGlyph(self: *const Face, cp: u32) bool { + // Render the glyph + var render = self.renderGlyphInternal(self.alloc, cp) catch unreachable; + defer render.deinit(); + + // Inspect the image data for any non-zeros in the RGB value. + // NOTE(perf): this is an easy candidate for SIMD. + var i: usize = 0; + while (i < render.bitmap.len) : (i += 4) { + if (render.bitmap[i] > 0 or + render.bitmap[i + 1] > 0 or + render.bitmap[i + 2] > 0) return true; + } + + return false; + } + /// An internal (web-canvas-only) format for rendered glyphs /// since we do render passes in multiple different situations. const RenderedGlyph = struct { @@ -332,6 +343,7 @@ pub const Face = struct { metrics: js.Object, width: u32, height: u32, + y_offset: i32, bitmap: []u8, pub fn deinit(self: *RenderedGlyph) void { @@ -392,24 +404,34 @@ pub const Face = struct { // Height is our ascender + descender for this char const height = if (!broken_bbox) @as(u32, @intFromFloat(@ceil(asc + desc))) + 1 else width; + const ctx_temp = try self.context(); + try ctx_temp.set("textBaseline", js.string("top")); + // Get the width and height of the render + const metrics_2 = try measure_ctx.call(js.Object, "measureText", .{glyph_str}); + const top_desc = try metrics_2.get(f32, "actualBoundingBoxDescent") + 1; + const y_offset = @as(i32, @intCast(height)) - @as(i32, @intFromFloat(top_desc)); + ctx_temp.deinit(); + // Note: width and height both get "+ 1" added to them above. This // is important so that there is a 1px border around the glyph to avoid // any clipping in the atlas. // Resize canvas to match the glyph size exactly { - try self.canvas.set("width", width); - try self.canvas.set("height", height); + const canvas = try js.global.get(js.Object, "fontCanvas"); + defer canvas.deinit(); + try canvas.set("width", width); + try canvas.set("height", height); - const width_str = try std.fmt.allocPrint(alloc, "{d}px", .{width}); - defer alloc.free(width_str); - const height_str = try std.fmt.allocPrint(alloc, "{d}px", .{height}); - defer alloc.free(height_str); + // const width_str = try std.fmt.allocPrint(alloc, "{d}px", .{width}); + // defer alloc.free(width_str); + // const height_str = try std.fmt.allocPrint(alloc, "{d}px", .{height}); + // defer alloc.free(height_str); - const style = try self.canvas.get(js.Object, "style"); - defer style.deinit(); - try style.set("width", js.string(width_str)); - try style.set("height", js.string(height_str)); + // const style = try self.canvas.get(js.Object, "style"); + // defer style.deinit(); + // try style.set("width", js.string(width_str)); + // try style.set("height", js.string(height_str)); } // Reload our context since we resized the canvas @@ -484,6 +506,7 @@ pub const Face = struct { .width = width, .height = height, .bitmap = bitmap, + .y_offset = y_offset, }; } }; @@ -494,7 +517,7 @@ pub const Wasm = struct { const alloc = wasm.alloc; export fn face_new(ptr: [*]const u8, len: usize, pts: u16, p: u16) ?*Face { - return face_new_(ptr, len, pts, p) catch null; + return face_new_(ptr, len, @floatFromInt(pts), p) catch null; } fn face_new_(ptr: [*]const u8, len: usize, pts: f32, presentation: u16) !*Face { @@ -531,25 +554,25 @@ pub const Wasm = struct { }; } - export fn face_debug_canvas(face: *Face) void { - face_debug_canvas_(face) catch |err| { - log.warn("error adding debug canvas err={}", .{err}); - }; - } + // export fn face_debug_canvas(face: *Face) void { + // face_debug_canvas_(face) catch |err| { + // log.warn("error adding debug canvas err={}", .{err}); + // }; + // } - fn face_debug_canvas_(face: *Face) !void { - const doc = try js.global.get(js.Object, "document"); - defer doc.deinit(); + // fn face_debug_canvas_(face: *Face) !void { + // const doc = try js.global.get(js.Object, "document"); + // defer doc.deinit(); - const elem = try doc.call( - ?js.Object, - "getElementById", - .{js.string("face-canvas")}, - ) orelse return error.CanvasContainerNotFound; - defer elem.deinit(); + // const elem = try doc.call( + // ?js.Object, + // "getElementById", + // .{js.string("face-canvas")}, + // ) orelse return error.CanvasContainerNotFound; + // defer elem.deinit(); - try elem.call(void, "append", .{face.canvas}); - } + // try elem.call(void, "append", .{face.canvas}); + // } fn face_render_glyph_(face: *Face, atlas: *font.Atlas, codepoint: u32) !*font.Glyph { const glyph = try face.renderGlyph(alloc, atlas, codepoint, .{}); diff --git a/src/font/main.zig b/src/font/main.zig index 60e7593cb..413788c31 100644 --- a/src/font/main.zig +++ b/src/font/main.zig @@ -33,6 +33,8 @@ comptime { if (builtin.target.isWasm()) { _ = Atlas.Wasm; _ = DeferredFace.Wasm; + _ = SharedGrid.Wasm; + _ = @import("Collection.zig").Wasm; _ = face.web_canvas.Wasm; _ = shape.web_canvas.Wasm; } diff --git a/src/font/shaper/web_canvas.zig b/src/font/shaper/web_canvas.zig index f38ab885a..11b304da7 100644 --- a/src/font/shaper/web_canvas.zig +++ b/src/font/shaper/web_canvas.zig @@ -4,6 +4,7 @@ const Allocator = std.mem.Allocator; const ziglyph = @import("ziglyph"); const font = @import("../main.zig"); const terminal = @import("../../terminal/main.zig"); +const SharedGrid = font.SharedGrid; const log = std.log.scoped(.font_shaper); @@ -30,19 +31,19 @@ pub const Shaper = struct { alloc: Allocator, /// The shared memory used for shaping results. - cell_buf: []font.shape.Cell, + cell_buf: std.ArrayListUnmanaged(font.shape.Cell), /// The shared memory used for storing information about a run. run_buf: RunBuf, /// The cell_buf argument is the buffer to use for storing shaped results. /// This should be at least the number of columns in the terminal. - pub fn init(alloc: Allocator, opts: font.shape.Options) !Shaper { + pub fn init(alloc: Allocator, _: font.shape.Options) !Shaper { // Note: we do not support opts.font_features return Shaper{ .alloc = alloc, - .cell_buf = opts.cell_buf, + .cell_buf = .{}, .run_buf = .{}, }; } @@ -61,14 +62,16 @@ pub const Shaper = struct { /// for a Shaper struct since they share state. pub fn runIterator( self: *Shaper, - group: *font.GroupCache, - row: terminal.Screen.Row, + grid: *SharedGrid, + screen: *const terminal.Screen, + row: terminal.Pin, selection: ?terminal.Selection, cursor_x: ?usize, ) font.shape.RunIterator { return .{ .hooks = .{ .shaper = self }, - .group = group, + .grid = grid, + .screen = screen, .row = row, .selection = selection, .cursor_x = cursor_x, @@ -90,21 +93,22 @@ pub const Shaper = struct { const clusters = self.run_buf.items(.cluster); assert(codepoints.len == clusters.len); + self.cell_buf.clearRetainingCapacity(); switch (codepoints.len) { // Special cases: if we have no codepoints (is this possible?) // then our result is also an empty cell run. - 0 => return self.cell_buf[0..0], + 0 => return self.cell_buf.items[0..0], // If we have only 1 codepoint, then we assume that it is // a single grapheme and just let it through. At this point, // we can't have any more information to do anything else. 1 => { - self.cell_buf[0] = .{ + try self.cell_buf.append(self.alloc, .{ .x = @intCast(clusters[0]), .glyph_index = codepoints[0], - }; + }); - return self.cell_buf[0..1]; + return self.cell_buf.items[0..1]; }, else => {}, @@ -151,10 +155,10 @@ pub const Shaper = struct { switch (len) { // If we have only a single codepoint then just render it // as-is. - 1 => self.cell_buf[cur] = .{ + 1 => try self.cell_buf.append(self.alloc, .{ .x = @intCast(clusters[start]), .glyph_index = codepoints[start], - }, + }), // We must have multiple codepoints (see assert above). In // this case we UTF-8 encode the codepoints and send them @@ -190,13 +194,13 @@ pub const Shaper = struct { }; defer self.alloc.free(cluster); - var face = try run.group.group.faceFromIndex(run.font_index); + var face = try run.grid.resolver.collection.getFace(run.font_index); const index = try face.graphemeGlyphIndex(cluster); - self.cell_buf[cur] = .{ + try self.cell_buf.append(self.alloc, .{ .x = @intCast(clusters[start]), .glyph_index = index, - }; + }); }, } @@ -204,7 +208,7 @@ pub const Shaper = struct { cur += 1; } - return self.cell_buf[0..cur]; + return self.cell_buf.items[0..cur]; } /// The hooks for RunIterator. @@ -238,15 +242,12 @@ pub const Wasm = struct { const wasm = @import("../../os/wasm.zig"); const alloc = wasm.alloc; - export fn shaper_new(cap: usize) ?*Shaper { - return shaper_new_(cap) catch null; + export fn shaper_new() ?*Shaper { + return shaper_new_() catch null; } - fn shaper_new_(cap: usize) !*Shaper { - const cell_buf = try alloc.alloc(font.shape.Cell, cap); - errdefer alloc.free(cell_buf); - - var shaper = try Shaper.init(alloc, .{ .cell_buf = cell_buf }); + fn shaper_new_() !*Shaper { + var shaper = try Shaper.init(alloc, .{}); errdefer shaper.deinit(); const result = try alloc.create(Shaper); @@ -257,7 +258,6 @@ pub const Wasm = struct { export fn shaper_free(ptr: ?*Shaper) void { if (ptr) |v| { - alloc.free(v.cell_buf); v.deinit(); alloc.destroy(v); } @@ -266,45 +266,130 @@ pub const Wasm = struct { /// Runs a test to verify shaping works properly. export fn shaper_test( self: *Shaper, - group: *font.GroupCache, + grid: *SharedGrid, str: [*]const u8, len: usize, ) void { - shaper_test_(self, group, str[0..len]) catch |err| { + shaper_test_(self, grid, str[0..len]) catch |err| { log.warn("error during shaper test err={}", .{err}); }; } + const js = @import("zig-js"); - fn shaper_test_(self: *Shaper, group: *font.GroupCache, str: []const u8) !void { - // Create a terminal and print all our characters into it. - var term = try terminal.Terminal.init(alloc, self.cell_buf.len, 80); + fn createImageData(self: *font.Atlas) !js.Object { + // We need to draw pixels so this is format dependent. + const buf: []u8 = switch (self.format) { + // RGBA is the native ImageData format + .rgba => self.data, + + .grayscale => buf: { + // Convert from A8 to RGBA so every 4th byte is set to a value. + var buf: []u8 = try alloc.alloc(u8, self.data.len * 4); + errdefer alloc.free(buf); + @memset(buf, 0); + for (self.data, 0..) |value, i| { + buf[(i * 4) + 3] = value; + } + break :buf buf; + }, + + else => return error.UnsupportedAtlasFormat, + }; + defer if (buf.ptr != self.data.ptr) alloc.free(buf); + + // Create an ImageData from our buffer and then write it to the canvas + const image_data: js.Object = data: { + // Get our runtime memory + const mem = try js.runtime.get(js.Object, "memory"); + defer mem.deinit(); + const mem_buf = try mem.get(js.Object, "buffer"); + defer mem_buf.deinit(); + + // Create an array that points to our buffer + const arr = arr: { + const Uint8ClampedArray = try js.global.get(js.Object, "Uint8ClampedArray"); + defer Uint8ClampedArray.deinit(); + const arr = try Uint8ClampedArray.new(.{ mem_buf, buf.ptr, buf.len }); + if (!wasm.shared_mem) break :arr arr; + + // If we're sharing memory then we have to copy the data since + // we can't set ImageData directly using a SharedArrayBuffer. + defer arr.deinit(); + break :arr try arr.call(js.Object, "slice", .{}); + }; + defer arr.deinit(); + + // Create the image data from our array + const ImageData = try js.global.get(js.Object, "ImageData"); + defer ImageData.deinit(); + const data = try ImageData.new(.{ arr, self.size, self.size }); + errdefer data.deinit(); + + break :data data; + }; + + return image_data; + } + + fn shaper_test_(self: *Shaper, grid: *SharedGrid, str: []const u8) !void { + // Make a screen with some data + var term = try terminal.Terminal.init(alloc, .{ .cols = 20, .rows = 5 }); defer term.deinit(alloc); + try term.printString(str); - // Iterate over unicode codepoints and add to terminal - { - const view = try std.unicode.Utf8View.init(str); - var iter = view.iterator(); - while (iter.nextCodepoint()) |c| { - try term.print(c); + // Get our run iterator + + var row_it = term.screen.pages.rowIterator(.right_down, .{ .viewport = .{} }, null); + var y: usize = 0; + const Render = struct { + render: SharedGrid.Render, + y: usize, + x: usize, + }; + var cell_list: std.ArrayListUnmanaged(Render) = .{}; + defer cell_list.deinit(wasm.alloc); + while (row_it.next()) |row| { + defer y += 1; + var it = self.runIterator(grid, &term.screen, row, null, null); + while (try it.next(alloc)) |run| { + const cells = try self.shape(run); + for (cells) |cell| { + const render = try grid.renderGlyph(wasm.alloc, run.font_index, cell.glyph_index, .{}); + try cell_list.append(wasm.alloc, .{ .render = render, .x = cell.x, .y = y }); + + log.info("y={} x={} width={} height={} ax={} ay={} base={}", .{ + y * grid.metrics.cell_height, + cell.x * grid.metrics.cell_width, + render.glyph.width, + render.glyph.height, + render.glyph.atlas_x, + render.glyph.atlas_y, + grid.metrics.cell_baseline, + }); + } } } + const colour_data = try createImageData(&grid.atlas_color); + const gray_data = try createImageData(&grid.atlas_grayscale); - // Iterate over the rows and print out all the runs we get. - var rowIter = term.screen.rowIterator(.viewport); - var y: usize = 0; - while (rowIter.next()) |row| { - defer y += 1; - - var iter = self.runIterator(group, row, null, null); - while (try iter.next(alloc)) |run| { - const cells = try self.shape(run); - log.info("y={} run={d} shape={any} idx={}", .{ - y, - run.cells, - cells, - run.font_index, - }); - } + const doc = try js.global.get(js.Object, "document"); + defer doc.deinit(); + const canvas = try doc.call(js.Object, "getElementById", .{js.string("shaper-canvas")}); + errdefer canvas.deinit(); + const ctx = try canvas.call(js.Object, "getContext", .{js.string("2d")}); + defer ctx.deinit(); + for (cell_list.items) |cell| { + const x_start = -@as(isize, @intCast(cell.render.glyph.atlas_x)); + const y_start = -@as(isize, @intCast(cell.render.glyph.atlas_y)); + try ctx.call(void, "putImageData", .{ + if (cell.render.presentation == .emoji) colour_data else gray_data, + x_start + @as(isize, @intCast(cell.x * grid.metrics.cell_width)) - cell.render.glyph.offset_x, + y_start + @as(isize, @intCast(cell.y * grid.metrics.cell_height)) - cell.render.glyph.offset_y, + cell.render.glyph.atlas_x, + cell.render.glyph.atlas_y, + cell.render.glyph.width, + cell.render.glyph.height, + }); } } }; diff --git a/src/input/Link.zig b/src/input/Link.zig index adc52a270..a0b63f5dd 100644 --- a/src/input/Link.zig +++ b/src/input/Link.zig @@ -6,6 +6,7 @@ const Link = @This(); const oni = @import("oniguruma"); const Mods = @import("key.zig").Mods; +const builtin = @import("builtin"); /// The regular expression that will be used to match the link. Ownership /// of this memory is up to the caller. The link will never free this memory. diff --git a/src/inspector/main.zig b/src/inspector/main.zig index ee871f200..7b1747c05 100644 --- a/src/inspector/main.zig +++ b/src/inspector/main.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const builtin = @import("builtin"); pub const cell = @import("cell.zig"); pub const cursor = @import("cursor.zig"); pub const key = @import("key.zig"); @@ -6,7 +7,7 @@ pub const page = @import("page.zig"); pub const termio = @import("termio.zig"); pub const Cell = cell.Cell; -pub const Inspector = @import("Inspector.zig"); +pub const Inspector = if (builtin.cpu.arch != .wasm32) @import("Inspector.zig") else struct {}; test { @import("std").testing.refAllDecls(@This()); diff --git a/src/main_wasm.zig b/src/main_wasm.zig index bffe5e4b7..fcdb9b1ae 100644 --- a/src/main_wasm.zig +++ b/src/main_wasm.zig @@ -11,16 +11,79 @@ comptime { _ = @import("App.zig").Wasm; } -pub const std_options = struct { +const renderer = @import("renderer.zig"); +const Surface = @import("Surface.zig"); +const App = @import("App.zig"); +const apprt = @import("apprt.zig"); + +const wasm = @import("os/wasm.zig"); +const alloc = wasm.alloc; +const cli = @import("cli.zig"); +const Config = @import("config/Config.zig"); + +export fn run(str: [*]const u8, len: usize) void { + run_(str[0..len]) catch |err| { + std.log.err("err: {?}", .{err}); + }; +} + +var surf: ?*Surface = null; +export fn draw() void { + surf.?.renderer.drawFrame(surf.?.rt_surface) catch |err| { + std.log.err("err: {?}", .{err}); + }; +} + +fn run_(str: []const u8) !void { + var config = try Config.default(alloc); + var fbs = std.io.fixedBufferStream(str); + var iter = cli.args.lineIterator(fbs.reader()); + try config.loadIter(alloc, &iter); + try config.finalize(); + std.log.err("font-size {}", .{config.@"font-size"}); + const app = try App.create(alloc); + // Create our runtime app + var app_runtime = try apprt.App.init(app, .{}); + const surface = try alloc.create(Surface); + const apprt_surface = try alloc.create(apprt.Surface); + try surface.init(alloc, &config, app, &app_runtime, apprt_surface); + std.log.err("{}", .{surface.size}); + try surface.renderer.setScreenSize(surface.size); + surf = surface; + // const esc = "\x1b["; + // surface.io.processOutput("M_yhelloaaaaaaaaa\n\rπ\n\rππ½\n\rM_ghostty" ++ esc ++ "2;2H" ++ esc ++ "48;2;240;40;40m" ++ esc ++ "38;2;23;255;80mhello"); + // // try surface.renderer_state.terminal.printString("M_yhelloaaaaaaaaa\nπ\nππ½\nM_ghostty"); + // // surface.renderer_state.terminal.setCursorPos(4, 2); + // // try surface.renderer_state.terminal.setAttribute(.{ .direct_color_bg = .{ + // // .r = 240, + // // .g = 40, + // // .b = 40, + // // } }); + // // try surface.renderer_state.terminal.setAttribute(.{ .direct_color_fg = .{ + // // .r = 255, + // // .g = 255, + // // .b = 255, + // // } }); + // // try surface.renderer_state.terminal.printString("hello"); + // try surface.renderer.updateFrame(apprt_surface, &surface.renderer_state, false); + // try surface.renderer.drawFrame(apprt_surface); + // try surface.renderer.updateFrame(apprt_surface, &surface.renderer_state, false); + // try surface.renderer.drawFrame(apprt_surface); + + // // const webgl = try renderer.OpenGL.init(alloc, .{ .config = try renderer.OpenGL.DerivedConfig.init(alloc, &config) }); + // // _ = webgl; +} + +pub const std_options: std.Options = .{ // Set our log level. We try to get as much logging as possible but in // ReleaseSmall mode where we're optimizing for space, we elevate the // log level. - pub const log_level: std.log.Level = switch (builtin.mode) { + .log_level = switch (builtin.mode) { .Debug => .debug, .ReleaseSmall => .warn, else => .info, - }; + }, // Set our log function - pub const logFn = @import("os/wasm/log.zig").log; + .logFn = @import("os/wasm/log.zig").log, }; diff --git a/src/os/desktop.zig b/src/os/desktop.zig index 103127dfa..a2e5b61c3 100644 --- a/src/os/desktop.zig +++ b/src/os/desktop.zig @@ -56,6 +56,8 @@ pub fn launchedFromDesktop() bool { // iPhone/iPad is always launched from the "desktop" .ios => true, + .freestanding, .wasi => false, + else => @compileError("unsupported platform"), }; } diff --git a/src/os/homedir.zig b/src/os/homedir.zig index cf6931f22..b299563fb 100644 --- a/src/os/homedir.zig +++ b/src/os/homedir.zig @@ -20,6 +20,8 @@ pub inline fn home(buf: []u8) !?[]u8 { // iOS doesn't have a user-writable home directory .ios => null, + .wasi => null, + else => @compileError("unimplemented"), }; } diff --git a/src/os/hostname.zig b/src/os/hostname.zig index 22f29ceff..0a326c97a 100644 --- a/src/os/hostname.zig +++ b/src/os/hostname.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const builtin = @import("builtin"); const posix = std.posix; pub const HostnameParsingError = error{ @@ -57,6 +58,7 @@ pub const LocalHostnameValidationError = error{ Unexpected, }; +const HOST_NAME_MAX = (if (builtin.cpu.arch == .wasm32) 64 else posix.HOST_NAME_MAX); /// Checks if a hostname is local to the current machine. This matches /// both "localhost" and the current hostname of the machine (as returned /// by `gethostname`). @@ -65,7 +67,8 @@ pub fn isLocalHostname(hostname: []const u8) LocalHostnameValidationError!bool { if (std.mem.eql(u8, "localhost", hostname)) return true; // If hostname is not "localhost" it must match our hostname. - var buf: [posix.HOST_NAME_MAX]u8 = undefined; + if (builtin.cpu.arch == .wasm32) return false; + var buf: [HOST_NAME_MAX]u8 = undefined; const ourHostname = try posix.gethostname(&buf); return std.mem.eql(u8, hostname, ourHostname); } @@ -73,7 +76,7 @@ pub fn isLocalHostname(hostname: []const u8) LocalHostnameValidationError!bool { test "bufPrintHostnameFromFileUri succeeds with ascii hostname" { const uri = try std.Uri.parse("file://localhost/"); - var buf: [posix.HOST_NAME_MAX]u8 = undefined; + var buf: [HOST_NAME_MAX]u8 = undefined; const actual = try bufPrintHostnameFromFileUri(&buf, uri); try std.testing.expectEqualStrings("localhost", actual); } @@ -81,7 +84,7 @@ test "bufPrintHostnameFromFileUri succeeds with ascii hostname" { test "bufPrintHostnameFromFileUri succeeds with hostname as mac address" { const uri = try std.Uri.parse("file://12:34:56:78:90:12"); - var buf: [posix.HOST_NAME_MAX]u8 = undefined; + var buf: [HOST_NAME_MAX]u8 = undefined; const actual = try bufPrintHostnameFromFileUri(&buf, uri); try std.testing.expectEqualStrings("12:34:56:78:90:12", actual); } @@ -89,7 +92,7 @@ test "bufPrintHostnameFromFileUri succeeds with hostname as mac address" { test "bufPrintHostnameFromFileUri succeeds with hostname as a mac address and the last section is < 10" { const uri = try std.Uri.parse("file://12:34:56:78:90:05"); - var buf: [posix.HOST_NAME_MAX]u8 = undefined; + var buf: [HOST_NAME_MAX]u8 = undefined; const actual = try bufPrintHostnameFromFileUri(&buf, uri); try std.testing.expectEqualStrings("12:34:56:78:90:05", actual); } @@ -98,21 +101,21 @@ test "bufPrintHostnameFromFileUri returns only hostname when there is a port com // First: try with a non-2-digit port, to test general port handling. const four_port_uri = try std.Uri.parse("file://has-a-port:1234"); - var four_port_buf: [posix.HOST_NAME_MAX]u8 = undefined; + var four_port_buf: [HOST_NAME_MAX]u8 = undefined; const four_port_actual = try bufPrintHostnameFromFileUri(&four_port_buf, four_port_uri); try std.testing.expectEqualStrings("has-a-port", four_port_actual); // Second: try with a 2-digit port to test mac-address handling. const two_port_uri = try std.Uri.parse("file://has-a-port:12"); - var two_port_buf: [posix.HOST_NAME_MAX]u8 = undefined; + var two_port_buf: [HOST_NAME_MAX]u8 = undefined; const two_port_actual = try bufPrintHostnameFromFileUri(&two_port_buf, two_port_uri); try std.testing.expectEqualStrings("has-a-port", two_port_actual); // Third: try with a mac-address that has a port-component added to it to test mac-address handling. const mac_with_port_uri = try std.Uri.parse("file://12:34:56:78:90:12:1234"); - var mac_with_port_buf: [posix.HOST_NAME_MAX]u8 = undefined; + var mac_with_port_buf: [HOST_NAME_MAX]u8 = undefined; const mac_with_port_actual = try bufPrintHostnameFromFileUri(&mac_with_port_buf, mac_with_port_uri); try std.testing.expectEqualStrings("12:34:56:78:90:12", mac_with_port_actual); } @@ -120,7 +123,7 @@ test "bufPrintHostnameFromFileUri returns only hostname when there is a port com test "bufPrintHostnameFromFileUri returns NoHostnameInUri error when hostname is missing from uri" { const uri = try std.Uri.parse("file:///"); - var buf: [posix.HOST_NAME_MAX]u8 = undefined; + var buf: [HOST_NAME_MAX]u8 = undefined; const actual = bufPrintHostnameFromFileUri(&buf, uri); try std.testing.expectError(HostnameParsingError.NoHostnameInUri, actual); } @@ -138,7 +141,7 @@ test "isLocalHostname returns true when provided hostname is localhost" { } test "isLocalHostname returns true when hostname is local" { - var buf: [posix.HOST_NAME_MAX]u8 = undefined; + var buf: [HOST_NAME_MAX]u8 = undefined; const localHostname = try posix.gethostname(&buf); try std.testing.expect(try isLocalHostname(localHostname)); } diff --git a/src/os/main.zig b/src/os/main.zig index 22765f546..796b27536 100644 --- a/src/os/main.zig +++ b/src/os/main.zig @@ -13,6 +13,8 @@ const mouse = @import("mouse.zig"); const openpkg = @import("open.zig"); const pipepkg = @import("pipe.zig"); const resourcesdir = @import("resourcesdir.zig"); +const builtin = @import("builtin"); +const std = @import("std"); // Namespaces pub const args = @import("args.zig"); diff --git a/src/pty.zig b/src/pty.zig index c0d082411..f282073de 100644 --- a/src/pty.zig +++ b/src/pty.zig @@ -18,6 +18,7 @@ pub const winsize = extern struct { pub const Pty = switch (builtin.os.tag) { .windows => WindowsPty, .ios => NullPty, + .freestanding, .wasi => NullPty, else => PosixPty, }; @@ -41,7 +42,7 @@ pub const Mode = packed struct { // a termio that doesn't use a pty. This isn't used in any user-facing // artifacts, this is just a stopgap to get compilation to work on iOS. const NullPty = struct { - pub const Fd = posix.fd_t; + pub const Fd = i32; master: Fd, slave: Fd, diff --git a/src/renderer.zig b/src/renderer.zig index d968ab4df..9c88a0632 100644 --- a/src/renderer.zig +++ b/src/renderer.zig @@ -44,7 +44,7 @@ pub const Impl = enum { ) Impl { if (target.cpu.arch == .wasm32) { return switch (wasm_target) { - .browser => .webgl, + .browser => .opengl, }; } diff --git a/src/renderer/OpenGL.zig b/src/renderer/OpenGL.zig index 481f5b0db..d745d7674 100644 --- a/src/renderer/OpenGL.zig +++ b/src/renderer/OpenGL.zig @@ -460,6 +460,9 @@ pub fn surfaceInit(surface: *apprt.Surface) !void { // to compile for OpenGL targets but libghostty is strictly // broken for rendering on this platforms. }, + apprt.browser => { + gl.glad.context.init(); + }, } // These are very noisy so this is commented, but easy to uncomment @@ -574,6 +577,10 @@ pub fn threadEnter(self: *const OpenGL, surface: *apprt.Surface) !void { // to compile for OpenGL targets but libghostty is strictly // broken for rendering on this platforms. }, + apprt.browser => { + log.err("context init", .{}); + gl.glad.context.init(); + }, } } @@ -597,6 +604,7 @@ pub fn threadExit(self: *const OpenGL) void { apprt.embedded => { // TODO: see threadEnter }, + apprt.browser => {}, } } @@ -675,6 +683,7 @@ pub fn updateFrame( ) !void { _ = surface; + std.log.err("update frame", .{}); // Data we extract out of the critical area. const Critical = struct { full_rebuild: bool, @@ -693,6 +702,7 @@ pub fn updateFrame( state.mutex.lock(); defer state.mutex.unlock(); + std.log.err("critical", .{}); // If we're in a synchronized output state, we pause all rendering. if (state.terminal.modes.get(.synchronized_output)) { @@ -2219,7 +2229,14 @@ fn flushAtlasSingle( /// the cells. pub fn drawFrame(self: *OpenGL, surface: *apprt.Surface) !void { // If we're in single-threaded more we grab a lock since we use shared data. - if (single_threaded_draw) self.draw_mutex.lock(); + // wasm can't lock a mutex on the main thread because it uses Atomic.wait + if (single_threaded_draw) { + if (builtin.cpu.arch == .wasm32) { + if (!self.draw_mutex.tryLock()) return; + } else { + self.draw_mutex.lock(); + } + } defer if (single_threaded_draw) self.draw_mutex.unlock(); const gl_state: *GLState = if (self.gl_state) |*v| v else return; @@ -2278,6 +2295,7 @@ pub fn drawFrame(self: *OpenGL, surface: *apprt.Surface) !void { apprt.glfw => surface.window.swapBuffers(), apprt.gtk => {}, apprt.embedded => {}, + apprt.browser => {}, else => @compileError("unsupported runtime"), } } @@ -2473,10 +2491,10 @@ fn drawCells( // Our allocated buffer on the GPU is smaller than our capacity. // We reallocate a new buffer with the full new capacity. if (self.gl_cells_size < cells.capacity) { - log.info("reallocating GPU buffer old={} new={}", .{ - self.gl_cells_size, - cells.capacity, - }); + // log.info("reallocating GPU buffer old={} new={}", .{ + // self.gl_cells_size, + // cells.capacity, + // }); try bind.vbo.setDataNullManual( @sizeOf(CellProgram.Cell) * cells.capacity, @@ -2526,7 +2544,7 @@ const GLState = struct { const arena_alloc = arena.allocator(); // Load our custom shaders - const custom_state: ?custom.State = custom: { + const custom_state: ?custom.State = if (builtin.cpu.arch == .wasm32) null else custom: { const shaders: []const [:0]const u8 = shadertoy.loadFromFiles( arena_alloc, config.custom_shaders, diff --git a/src/renderer/Thread.zig b/src/renderer/Thread.zig index 91e355480..acf6a9baf 100644 --- a/src/renderer/Thread.zig +++ b/src/renderer/Thread.zig @@ -232,7 +232,7 @@ fn threadMain_(self: *Thread) !void { self.startDrawTimer(); // Run - log.debug("starting renderer thread", .{}); + log.err("starting renderer thread", .{}); defer log.debug("starting renderer thread shutdown", .{}); _ = try self.loop.run(.until_done); } @@ -437,6 +437,7 @@ fn wakeupCallback( }; const t = self_.?; + log.err("wakeup", .{}); // When we wake up, we check the mailbox. Mailbox producers should // wake up our thread after publishing. diff --git a/src/renderer/opengl/image.zig b/src/renderer/opengl/image.zig index 85f59f1f3..599363ff6 100644 --- a/src/renderer/opengl/image.zig +++ b/src/renderer/opengl/image.zig @@ -3,6 +3,7 @@ const Allocator = std.mem.Allocator; const assert = std.debug.assert; const gl = @import("opengl"); const wuffs = @import("wuffs"); +const internal_os = @import("../../os/main.zig"); /// Represents a single image placement on the grid. A placement is a /// request to render an instance of an image. diff --git a/src/renderer/shaders/cell.f.glsl b/src/renderer/shaders/cell.f.glsl index f9c1ce2b1..e9982144b 100644 --- a/src/renderer/shaders/cell.f.glsl +++ b/src/renderer/shaders/cell.f.glsl @@ -1,27 +1,27 @@ -#version 330 core +#version 300 es -in vec2 glyph_tex_coords; +in mediump vec2 glyph_tex_coords; flat in uint mode; // The color for this cell. If this is a background pass this is the // background color. Otherwise, this is the foreground color. -flat in vec4 color; +flat in mediump vec4 color; // The position of the cells top-left corner. -flat in vec2 screen_cell_pos; +flat in mediump vec2 screen_cell_pos; // Position the fragment coordinate to the upper left -layout(origin_upper_left) in vec4 gl_FragCoord; +// layout(origin_upper_left) in vec4 gl_FragCoord; // Must declare this output for some versions of OpenGL. -layout(location = 0) out vec4 out_FragColor; +out mediump vec4 out_FragColor; // Font texture uniform sampler2D text; uniform sampler2D text_color; // Dimensions of the cell -uniform vec2 cell_size; +uniform highp vec2 cell_size; // See vertex shader const uint MODE_BG = 1u; @@ -31,7 +31,7 @@ const uint MODE_FG_COLOR = 7u; const uint MODE_FG_POWERLINE = 15u; void main() { - float a; + highp float a; switch (mode) { case MODE_BG: @@ -42,7 +42,7 @@ void main() { case MODE_FG_CONSTRAINED: case MODE_FG_POWERLINE: a = texture(text, glyph_tex_coords).r; - vec3 premult = color.rgb * color.a; + highp vec3 premult = color.rgb * color.a; out_FragColor = vec4(premult.rgb*a, a); break; diff --git a/src/renderer/shaders/cell.v.glsl b/src/renderer/shaders/cell.v.glsl index 942b7ac44..3b68eb3ed 100644 --- a/src/renderer/shaders/cell.v.glsl +++ b/src/renderer/shaders/cell.v.glsl @@ -1,4 +1,4 @@ -#version 330 core +#version 300 es // These are the possible modes that "mode" can be set to. This is // used to multiplex multiple render modes into a single shader. @@ -11,33 +11,33 @@ const uint MODE_FG_COLOR = 7u; const uint MODE_FG_POWERLINE = 15u; // The grid coordinates (x, y) where x < columns and y < rows -layout (location = 0) in vec2 grid_coord; +in vec2 grid_coord; // Position of the glyph in the texture. -layout (location = 1) in vec2 glyph_pos; +in vec2 glyph_pos; // Width/height of the glyph -layout (location = 2) in vec2 glyph_size; +in vec2 glyph_size; // Offset of the top-left corner of the glyph when rendered in a rect. -layout (location = 3) in vec2 glyph_offset; +in vec2 glyph_offset; // The color for this cell in RGBA (0 to 1.0). Background or foreground // depends on mode. -layout (location = 4) in vec4 color_in; +in vec4 color_in; // Only set for MODE_FG, this is the background color of the FG text. // This is used to detect minimal contrast for the text. -layout (location = 5) in vec4 bg_color_in; +in vec4 bg_color_in; // The mode of this shader. The mode determines what fields are used, // what the output will be, etc. This shader is capable of executing in // multiple "modes" so that we can share some logic and so that we can draw // the entire terminal grid in a single GPU pass. -layout (location = 6) in uint mode_in; +in uint mode_in; // The width in cells of this item. -layout (location = 7) in uint grid_width; +in uint grid_width; // The background or foreground color for the fragment, depending on // whether this is a background or foreground pass. @@ -168,22 +168,22 @@ void main() { // Scaled for wide chars vec2 cell_size_scaled = cell_size; - cell_size_scaled.x = cell_size_scaled.x * grid_width; + cell_size_scaled.x = cell_size_scaled.x * float(grid_width); switch (mode) { case MODE_BG: // If we're at the edge of the grid, we add our padding to the background // to extend it. Note: grid_padding is top/right/bottom/left. - if (grid_coord.y == 0 && padding_vertical_top) { + if (grid_coord.y == 0. && padding_vertical_top) { cell_pos.y -= grid_padding.r; cell_size_scaled.y += grid_padding.r; - } else if (grid_coord.y == grid_size.y - 1 && padding_vertical_bottom) { + } else if (grid_coord.y == grid_size.y - 1. && padding_vertical_bottom) { cell_size_scaled.y += grid_padding.b; } - if (grid_coord.x == 0) { + if (grid_coord.x == 0.) { cell_pos.x -= grid_padding.a; cell_size_scaled.x += grid_padding.a; - } else if (grid_coord.x == grid_size.x - 1) { + } else if (grid_coord.x == grid_size.x - 1.) { cell_size_scaled.x += grid_padding.g; } @@ -205,7 +205,7 @@ void main() { // The glyph_offset.y is the y bearing, a y value that when added // to the baseline is the offset (+y is up). Our grid goes down. // So we flip it with `cell_size.y - glyph_offset.y`. - glyph_offset_calc.y = cell_size_scaled.y - glyph_offset_calc.y; + glyph_offset_calc.y = -glyph_offset_calc.y; // If this is a constrained mode, we need to constrain it! // We also always constrain colored glyphs since we should have @@ -214,7 +214,7 @@ void main() { if (mode == MODE_FG_CONSTRAINED || mode == MODE_FG_COLOR) { if (glyph_size.x > cell_size_scaled.x) { float new_y = glyph_size.y * (cell_size_scaled.x / glyph_size.x); - glyph_offset_calc.y = glyph_offset_calc.y + ((glyph_size.y - new_y) / 2); + glyph_offset_calc.y = glyph_offset_calc.y + ((glyph_size.y - new_y) / 2.); glyph_size_calc.y = new_y; glyph_size_calc.x = cell_size_scaled.x; } @@ -238,8 +238,8 @@ void main() { text_size = textureSize(text_color, 0); break; } - vec2 glyph_tex_pos = glyph_pos / text_size; - vec2 glyph_tex_size = glyph_size / text_size; + vec2 glyph_tex_pos = glyph_pos / vec2(text_size); + vec2 glyph_tex_size = glyph_size / vec2(text_size); glyph_tex_coords = glyph_tex_pos + glyph_tex_size * position; // If we have a minimum contrast, we need to check if we need to diff --git a/src/renderer/shaders/custom.v.glsl b/src/renderer/shaders/custom.v.glsl index 653e1800e..4e553ae3f 100644 --- a/src/renderer/shaders/custom.v.glsl +++ b/src/renderer/shaders/custom.v.glsl @@ -1,4 +1,4 @@ -#version 330 core +#version 300 es void main(){ vec2 position; diff --git a/src/renderer/shaders/image.f.glsl b/src/renderer/shaders/image.f.glsl index e8c00b271..4ff7aaf58 100644 --- a/src/renderer/shaders/image.f.glsl +++ b/src/renderer/shaders/image.f.glsl @@ -1,12 +1,12 @@ -#version 330 core +#version 300 es -in vec2 tex_coord; +in mediump vec2 tex_coord; -layout(location = 0) out vec4 out_FragColor; +out mediump vec4 out_FragColor; uniform sampler2D image; void main() { - vec4 color = texture(image, tex_coord); + mediump vec4 color = texture(image, tex_coord); out_FragColor = vec4(color.rgb * color.a, color.a); } diff --git a/src/renderer/shaders/image.v.glsl b/src/renderer/shaders/image.v.glsl index e3d07ca9e..0c7ded6da 100644 --- a/src/renderer/shaders/image.v.glsl +++ b/src/renderer/shaders/image.v.glsl @@ -1,9 +1,9 @@ -#version 330 core +#version 300 es -layout (location = 0) in vec2 grid_pos; -layout (location = 1) in vec2 cell_offset; -layout (location = 2) in vec4 source_rect; -layout (location = 3) in vec2 dest_size; +in vec2 grid_pos; +in vec2 cell_offset; +in vec4 source_rect; +in vec2 dest_size; out vec2 tex_coord; @@ -13,7 +13,7 @@ uniform mat4 projection; void main() { // The size of the image in pixels - vec2 image_size = textureSize(image, 0); + vec2 image_size = vec2(textureSize(image, 0)); // Turn the cell position into a vertex point depending on the // gl_VertexID. Since we use instanced drawing, we have 4 vertices diff --git a/src/terminal/Parser.zig b/src/terminal/Parser.zig index 9aebdbd3a..68e68816f 100644 --- a/src/terminal/Parser.zig +++ b/src/terminal/Parser.zig @@ -328,8 +328,14 @@ fn doAction(self: *Parser, action: TransitionAction, c: u8) ?Action { } // A numeric value. Add it to our accumulator. - if (self.param_acc_idx > 0) { - self.param_acc *|= 10; + if (builtin.cpu.arch == .wasm32) { + if (self.param_acc_idx > 0) { + self.param_acc *= 10; + } + } else { + if (self.param_acc_idx > 0) { + self.param_acc *|= 10; + } } self.param_acc +|= c - '0'; diff --git a/src/terminal/kitty/graphics_image.zig b/src/terminal/kitty/graphics_image.zig index 931d068f9..f13b571f4 100644 --- a/src/terminal/kitty/graphics_image.zig +++ b/src/terminal/kitty/graphics_image.zig @@ -108,7 +108,7 @@ pub const LoadingImage = struct { path: []const u8, ) !void { // windows is currently unsupported, does it support shm? - if (comptime builtin.target.os.tag == .windows) { + if (comptime builtin.target.os.tag == .windows or builtin.cpu.arch == .wasm32) { return error.UnsupportedMedium; } diff --git a/src/terminal/kitty/graphics_storage.zig b/src/terminal/kitty/graphics_storage.zig index bf8633c88..9bfea0ebb 100644 --- a/src/terminal/kitty/graphics_storage.zig +++ b/src/terminal/kitty/graphics_storage.zig @@ -4,6 +4,7 @@ const Allocator = std.mem.Allocator; const ArenaAllocator = std.heap.ArenaAllocator; const terminal = @import("../main.zig"); +const internal_os = @import("../../os/main.zig"); const point = @import("../point.zig"); const size = @import("../size.zig"); const command = @import("graphics_command.zig"); diff --git a/src/terminal/osc.zig b/src/terminal/osc.zig index 34bc46745..0dcbd580b 100644 --- a/src/terminal/osc.zig +++ b/src/terminal/osc.zig @@ -11,6 +11,7 @@ const assert = std.debug.assert; const Allocator = mem.Allocator; const RGB = @import("color.zig").RGB; const kitty = @import("kitty.zig"); +const builtin = @import("builtin"); const log = std.log.scoped(.osc); @@ -871,7 +872,11 @@ pub const Parser = struct { self.complete = true; const idx = self.buf_idx - self.buf_start; - if (idx > 0) self.temp_state.num *|= 10; + if (builtin.cpu.arch == .wasm32) { + if (idx > 0) self.temp_state.num *= 10; + } else { + if (idx > 0) self.temp_state.num *|= 10; + } self.temp_state.num +|= c - '0'; }, ';' => { diff --git a/src/terminal/page.zig b/src/terminal/page.zig index 8c470d726..5cc24d01f 100644 --- a/src/terminal/page.zig +++ b/src/terminal/page.zig @@ -320,7 +320,7 @@ pub const Page = struct { /// when runtime safety is enabled. This is a no-op when runtime /// safety is disabled. This uses the libc allocator. pub fn assertIntegrity(self: *const Page) void { - if (comptime build_config.slow_runtime_safety) { + if (comptime build_config.slow_runtime_safety and builtin.cpu.arch != .wasm32) { self.verifyIntegrity(std.heap.c_allocator) catch |err| { log.err("page integrity violation, crashing. err={}", .{err}); @panic("page integrity violation"); diff --git a/src/terminal/stream.zig b/src/terminal/stream.zig index b8d60a13f..c0452a4e9 100644 --- a/src/terminal/stream.zig +++ b/src/terminal/stream.zig @@ -13,6 +13,7 @@ const osc = @import("osc.zig"); const sgr = @import("sgr.zig"); const UTF8Decoder = @import("UTF8Decoder.zig"); const MouseShape = @import("mouse_shape.zig").MouseShape; +const builtin = @import("builtin"); const log = std.log.scoped(.stream); @@ -242,8 +243,13 @@ pub fn Stream(comptime Handler: type) type { 0x18, 0x1A => self.parser.state = .ground, // A parameter digit: '0'...'9' => if (self.parser.params_idx < 16) { - self.parser.param_acc *|= 10; - self.parser.param_acc +|= c - '0'; + if (builtin.cpu.arch == .wasm32) { + self.parser.param_acc *= 10; + self.parser.param_acc += c - '0'; + } else { + self.parser.param_acc *|= 10; + self.parser.param_acc +|= c - '0'; + } // The parser's CSI param action uses param_acc_idx // to decide if there's a final param that needs to // be consumed or not, but it doesn't matter really diff --git a/src/termio/Exec.zig b/src/termio/Exec.zig index 07aa43c42..e1347e37c 100644 --- a/src/termio/Exec.zig +++ b/src/termio/Exec.zig @@ -126,7 +126,7 @@ pub fn threadEnter( // Start our read thread const read_thread = try std.Thread.spawn( - .{}, + .{ .allocator = alloc }, if (builtin.os.tag == .windows) ReadThread.threadMainWindows else ReadThread.threadMainPosix, .{ pty_fds.read, io, pipe[0] }, ); @@ -686,11 +686,18 @@ const Subprocess = struct { /// a potential execution on the host. const FlatpakHostCommand = if (build_config.flatpak) internal_os.FlatpakHostCommand else void; - const c = @cImport({ + const c = if (builtin.cpu.arch != .wasm32) @cImport({ @cInclude("errno.h"); @cInclude("signal.h"); @cInclude("unistd.h"); - }); + }) else struct { + pub const pid_t = Command.PidT; + pub const ESRCH = 0x03; + pub fn getpgid(pid: pid_t) pid_t { + _ = pid; + return 100; + } + }; arena: std.heap.ArenaAllocator, cwd: ?[]const u8, @@ -744,7 +751,7 @@ const Subprocess = struct { // Assume that the resources directory is adjacent to the terminfo // database - var buf: [std.fs.max_path_bytes]u8 = undefined; + var buf: [if (builtin.cpu.arch == .wasm32) 4096 else std.fs.max_path_bytes]u8 = undefined; const dir = try std.fmt.bufPrint(&buf, "{s}/terminfo", .{ std.fs.path.dirname(base) orelse unreachable, }); @@ -762,8 +769,8 @@ const Subprocess = struct { // Add our binary to the path if we can find it. ghostty_path: { - var exe_buf: [std.fs.max_path_bytes]u8 = undefined; - const exe_bin_path = std.fs.selfExePath(&exe_buf) catch |err| { + var exe_buf: [if (builtin.cpu.arch == .wasm32) 4096 else std.fs.max_path_bytes]u8 = undefined; + const exe_bin_path = if (builtin.cpu.arch == .wasm32) "ghostty-wasm.wasm" else std.fs.selfExePath(&exe_buf) catch |err| { log.warn("failed to get ghostty exe path err={}", .{err}); break :ghostty_path; }; @@ -848,6 +855,7 @@ const Subprocess = struct { // Setup our shell integration, if we can. const integrated_shell: ?shell_integration.Shell, const shell_command: []const u8 = shell: { + if (builtin.cpu.arch == .wasm32) break :shell .{ null, "" }; const default_shell_command = cfg.command orelse switch (builtin.os.tag) { .windows => "cmd.exe", else => "sh", @@ -1247,6 +1255,7 @@ const Subprocess = struct { _ = try command.wait(false); }, + .freestanding, .wasi => {}, else => if (getpgid(pid)) |pgid| { // It is possible to send a killpg between the time that @@ -1415,6 +1424,7 @@ pub const ReadThread = struct { // child process dies. To be safe, we just break the loop // and let our poll happen. if (n == 0) break; + std.log.err("{} {} {}", .{ buf[0], n, @intFromPtr(&buf) }); // log.info("DATA: {d}", .{n}); @call(.always_inline, termio.Termio.processOutput, .{ io, buf[0..n] }); diff --git a/src/termio/Termio.zig b/src/termio/Termio.zig index e7b391419..273ce1d96 100644 --- a/src/termio/Termio.zig +++ b/src/termio/Termio.zig @@ -554,6 +554,7 @@ fn processOutputLocked(self: *Termio, buf: []const u8) void { // use a timer under the covers if (std.time.Instant.now()) |now| cursor_reset: { if (self.last_cursor_reset) |last| { + log.err("now: {} last: {}", .{ now, last }); if (now.since(last) <= (500 * std.time.ns_per_ms)) { break :cursor_reset; } @@ -571,18 +572,24 @@ fn processOutputLocked(self: *Termio, buf: []const u8) void { // process a byte at a time alternating between the inspector handler // and the termio handler. This is very slow compared to our optimizations // below but at least users only pay for it if they're using the inspector. - if (self.renderer_state.inspector) |insp| { - for (buf, 0..) |byte, i| { - insp.recordPtyRead(buf[i .. i + 1]) catch |err| { - log.err("error recording pty read in inspector err={}", .{err}); - }; - - self.terminal_stream.next(byte) catch |err| - log.err("error processing terminal data: {}", .{err}); - } - } else { + std.log.err("to print {s}", .{buf}); + if (builtin.cpu.arch == .wasm32) { self.terminal_stream.nextSlice(buf) catch |err| log.err("error processing terminal data: {}", .{err}); + } else { + if (self.renderer_state.inspector) |insp| { + for (buf, 0..) |byte, i| { + insp.recordPtyRead(buf[i .. i + 1]) catch |err| { + log.err("error recording pty read in inspector err={}", .{err}); + }; + + self.terminal_stream.next(byte) catch |err| + log.err("error processing terminal data: {}", .{err}); + } + } else { + self.terminal_stream.nextSlice(buf) catch |err| + log.err("error processing terminal data: {}", .{err}); + } } // If our stream handling caused messages to be sent to the mailbox diff --git a/src/termio/stream_handler.zig b/src/termio/stream_handler.zig index 2fc9e92af..cc2dd20f2 100644 --- a/src/termio/stream_handler.zig +++ b/src/termio/stream_handler.zig @@ -1102,7 +1102,7 @@ pub const StreamHandler = struct { // See https://www.rfc-editor.org/rfc/rfc793#section-3.1. const PORT_NUMBER_MAX_DIGITS = 5; // Make sure there is space for a max length hostname + the max number of digits. - var host_and_port_buf: [posix.HOST_NAME_MAX + PORT_NUMBER_MAX_DIGITS]u8 = undefined; + var host_and_port_buf: [(if (builtin.cpu.arch == .wasm32) 64 else posix.HOST_NAME_MAX) + PORT_NUMBER_MAX_DIGITS]u8 = undefined; const hostname_from_uri = internal_os.hostname.bufPrintHostnameFromFileUri( &host_and_port_buf, uri,