762b7aa461df

size the man pager to the real terminal height via TIOCGWINSZ instead of a fixed 22-row guess; bump v3.4.10

time
2026-07-02 00:01 UTC · 3 months ago
machine
koh2
agent
claude-sonnet-5
session
man pager terminal height
parent
0feb174dd569
2 files VERSION+1 −1src/man.zig+32 −8
VERSION+1 −1
@@ -1 +1 @@1-3.4.91+3.4.10

view file

src/man.zig+32 −8
@@ -487,15 +487,37 @@487487 488488 // --- Pager state ---489489 490-const PAGE_ROWS: u16 = 22; // visible content rows490+// Visible content rows. Set once per run from the real terminal height, so491+// the pager fills the window instead of a fixed guess that left half the492+// screen unused on tall terminals. Falls back to this default when the493+// window size can't be read.494+var PAGE_ROWS: u16 = 22;495+const MIN_PAGE_ROWS: u16 = 5;491496 const COL_WIDTH: u16 = 96; // wrap width for paragraphs492497 // Frame geometry. The header paints exactly HEADER_ROWS lines and the footer493498 // FOOTER_ROWS; redraw arithmetic depends on these being right, so name them494499 // instead of magic +2 guesses that drift.495500 const HEADER_ROWS: u16 = 3;496501 const FOOTER_ROWS: u16 = 1;497-const FRAME_ROWS: u16 = HEADER_ROWS + PAGE_ROWS + FOOTER_ROWS;502+fn frameRows() u16 {503+    return HEADER_ROWS + PAGE_ROWS + FOOTER_ROWS;504+}498505 506+// Reads the terminal's row count via TIOCGWINSZ and converts it to a content507+// row budget by subtracting the fixed header/footer. Any failure (not a tty,508+// ioctl error, absurdly small window) falls back to the default PAGE_ROWS.509+fn detectPageRows(io: std.Io) u16 {510+    var ws: std.posix.winsize = .{ .row = 0, .col = 0, .xpixel = 0, .ypixel = 0 };511+    const result = io.operate(.{ .device_io_control = .{512+        .file = std.Io.File.stdout(),513+        .code = std.posix.T.IOCGWINSZ,514+        .arg = &ws,515+    } }) catch return PAGE_ROWS;516+    if (result.device_io_control < 0) return PAGE_ROWS;517+    if (ws.row <= HEADER_ROWS + FOOTER_ROWS + MIN_PAGE_ROWS) return PAGE_ROWS;518+    return ws.row - HEADER_ROWS - FOOTER_ROWS;519+}520+499521 pub fn run(io: std.Io, topic: []const u8) !void {500522     // Plain fallback for non-tty (piped, redirected). Print every section in501523     // order with a colored chapter divider — same vibe, but no interactivity.@@ -508,6 +530,8 @@508530     try rawModeEnable(STDIN_FD, &saved);509531     defer rawModeDisable(STDIN_FD, saved);510532 533+    PAGE_ROWS = detectPageRows(io);534+511535     const start_section: usize = if (topic.len == 0) 0 else blk: {512536         for (MAN_PAGE, 0..) |sec, i| {513537             if (std.mem.eql(u8, sec.id, topic)) break :blk i;@@ -628,11 +652,11 @@628652     // Clear the whole inline frame on exit — header included — so the shell629653     // prompt lands on a clean line. The old PAGE_ROWS + 2 count missed the top630654     // two header rows, leaving them stranded above the prompt.631-    output.cursorUp(FRAME_ROWS);632-    for (0..FRAME_ROWS) |_| {655+    output.cursorUp(frameRows());656+    for (0..frameRows()) |_| {633657         output.raw("\x1b[K\n");634658     }635-    output.cursorUp(FRAME_ROWS);659+    output.cursorUp(frameRows());636660     output.flush();637661 }638662 @@ -872,9 +896,9 @@872896 }873897 874898 fn showHelp() void {875-    output.cursorUp(FRAME_ROWS);876-    for (0..FRAME_ROWS) |_| output.raw("\x1b[K\n");877-    output.cursorUp(FRAME_ROWS);899+    output.cursorUp(frameRows());900+    for (0..frameRows()) |_| output.raw("\x1b[K\n");901+    output.cursorUp(frameRows());878902     drawHeader();879903     drawHelpBody();880904     drawFooter(0, MAN_PAGE.len, 0, 1);

view file