From dd91ef1d59b93120ae1f6b9324361bee56a1d393 Mon Sep 17 00:00:00 2001 From: Frank Date: Tue, 20 Oct 2026 21:27:16 -0700 Subject: [PATCH] fix(gen-keybinds): match the section dash as a literal so headers survive LC_ALL=C MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The section rule was `/^[[:space:]]*\/\/[[:space:]]*─+ (.+) ─+…$/`, a quantifier on a multibyte character. Under LC_ALL=C — which is what cron, systemd user units and agent shells get, regardless of LANG — gawk matches byte-wise, so `─+` means "the last byte of U+2500, repeated" and never matches. Measured on the live keybinds.kdl: the old script emitted 0 section headers instead of 12, all 120 binding rows intact, exit status 0. A silent one-third-of-the-page loss, invisible to any caller that only checks the status. The dash is now matched and stripped as a literal (`gsub(/─/, "")`), which is byte-safe in every locale, and a comment must be dash-decorated on both sides to open a section, so plain comments are still ignored. A test pins the C-locale case explicitly, because the box's own terminal has always been UTF-8 and could never have caught this. The committed artifact omp-docs/tools/niri/keybindings.md is unaffected (12 headers, 120 rows — it was generated from a UTF-8 shell); output is now identical either way. --- scripts/gen-keybinds.sh | 30 ++++++++++++++++++++---------- tests/gen-keybinds.bats | 10 ++++++++++ 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/scripts/gen-keybinds.sh b/scripts/gen-keybinds.sh index dcab227..3feeeec 100755 --- a/scripts/gen-keybinds.sh +++ b/scripts/gen-keybinds.sh @@ -42,17 +42,27 @@ gen() { echo "> GENERATED by \`scripts/gen-keybinds.sh\` from \`$(basename "$KBD")\` — do not edit by hand." echo awk ' - # section header: // ─── Name ─── - /^[[:space:]]*\/\/[[:space:]]*─+ (.+) ─+[[:space:]]*$/ { + # Section marker: a comment decorated with box-drawing dashes on both sides, + # `// ─── Name ───`. The dash is matched as a LITERAL and removed with gsub — never + # with a quantifier on the multibyte character. Under LC_ALL=C (cron, systemd units, + # agent shells) gawk works byte-wise, `─+` then means "the last byte of ─, repeated", + # and every header vanishes while the script still exits 0. Plain comments stay + # comments: only a dash-decorated one opens a section. + /^[[:space:]]*\/\/[[:space:]]*─/ { s = $0 - sub(/^[[:space:]]*\/\/[[:space:]]*─+ /, "", s) - sub(/ ─+[[:space:]]*$/, "", s) - if (in_table) print "" - print "## " s - print "" - print "| Key | Action |" - print "|-----|--------|" - in_table = 1 + sub(/^[[:space:]]*\/\/[[:space:]]*/, "", s) + sub(/[[:space:]]+$/, "", s) + if (s ~ /─ .*─/) { + gsub(/─/, "", s) + gsub(/[[:space:]]+/, " ", s) + sub(/^ /, "", s); sub(/ $/, "", s) + if (in_table) print "" + print "## " s + print "" + print "| Key | Action |" + print "|-----|--------|" + in_table = 1 + } next } # bind line: KEY [flags] [hotkey-overlay-title="..."] { action; } diff --git a/tests/gen-keybinds.bats b/tests/gen-keybinds.bats index 70edf8b..8823e11 100755 --- a/tests/gen-keybinds.bats +++ b/tests/gen-keybinds.bats @@ -48,6 +48,16 @@ teardown() { [[ "$output" != *"a plain comment"* ]] } +@test "section headers survive a C locale, where awk reads bytes instead of characters" { + # Cron, systemd units and agent shells get LC_ALL=C while Frank's terminal does not. + # A matcher that puts a quantifier on a multibyte character then loses EVERY section + # header and prints a sheet with no sections at all — silently, exit status 0. + run env LC_ALL=C "$GEN" "$TMP/keybinds.kdl" + [[ "$output" == *"## Applications"* ]] + [[ "$output" == *"## Screenshots"* ]] + [[ "$output" != *"a plain comment"* ]] +} + @test "row count matches bind count" { run "$GEN" "$TMP/keybinds.kdl" local rows -- 2.54.0