aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-09-29 10:14:23 +0200
committerDanilo M. <danix@danix.xyz>2026-09-29 10:14:23 +0200
commit457bb2ca770e7fa94a9401e637bfeac6fc61c462 (patch)
treeec3e475af362d5a2556691d7331f8b638d5576c0
parentfe118f0dffcd6f80c20a6c69b33232f2207ebf1f (diff)
downloadgrub-theme-udt-457bb2ca770e7fa94a9401e637bfeac6fc61c462.tar.gz
grub-theme-udt-457bb2ca770e7fa94a9401e637bfeac6fc61c462.zip
build: read colours from rendered theme.txt
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
-rwxr-xr-xbuild41
1 files changed, 41 insertions, 0 deletions
diff --git a/build b/build
index 73b5823..9097679 100755
--- a/build
+++ b/build
@@ -11,11 +11,39 @@ current wallpaper next to theme.txt. Everything is staged in a temporary
directory and swapped in at the end, so a failed run leaves the previous
dist/udt/ untouched. Never touches /boot: root copies dist/udt/ there.
"""
+import re
import struct
import sys
import zlib
+from pathlib import Path
PNG_SIG = b"\x89PNG\r\n\x1a\n"
+REPO = Path(__file__).resolve().parent
+PLACEHOLDERS = {f"@{r}@" for r in (
+ "SCHEME", "BG", "BG_ALT", "BG_DEEP", "SURFACE", "FG", "FG_DIM", "FG_FAINT", "ACCENT")}
+# file name: (fc-match pattern, size, the name grub-mkfont records and theme.txt uses)
+FONTS = {
+ "noto-sans-regular-24.pf2": ("Noto Sans:regular", 24, "Noto Sans Regular 24"),
+ "noto-sans-bold-32.pf2": ("Noto Sans:bold", 32, "Noto Sans Bold 32"),
+ "inconsolata-18.pf2": ("Inconsolata Nerd Font Mono", 18,
+ "Inconsolata Nerd Font Mono Regular 18"),
+}
+
+
+def die(msg):
+ sys.exit(f"build: {msg}")
+
+
+def read_colours(text):
+ """The colours on the '# udt:' line, as RGB tuples, from a rendered theme."""
+ left = sorted(set(re.findall(r"@[A-Z_]+@", text)))
+ if left:
+ die(f"theme.txt still has placeholders {' '.join(left)}; rerun udt-palette")
+ m = re.search(r"^# udt: (.+)$", text, re.M)
+ if not m:
+ die("theme.txt has no '# udt:' colour line")
+ return {k: tuple(bytes.fromhex(v.lstrip("#")))
+ for k, v in (kv.split("=") for kv in m.group(1).split())}
def chunk(tag, data):
@@ -58,6 +86,19 @@ def unpng(data):
def selftest():
w, h, px = unpng(png(3, 2, (0x12, 0x34, 0x56, 0xd9)))
assert (w, h, px) == (3, 2, {(0x12, 0x34, 0x56, 0xd9)}), (w, h, px)
+ good = "# udt: bg_alt=#1e2030 accent=#b7bdf8\ncolor = \"#cad3f5\"\n"
+ assert read_colours(good) == {"bg_alt": (0x1e, 0x20, 0x30), "accent": (0xb7, 0xbd, 0xf8)}
+ for bad in (good + 'color = "@FG@"\n', 'color = "#cad3f5"\n'):
+ try:
+ read_colours(bad)
+ except SystemExit:
+ pass
+ else:
+ raise AssertionError(f"accepted: {bad!r}")
+ tpl = (REPO / "theme.txt.in").read_text()
+ assert set(re.findall(r"@[A-Z_]+@", tpl)) <= PLACEHOLDERS, "template token udt does not fill"
+ for _, _, name in FONTS.values():
+ assert f'"{name}"' in tpl, f"template does not use font {name}"
print("selftest ok")