From bf33bbc974e8bc7e4d1975d6d125eaefbf5c9b12 Mon Sep 17 00:00:00 2001 From: Muhammad Daffa Ma'arif Date: Sun, 25 Oct 2026 07:40:56 +0700 Subject: [PATCH 1/2] chore(rices): plain-text rice metadata with a separate SHELL_NAME DISPLAY_NAME packed an emoji, the name and a parenthesised subtitle into one string, which rice-switch then took apart again. Make DISPLAY_NAME just the name, add SHELL_NAME, and build the subtitle from COMPOSITOR and SHELL_NAME. `rice-switch list` now prints the directory name it accepts next to that subtitle. A new test keeps the metadata complete and free of emoji. Fixes #78 --- README.md | 3 ++- bin/rice-switch | 50 +++++++++++++++++++------------------ rices/caelestia/rice.conf | 3 ++- rices/end4/rice.conf | 3 ++- rices/ii-p3drovfx/rice.conf | 3 ++- rices/iris/rice.conf | 3 ++- rices/minflair/rice.conf | 3 ++- rices/noctalia/rice.conf | 3 ++- rices/prism-shell/rice.conf | 3 ++- rices/vitreus/rice.conf | 3 ++- tests/rice-metadata.sh | 30 ++++++++++++++++++++++ tests/rice-switch.sh | 6 ++--- 12 files changed, 77 insertions(+), 36 deletions(-) create mode 100755 tests/rice-metadata.sh diff --git a/README.md b/README.md index a086e4c..acbdd5b 100644 --- a/README.md +++ b/README.md @@ -209,7 +209,8 @@ git fetch upstream && git merge upstream/main # resolve the patch conflicts, t 2. Add `rice.conf` metadata: ```bash NAME="rice-name" - DISPLAY_NAME="🎨 Rice Name (Hyprland / Waybar)" + DISPLAY_NAME="Rice Name" # plain text, no emoji + SHELL_NAME="Waybar" # shown next to the compositor in rice-switch COMPOSITOR="hyprland" ``` 3. Put the compositor and shell configuration inside it (e.g. `hypr/`, `waybar/`, `dunst/`). diff --git a/bin/rice-switch b/bin/rice-switch index d4a5b81..f96f542 100755 --- a/bin/rice-switch +++ b/bin/rice-switch @@ -49,6 +49,25 @@ rice_meta() { printf '%s' "$line" } +rice_title() { + local name + name="$(rice_meta "$1/rice.conf" DISPLAY_NAME)" + printf '%s' "${name:-$(basename "$1")}" +} + +# "Hyprland · end4-pC Material 3", from COMPOSITOR and SHELL_NAME +rice_subtitle() { + local compositor shell + compositor="$(rice_meta "$1/rice.conf" COMPOSITOR)" + shell="$(rice_meta "$1/rice.conf" SHELL_NAME)" + compositor="${compositor^}" + if [[ -n "$compositor" && -n "$shell" ]]; then + printf '%s · %s' "$compositor" "$shell" + else + printf '%s' "$compositor$shell" + fi +} + exit_compositor() { if pgrep -x Hyprland >/dev/null 2>&1; then hyprctl dispatch exit 2>/dev/null || pkill -x Hyprland || loginctl terminate-session "${XDG_SESSION_ID:-}" @@ -76,19 +95,10 @@ gui_menu() { local rice_names=() plain_rows="" rofi_rows="" active="" for d in "$DOTFILES_DIR"/rices/*/; do [[ -d "$d" ]] || continue - local rname dname title subtitle="" + local rname title subtitle rname="$(basename "$d")" - dname="$(rice_meta "$d/rice.conf" DISPLAY_NAME)" - dname="${dname:-$rname}" - - # DISPLAY_NAME is " ( · )": drop the - # glyph and show the part in parentheses as a subtitle - [[ "$dname" == *" "* ]] && dname="${dname#* }" - title="${dname%% (*}" - if [[ "$dname" == *" ("*")" ]]; then - subtitle="${dname#* (}" - subtitle="${subtitle%)}" - fi + title="$(rice_title "$d")" + subtitle="$(rice_subtitle "$d")" [[ "$rname" == "$current" ]] && active="${#rice_names[@]}" rice_names+=("$rname") @@ -165,19 +175,11 @@ switch_to() { echo "Available rices in $DOTFILES_DIR/rices/:" for d in "$DOTFILES_DIR"/rices/*/; do if [[ -d "$d" ]]; then - local rname + local rname mark=" " rname="$(basename "$d")" - local dname="$rname" - local conf_file="$d/rice.conf" - if [[ -f "$conf_file" ]]; then - dname="$(rice_meta "$conf_file" DISPLAY_NAME)" - [[ -n "$dname" ]] || dname="$rname" - fi - if [[ "$rname" == "$current" ]]; then - echo " * $dname [ACTIVE]" - else - echo " $dname" - fi + [[ "$rname" == "$current" ]] && mark=" *" + # the directory name is what `rice-switch ` takes + printf '%s %-13s %s\n' "$mark" "$rname" "$(rice_subtitle "$d")" fi done return 0 diff --git a/rices/caelestia/rice.conf b/rices/caelestia/rice.conf index e53f978..a56e046 100644 --- a/rices/caelestia/rice.conf +++ b/rices/caelestia/rice.conf @@ -1,6 +1,7 @@ # Profile metadata for caelestia NAME="caelestia" -DISPLAY_NAME="✨ caelestia (Hyprland · Caelestia Quickshell)" +DISPLAY_NAME="Caelestia" +SHELL_NAME="Caelestia Quickshell" COMPOSITOR="hyprland" SESSION="hyprland" DESCRIPTION="Fluid morphing Quickshell interface on Hyprland" diff --git a/rices/end4/rice.conf b/rices/end4/rice.conf index 34d4397..91d3f5f 100644 --- a/rices/end4/rice.conf +++ b/rices/end4/rice.conf @@ -1,6 +1,7 @@ # Profile metadata for end4 NAME="end4" -DISPLAY_NAME="◈ end4 (Hyprland · end4-pC Material 3)" +DISPLAY_NAME="end4" +SHELL_NAME="end4-pC Material 3" COMPOSITOR="hyprland" SESSION="hyprland" DESCRIPTION="Hyprland with Quickshell end4-pC and Material You adaptive theming" diff --git a/rices/ii-p3drovfx/rice.conf b/rices/ii-p3drovfx/rice.conf index c48f321..5eef2d3 100644 --- a/rices/ii-p3drovfx/rice.conf +++ b/rices/ii-p3drovfx/rice.conf @@ -1,6 +1,7 @@ # Profile metadata for ii-p3drovfx NAME="ii-p3drovfx" -DISPLAY_NAME="✨ ii-p3drovfx (Hyprland · Quickshell II VFX)" +DISPLAY_NAME="ii-p3drovfx" +SHELL_NAME="Quickshell II VFX" COMPOSITOR="hyprland" SESSION="hyprland" DESCRIPTION="illogical-impulse fork with dynamic VFX and enhanced Quickshell components" diff --git a/rices/iris/rice.conf b/rices/iris/rice.conf index 4d89835..9570eba 100644 --- a/rices/iris/rice.conf +++ b/rices/iris/rice.conf @@ -1,6 +1,7 @@ # Profile metadata for iris NAME="iris" -DISPLAY_NAME="✦ iris (Niri · iNiR iRiS)" +DISPLAY_NAME="iRiS" +SHELL_NAME="iNiR" COMPOSITOR="niri" SESSION="niri" DESCRIPTION="Niri scrolling compositor with iNiR Quickshell shell" diff --git a/rices/minflair/rice.conf b/rices/minflair/rice.conf index 9b1d9cc..a854edf 100644 --- a/rices/minflair/rice.conf +++ b/rices/minflair/rice.conf @@ -1,6 +1,7 @@ # Profile metadata for minflair NAME="minflair" -DISPLAY_NAME="🎨 minflair (Hyprland · Quickshell Minflair)" +DISPLAY_NAME="Minflair" +SHELL_NAME="Quickshell Minflair" COMPOSITOR="hyprland" SESSION="hyprland" DESCRIPTION="Modular dynamic aesthetic Hyprland desktop powered by Quickshell" diff --git a/rices/noctalia/rice.conf b/rices/noctalia/rice.conf index 38b3a3e..3f231cc 100644 --- a/rices/noctalia/rice.conf +++ b/rices/noctalia/rice.conf @@ -1,6 +1,7 @@ # Profile metadata for noctalia NAME="noctalia" -DISPLAY_NAME="🌌 noctalia (Umbriel · Noctalia v5)" +DISPLAY_NAME="Noctalia" +SHELL_NAME="Noctalia v5" COMPOSITOR="umbriel" SESSION="umbriel" DESCRIPTION="Umbriel SceneFX compositor with Noctalia v5 shell" diff --git a/rices/prism-shell/rice.conf b/rices/prism-shell/rice.conf index 5705311..24dc3aa 100644 --- a/rices/prism-shell/rice.conf +++ b/rices/prism-shell/rice.conf @@ -1,6 +1,7 @@ # Profile metadata for prism-shell NAME="prism-shell" -DISPLAY_NAME="💎 prism-shell (Hyprland · Quickshell Prism)" +DISPLAY_NAME="Prism Shell" +SHELL_NAME="Quickshell Prism" COMPOSITOR="hyprland" SESSION="hyprland" DESCRIPTION="Prism dynamic desktop shell powered by Quickshell & Matugen" diff --git a/rices/vitreus/rice.conf b/rices/vitreus/rice.conf index 38b66d1..04cef69 100644 --- a/rices/vitreus/rice.conf +++ b/rices/vitreus/rice.conf @@ -1,6 +1,7 @@ # Profile metadata for vitreus NAME="vitreus" -DISPLAY_NAME="🫧 vitreus (Hyprland · Vitreus liquid-glass)" +DISPLAY_NAME="Vitreus" +SHELL_NAME="Vitreus liquid-glass" COMPOSITOR="hyprland" SESSION="hyprland" DESCRIPTION="Liquid-glass pleamar shell on Hyprland" diff --git a/tests/rice-metadata.sh b/tests/rice-metadata.sh new file mode 100755 index 0000000..961d6ad --- /dev/null +++ b/tests/rice-metadata.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +# Every rices/*/rice.conf has the fields rice-switch shows, as plain text: +# NAME matching the directory, DISPLAY_NAME, SHELL_NAME and COMPOSITOR, with no +# emoji or other non-ASCII symbols in the user-facing ones. +set -euo pipefail + +REPO="$(cd "$(dirname "$0")/.." && pwd)" +failed=0 + +field() { + grep -m1 -E "^$2=" "$1" | cut -d= -f2- | sed -e 's/^"//' -e 's/"$//' +} + +for conf in "$REPO"/rices/*/rice.conf; do + rice="$(basename "$(dirname "$conf")")" + [[ "$(field "$conf" NAME)" == "$rice" ]] || { echo "FAIL: $rice: NAME does not match the directory" >&2; failed=1; } + for key in DISPLAY_NAME SHELL_NAME COMPOSITOR; do + value="$(field "$conf" "$key")" + if [[ -z "$value" ]]; then + echo "FAIL: $rice: $key is missing" >&2 + failed=1 + elif LC_ALL=C grep -q '[^ -~]' <<<"$value"; then + echo "FAIL: $rice: $key is not plain text: $value" >&2 + failed=1 + fi + done +done + +(( failed == 0 )) && echo "ok: rice metadata is complete and plain text" +exit "$failed" diff --git a/tests/rice-switch.sh b/tests/rice-switch.sh index f6e4a21..c5f5282 100755 --- a/tests/rice-switch.sh +++ b/tests/rice-switch.sh @@ -4,8 +4,9 @@ # 2. Closing the menu without a row (rofi exits 0, prints nothing) does the same. # 3. A chosen row still reaches the switch. # 4. Empty or path-like rice names are rejected. -# 5. Menu content: one two-line row per rice without the glyph, the current -# rice marked active, an out-of-range index ignored, theme fallback. +# 5. Menu content: one two-line row per rice (DISPLAY_NAME, then COMPOSITOR · +# SHELL_NAME), the current rice marked active, an out-of-range index +# ignored, theme fallback. set -euo pipefail REPO="$(cd "$(dirname "$0")/.." && pwd)" @@ -82,7 +83,6 @@ rices="$(find "$REPO/rices" -mindepth 1 -maxdepth 1 -type d | wc -l)" [[ "$rows" -eq "$rices" ]] || fail "expected $rices rows, got $rows" grep -qF 'end4' "$TMP/rofi.stdin" || fail "end4 row has no plain title: $(cat "$TMP/rofi.stdin")" grep -qF '>Hyprland · end4-pC Material 3' "$TMP/rofi.stdin" || fail "end4 row has no subtitle" -grep -qF '◈' "$TMP/rofi.stdin" && fail "DISPLAY_NAME glyph still shown" end4_index="$(find "$REPO/rices" -mindepth 1 -maxdepth 1 -type d -printf '%f\n' | LC_ALL=C sort | grep -nx end4 | cut -d: -f1)" grep -A1 -x -- '-a' "$TMP/rofi.args" | tail -n1 | grep -qx "$((end4_index - 1))" || fail "current rice not marked active: $(cat "$TMP/rofi.args")" grep -A1 -x -- '-theme' "$TMP/rofi.args" | tail -n1 | grep -q 'rice-switch.rasi$' || fail "rice-switch.rasi not used" From 3be7763a9be1fc662dda06d425883134b140b5da Mon Sep 17 00:00:00 2001 From: Muhammad Daffa Ma'arif Date: Sun, 25 Oct 2026 07:44:08 +0700 Subject: [PATCH 2/2] test(rices): report every missing metadata key instead of aborting on the first --- tests/rice-metadata.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/rice-metadata.sh b/tests/rice-metadata.sh index 961d6ad..bb3f85e 100755 --- a/tests/rice-metadata.sh +++ b/tests/rice-metadata.sh @@ -8,7 +8,8 @@ REPO="$(cd "$(dirname "$0")/.." && pwd)" failed=0 field() { - grep -m1 -E "^$2=" "$1" | cut -d= -f2- | sed -e 's/^"//' -e 's/"$//' + # a missing key is reported by the caller, so it must not trip set -e here + { grep -m1 -E "^$2=" "$1" || true; } | cut -d= -f2- | sed -e 's/^"//' -e 's/"$//' } for conf in "$REPO"/rices/*/rice.conf; do @@ -26,5 +27,7 @@ for conf in "$REPO"/rices/*/rice.conf; do done done -(( failed == 0 )) && echo "ok: rice metadata is complete and plain text" +if (( failed == 0 )); then + echo "ok: rice metadata is complete and plain text" +fi exit "$failed"