diff options
Diffstat (limited to 'src/pardes.zig')
| -rw-r--r-- | src/pardes.zig | 53 |
1 files changed, 47 insertions, 6 deletions
diff --git a/src/pardes.zig b/src/pardes.zig index bc9a0939..1eae2113 100644 --- a/src/pardes.zig +++ b/src/pardes.zig @@ -199,6 +199,36 @@ pub const MAX_JUMPS = 64; pub const TOPBAR_H: u16 = 1; pub const BOX_H: u16 = 1; +/// Where a reduced-height tagline band sits inside its body-sized grid row, in +/// physical pixels down from the row's top. ONE rule for both pixel hosts: the +/// SDL shell (`src/gui/gui.zig`) and the AppKit shell (`src/macos.zig`, over the +/// C ABI) both call this. It lived in gui.zig, the native shell grew its own +/// copy that only ever centred, and centring is precisely the case +/// `config.gui_topbar_pane_border_px` exists to avoid: two half-bands touching +/// with a strip of window background showing between them, widening as the +/// tagline face shrinks. +/// +/// Row zero and the first pane-tag row face a shared rule instead of centering +/// two independent bands. A Tagbottom band on the final grid row faces the +/// window edge, eliminating the matching unused half-band at the bottom. +pub fn taglineBandOffset(row: u16, canvas_h: f32, cell_h: u32, tagline_h: u32) u32 { + const spare = cell_h -| tagline_h; + const border = topbarPaneBorderPixels(cell_h, tagline_h); + if (row == 0) return spare - border / 2; + if (row == TOPBAR_H) return border - border / 2; + const rows: u32 = @max(1, @as(u32, @intFromFloat(@floor(canvas_h / @as(f32, @floatFromInt(cell_h)))))); + if (@as(u32, row) + 1 >= rows) return spare; + return spare / 2; +} + +/// The rule between the topbar band and the first pane-tag band, clamped to the +/// spare pixels those two bands have between them so a wide compiled value +/// cannot paint over either. +pub fn topbarPaneBorderPixels(cell_h: u32, tagline_h: u32) u32 { + const spare = cell_h -| tagline_h; + return @min(@as(u32, config.gui_topbar_pane_border_px), spare * 2); +} + /// A place the keyboard has been: a pane AND a spot in it, which is the whole /// upgrade over the stack of bare pane ids this replaces — Ctrl-o can now /// rewind WITHIN a pane, and a Jumplist row can name a line. @@ -330,7 +360,10 @@ fn drainForAttach(p: *Pardes) ?AttachRequest { } test "Attach asks for a session and tears nothing down" { - if (comptime !hosted) return; // no unix socket on this platform, so no word + // `can_attach` and not `hosted`: 29ac9be compiled both words out of a + // frontend that never polls `takeAttach`, which is macOS — hosted, with a + // unix socket, and still no word to run here. + if (comptime !can_attach) return; const gpa = std.testing.allocator; const p = try Pardes.init(gpa, .{ .tty_only = true }); defer p.deinit(); @@ -356,7 +389,7 @@ test "Attach asks for a session and tears nothing down" { } test "Detach asks the frontend to leave, and says so when there is nothing to leave" { - if (comptime !hosted) return; // no unix socket on this platform, so no word + if (comptime !can_attach) return; // compiled out where nothing polls `takeAttach` — see `can_attach` const gpa = std.testing.allocator; const p = try Pardes.init(gpa, .{ .tty_only = true }); defer p.deinit(); @@ -1384,12 +1417,20 @@ test "a Look on a directory does not type ls into an occupied terminal" { while (p.nextEffect()) |_| {} // /tmp rather than a made-up name: the look resolves against the real - // filesystem, so the directory has to exist for this arm to be reached - p.setCwd(0, "/tmp"); + // filesystem, so the directory has to exist for this arm to be reached — + // and in the spelling `resolve` HANDS BACK, which is the realpath. `/tmp` + // is itself on Linux and a symlink to `/private/tmp` on Darwin, and the + // `.dir` arm matches a pane by `cwdSlice()` against that realpath, on the + // documented invariant that pane paths are canonical (see `lookAt`). A + // literal "/tmp" therefore matched nothing on a Mac and forked a second + // terminal for a directory that already had one. + var realbuf: [4096]u8 = undefined; + const tmp = look.resolve("/tmp", "/", &realbuf).dir; + p.setCwd(0, tmp); var host: FakeTtyQuery = .{}; host.install(p); host.taken[0] = true; - p.lookAt(0, "/tmp"); + p.lookAt(0, tmp); var spawned = false; while (p.nextEffect()) |effect| switch (effect) { @@ -1402,7 +1443,7 @@ test "a Look on a directory does not type ls into an occupied terminal" { // ...and the same look reuses that very pane once its program is gone: the // core keeps no state of its own about it, so recovery needs nothing reset host.taken[0] = false; - p.lookAt(0, "/tmp"); + p.lookAt(0, tmp); var sent: [64]u8 = undefined; var sent_len: usize = 0; while (p.nextEffect()) |effect| switch (effect) { |
