From bf7526c342c763252c8cd8c917b594e2ec22102c Mon Sep 17 00:00:00 2001 From: Phorcys Date: Wed, 1 Jul 2026 00:06:10 +0000 Subject: [PATCH] feat(images): two-line boot-screen footer for the PR title Split the boot-screen footer across up to two GRUB labels so a long PR title no longer overflows the screen width: line 1 (always): Coder Box - @ line 2 (PR only): (PR #46: ) A non-PR build shows only line 1. box-turnkey.nix now exposes coderBox.bootLabelLine1 / bootLabelLine2 (replacing the single-line bootLabel), and base/iso.nix stacks the second label ~1 line-height below the first (emitted only when line 2 is non-empty). --- nixos/_images/base/iso.nix | 65 ++++++++++++++++++++++------------- nixos/_images/box-turnkey.nix | 31 +++++++++++------ 2 files changed, 61 insertions(+), 35 deletions(-) diff --git a/nixos/_images/base/iso.nix b/nixos/_images/base/iso.nix index 8b7ac1e..311d8b9 100644 --- a/nixos/_images/base/iso.nix +++ b/nixos/_images/base/iso.nix @@ -35,53 +35,70 @@ boot.loader.systemd-boot.enable = lib.mkForce false; boot.loader.efi.canTouchEfiVariables = lib.mkForce false; - # ── Show the build identity on the boot screen as a footer label ───────────── + # ── Show the build identity on the boot screen as a footer ─────────────────── # The boot-menu ENTRY can't carry the build identity: it's a single, # non-wrapping line in a fixed-width GRUB/isolinux menu, so a long PR title # overflows and gets clipped (and widening the menu makes it span the whole - # screen). Instead, render coderBox.bootLabel — e.g. - # "Coder Box - PR #46: <title> (abc123@branch)", or just - # "Coder Box - abc123@branch" with no PR — as a standalone GRUB *label* - # (boot-screen chrome, not a selectable entry) shown as a footer UNDER the menu. - # The label is ALWAYS present (every build has a commit/branch), so this also - # makes the footer visible on local/non-PR builds, not just CI PR previews. + # screen). Instead, render the identity as standalone GRUB *labels* + # (boot-screen chrome, not selectable entries) shown as a footer UNDER the + # menu, on up to two lines so a long PR title doesn't overflow the width: + # line 1 (always): "Coder Box - <short-sha>@<branch>" + # line 2 (PR only): "(PR #46: <title>)" + # Line 1 is always present (every build has a commit/branch), so the footer + # shows on local/non-PR builds too, not just CI PR previews. # # Key gotcha: the stock theme's boot_menu fills almost the whole height with an # opaque white pixmap (boot_menu_*.png), and GRUB paints that box OVER any # label that overlaps it — so a footer placed inside the box is invisible. The # menu only has a handful of entries, so we shrink boot_menu's height to free - # the lower area of the screen, then place the label there on the plain + # the lower area of the screen, then place the labels there on the plain # background (dark text, good contrast). The menu WIDTH is untouched (still the - # stock 800px), so the menu doesn't blow up horizontally like the earlier - # full-width experiment. EFI/GRUB only; the BIOS/isolinux text menu has no - # theme, so there the identity is available off-menu via /etc/coder-box-pr + - # the installer console banner. + # stock 800px), so the menu doesn't blow up horizontally. EFI/GRUB only; the + # BIOS/isolinux text menu has no theme, so there the identity is available + # off-menu via /etc/coder-box-pr + the installer console banner. # # substituteInPlace uses --replace-fail so a future nixpkgs theme reflow fails # the build loudly instead of silently dropping the footer. isoImage.grubTheme = let - inherit (config.coderBox) bootLabel; + inherit (config.coderBox) bootLabelLine1 bootLabelLine2; # theme.txt wraps the text in double quotes; neutralise quotes/backslashes # so an arbitrary title can't break the theme parser. - bootLabelThemeSafe = builtins.replaceStrings [ "\"" "\\" ] [ "'" "" ] bootLabel; + themeSafe = builtins.replaceStrings [ "\"" "\\" ] [ "'" "" ]; + line1 = themeSafe bootLabelLine1; + line2 = themeSafe bootLabelLine2; + # A GRUB `+ label` is a single line, so line 2 (the PR title) is a second + # label stacked ~1 line-height (font is 20px) below line 1. Only emitted + # for PR builds (bootLabelLine2 is empty otherwise). + line2Label = lib.optionalString (bootLabelLine2 != "") '' + + + label { + top = 50%+28 + left = 50%-400 + width = 800 + align = "center" + color = "#232627" + font = "DejaVu Regular" + text = "${line2}" + } + ''; in pkgs.runCommand "coder-box-grub2-theme" { } '' cp -r ${pkgs.nixos-grub2-theme} "$out" chmod -R u+w "$out" # 1) Shrink the menu box so its opaque pixmap stops at ~46% of the screen - # (~1/3 shorter than the previous 62%), leaving the lower area free for - # the footer (stock fills to the progress bar and would cover it). + # (~1/3 shorter than the stock full height), leaving the lower area free + # for the footer (stock fills to the progress bar and would cover it). substituteInPlace "$out/theme.txt" \ --replace-fail 'height = 100%-3%-100-3%-3%-32-3%' 'height = 46%-100-6%' - # 2) Footer label just BELOW the shrunk box (top ~50%), so it sits close to - # the menu rather than far down the screen. Its left/width match the menu - # box (left = 50%-400, width = 800) so the centred text lines up with the - # rectangle instead of spanning the full screen. Quoted heredoc so the - # build shell does no expansion; the text is already substituted by Nix - # (and quote/backslash-sanitised). + # 2) Footer label(s) just BELOW the shrunk box (top ~50%), so they sit close + # to the menu. left/width match the menu box (left = 50%-400, width = + # 800) so the centred text lines up with the rectangle. Quoted heredoc so + # the build shell does no expansion; the text is already substituted by + # Nix (and quote/backslash-sanitised). line2Label is empty on non-PR + # builds. cat >> "$out/theme.txt" <<'EOF' + label { @@ -91,8 +108,8 @@ align = "center" color = "#232627" font = "DejaVu Regular" - text = "${bootLabelThemeSafe}" - } + text = "${line1}" + }${line2Label} EOF ''; diff --git a/nixos/_images/box-turnkey.nix b/nixos/_images/box-turnkey.nix index af27caf..8645631 100644 --- a/nixos/_images/box-turnkey.nix +++ b/nixos/_images/box-turnkey.nix @@ -69,11 +69,13 @@ let # "<short-sha>@<branch>" form (branch omitted when unknown/detached). versionStamp = revShort + lib.optionalString (branchClean != "") "@${branchClean}"; - # Boot-screen label (the GRUB footer in ../base/iso.nix). ALWAYS present so the - # image's identity is visible on the boot screen regardless of build type: - # with a PR: "Coder Box - PR #46: <title> (<short-sha>@<branch>)" - # without a PR: "Coder Box - <short-sha>@<branch>" - bootLabel = "Coder Box - " + (if prFull != "" then "${prFull} (${versionStamp})" else versionStamp); + # Boot-screen footer (the GRUB label(s) in ../base/iso.nix), rendered on up to + # two lines so a long PR title doesn't overflow the screen width: + # line 1 (always): "Coder Box - <short-sha>@<branch>" + # line 2 (PR only): "(PR #46: <title>)" + # A non-PR build shows only line 1. + bootLabelLine1 = "Coder Box - ${versionStamp}"; + bootLabelLine2 = lib.optionalString (prFull != "") "(${prFull})"; in { imports = [ @@ -146,15 +148,22 @@ in description = "Full PR identity (number + untruncated title) for off-menu surfaces (empty for non-PR builds)."; }; - # Boot-screen label (the GRUB footer in ../base/iso.nix), e.g. - # "Coder Box - PR #46: <title> (abc123def456@my-branch)" or, without a PR, - # "Coder Box - abc123def456@my-branch". Always non-empty. - options.coderBox.bootLabel = lib.mkOption { + # Boot-screen footer, split across up to two GRUB labels (../base/iso.nix): + # line 1 (always): "Coder Box - abc123def456@my-branch" + # line 2 (PR only): "(PR #46: <title>)" (empty string on non-PR builds) + options.coderBox.bootLabelLine1 = lib.mkOption { type = lib.types.str; internal = true; readOnly = true; - default = bootLabel; - description = "Boot-screen footer label (build identity: PR + short-sha@branch); always present."; + default = bootLabelLine1; + description = "First boot-screen footer line (Coder Box - short-sha@branch); always present."; + }; + options.coderBox.bootLabelLine2 = lib.mkOption { + type = lib.types.str; + internal = true; + readOnly = true; + default = bootLabelLine2; + description = "Second boot-screen footer line ((PR #N: title)); empty on non-PR builds."; }; config = {