summaryrefslogtreecommitdiff
path: root/src/pardes.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/pardes.zig')
-rw-r--r--src/pardes.zig53
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) {