From e714bbfa8b7cbf9970053cfbabbb9b1f02a2290e Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Mon, 21 Sep 2026 23:43:31 -0300 Subject: Draw a frame only when there is one worth drawing A 9P round trip on a local Unix socket cost 9.7 ms against the SDL shell and 0.758 ms against the terminal one. The server was not slow and the wake was not broken: instrumenting the path showed every request waking the loop early (wakes=210, woke_early=212, timed_out=38 over 250 ticks) and being answered on that same pass. The cost was that `pump` answers 9P at one point in a loop that then renders and presents unconditionally, so a client's next request landed while the main thread was blocked on the display, and each round trip therefore cost a whole frame. The frame rate was governing something that has nothing to do with drawing. `Pardes.needs_frame` starts true, is set by every event except a tick with nothing animating and a filesystem request that only reads, and is cleared once a frame is presented. `pump` returns before render and present when it is false and nothing is animating. An idle editor answering reads now draws nothing at all. 9P read_fid, one RPC: gui 9.7 ms -> 0.056 ms (173x) tty 0.758 ms -> 0.062 ms (12x) Verified the shells still paint rather than going quiet: the rendered screen carries the opened file, a write through 9P redraws within the frame, and `fs-discovery-test` passes over the real wire. Suite unchanged at 778/783 with the two pre-existing crashes. Also from the adversarial review of the previous commits: `pardes --tty FILE` silently discarded the file, and `--tty MISSING` silently discarded the error pane. main.zig named the boot layout before the positional was resolved, and naming one short-circuits `Boot.of`. The choice now happens after the argument is known, and only when there is no file and no missing word. macos.zig names the same layout, so the app no longer boots a different one from the terminal and SDL shells. `pre_close_last_pane_tail` was transcribed from the NEW default rather than the old one, so the upgrade path it was added for did not exist: a workspace dumped before the tagline reorder came back with the old default welded on as a custom tail. It is now the string it claims to be. A pane two rows tall lost its message and, worse, its prompt and the cursor with it. The notice cap keeps the LAST notices now, because the prompt is last and a prompt you cannot see is one you type into blind. Co-Authored-By: Claude Opus 5 (1M context) --- src/main.zig | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'src/main.zig') diff --git a/src/main.zig b/src/main.zig index 1cbdf24c..9abc04bf 100644 --- a/src/main.zig +++ b/src/main.zig @@ -270,10 +270,6 @@ fn nativeMain(init: std.process.Init) !void { } } opts.tty_only = explicit_tty or session_only; - // The real bare-tty startup wants the editor half present from the first - // frame, so it names that layout; a core booted for a test names none and - // gets the raw shell by itself. - if (opts.tty_only) opts.boot = .tty; opts.mounts = mounts[0..mounts_len]; if (detach != null and attach != null) badArgs(init.io, "--detach and --attach are opposites: one runs the session, the other joins one", .{}); @@ -370,6 +366,13 @@ fn nativeMain(init: std.process.Init) !void { } } } + // The real bare-tty startup wants the editor half present from the first + // frame, so it names that layout; a core booted for a test names none and + // gets the raw shell by itself. This has to come AFTER the positional is + // resolved: naming a layout short-circuits `Boot.of`, so choosing it any + // earlier threw away a file argument, and the error pane for one that does + // not exist, without a word. + if (opts.tty_only and opts.file == null and opts.missing == null) opts.boot = .tty; const found = pardes.config.User.load(init.io, arena, init.environ_map); opts.startup_config = found.bytes; opts.startup_config_path = found.path; -- cgit v1.3