summaryrefslogtreecommitdiff
path: root/src/main.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-07-05 20:21:50 -0300
committerGabriel Schneider <[email protected]>2026-08-01 15:02:07 -0300
commitde4def3548a6729b0dfd2120495a61beef8c8c2c (patch)
tree12144f0f64dc96bb4741459c1f9db57f44349330 /src/main.zig
parent7988d9bc6e31210ff13994f18d5622dd57ba9341 (diff)
downloadpardes-de4def3548a6729b0dfd2120495a61beef8c8c2c.tar.gz
pardes-de4def3548a6729b0dfd2120495a61beef8c8c2c.zip
pardes v2: the rewrite, complete and organized. src/ (core + three shells), test/ (snapshot parity harness + 18 frozen goldens). One sans-IO core, vaxis tty + SDL3 GPU native + wasm web shells, 18/18 parity with the purged prototype, 7.6k lines vs 12.1k. Fix: gui shell pre-sized the core at init so the greet-releasing resize never fired (blank panes until first interaction); live sessions now init at defaults and get the real grid as a resize event (the shell contract, documented on Options).
Diffstat (limited to 'src/main.zig')
-rw-r--r--src/main.zig102
1 files changed, 102 insertions, 0 deletions
diff --git a/src/main.zig b/src/main.zig
new file mode 100644
index 00000000..ff151323
--- /dev/null
+++ b/src/main.zig
@@ -0,0 +1,102 @@
+const std = @import("std");
+const builtin = @import("builtin");
+const pardes = @import("pardes.zig");
+
+const is_emscripten = builtin.os.tag == .emscripten;
+
+extern "c" fn emscripten_console_error(utf8: [*:0]const u8) void;
+
+// emscripten: std.debug's default threaded-io singleton doesn't run on wasm;
+// fail it (init errors surface via emscripten_console_error below). Native
+// values match the std defaults. Same shim as the prototype's replay.zig.
+pub const std_options_debug_threaded_io: ?*std.Io.Threaded = if (is_emscripten)
+ null
+else
+ std.Io.Threaded.global_single_threaded;
+pub const std_options_debug_io: std.Io = if (is_emscripten)
+ std.Io.failing
+else
+ std_options_debug_threaded_io.?.io();
+
+const help_text =
+ \\Usage: pardes [options]
+ \\
+ \\Options:
+ \\ --tty start as one shell pane already in tty mode
+ \\ --tty-toggle <key> use Ctrl-<key> to enter/leave tty mode
+ \\ -l <dump.zon> load a dump of another instance (see Dump)
+ \\ -h, --help show this help and exit
+ \\
+;
+
+// The browser runtime calls a C main (exported below); everything else keeps
+// the std.process.Init entry.
+pub const main = if (is_emscripten) webMain else nativeMain;
+
+comptime {
+ if (is_emscripten) @export(&emscriptenMain, .{ .name = "main" });
+}
+
+fn emscriptenMain(argc: c_int, argv: [*]?[*:0]u8) callconv(.c) c_int {
+ _ = argc;
+ _ = argv;
+ webMain() catch |err| {
+ var buf: [128]u8 = undefined;
+ const msg = std.fmt.bufPrintSentinel(&buf, "pardes web init failed: {t}", .{err}, 0) catch "pardes web init failed";
+ emscripten_console_error(msg.ptr);
+ return 1;
+ };
+ return 0;
+}
+
+// no argv in the browser: options stay default, state comes from the dump
+fn webMain() !void {
+ try @import("gui.zig").run(.{});
+}
+
+fn nativeMain(init: std.process.Init) !void {
+ var opts: pardes.Options = .{};
+ const args = try init.minimal.args.toSlice(init.arena.allocator());
+ var i: usize = 1;
+ while (i < args.len) : (i += 1) {
+ const a = args[i];
+ if (std.mem.eql(u8, a, "--tty")) {
+ opts.tty_only = true;
+ } else if (std.mem.startsWith(u8, a, "--tty-toggle=")) {
+ opts.tty_toggle = parseCtrlKey(a["--tty-toggle=".len..]) orelse return error.BadArgs;
+ } else if (std.mem.eql(u8, a, "--tty-toggle")) {
+ i += 1;
+ if (i >= args.len) return error.BadArgs;
+ opts.tty_toggle = parseCtrlKey(args[i]) orelse return error.BadArgs;
+ } else if (std.mem.eql(u8, a, "-l")) {
+ i += 1;
+ if (i >= args.len) return error.BadArgs;
+ opts.load_path = args[i];
+ } else if (std.mem.eql(u8, a, "-h") or std.mem.eql(u8, a, "--help")) {
+ try std.Io.File.stdout().writeStreamingAll(init.io, help_text);
+ return;
+ } else {
+ return error.BadArgs;
+ }
+ }
+ switch (pardes.platform) {
+ .tty => try @import("tty.zig").run(init, opts),
+ .gui => try @import("gui.zig").run(init, opts),
+ .web => unreachable, // web enters through webMain, never here
+ }
+}
+
+fn parseCtrlKey(raw: []const u8) ?u21 {
+ var value = std.mem.trim(u8, raw, " \t\r\n");
+ if (value.len >= 5 and std.ascii.eqlIgnoreCase(value[0..5], "ctrl-")) {
+ value = value[5..];
+ } else if (value.len >= 5 and std.ascii.eqlIgnoreCase(value[0..5], "ctrl+")) {
+ value = value[5..];
+ } else if (value.len == 2 and value[0] == '^') {
+ value = value[1..];
+ }
+ if (value.len != 1) return null;
+ const c = std.ascii.toLower(value[0]);
+ if (c < 'a' or c > 'z' or c == 'c') return null;
+ return c;
+}