diff --git a/agent/HARDWARE-QUEUE.md b/agent/HARDWARE-QUEUE.md index fb7a370..b80be40 100644 --- a/agent/HARDWARE-QUEUE.md +++ b/agent/HARDWARE-QUEUE.md @@ -16,10 +16,10 @@ QA machine), the **T14s** (webcam case). one module (`HH:MM · Day DD Mon`). First pass: volume-high and keyboard still tight → pad doubled. - [x] **Calendar on unified clock (2026-07-10)** — PASS (Bernardo). -- [ ] **Rofi case-insensitive search (2026-07-10)** — SUPER+Space: type - `ste` → Steam listed (not only `Ste`/`STE`); type `sys` → System - menu row if testing nomarchy-menu. Config: matching normal,fuzzy + - case-sensitive false + case-smart false. +- [ ] **Rofi menu case-insensitive filter (2026-07-10)** — SUPER+M root + Menu: type `sys` → **System** (dmenu path uses `rofi_menu` = `-i`; + apps/drun already worked via config.rasi). Spot-check System and + Tools filters the same way. Network picker inherits `rofi -i`. - [ ] **Charge-limit live apply (2026-07-10)** — on a laptop with `charge_control_end_threshold`: System › Battery limit → 80%; confirm `cat …/charge_control_end_threshold` is 80 without rebuild; diff --git a/modules/home/rofi.nix b/modules/home/rofi.nix index 5edd1c1..bdb9f5d 100644 --- a/modules/home/rofi.nix +++ b/modules/home/rofi.nix @@ -169,10 +169,11 @@ let nomarchy-menu = pkgs.writeShellScriptBin "nomarchy-menu" '' # Nomarchy menu dispatcher — thin presentation layer over - # `rofi -dmenu`; actions delegate to nomarchy-theme-sync, systemctl, - # hyprctl and friends. Menu entries carry real icons from the theme's - # icon set (Papirus) via rofi's per-row icon protocol — see row() below. - # `nomarchy-menu` with no argument shows the module picker. + # `rofi -dmenu` (via rofi_menu helper); actions delegate to + # nomarchy-theme-sync, systemctl, hyprctl and friends. Menu entries + # carry real icons from the theme's icon set (Papirus) via rofi's + # per-row icon protocol — see row() below. `nomarchy-menu` with no + # argument shows the module picker. # System batteries: type=Battery, not scope=Device — same filter as # nomarchy-battery-notify. Name-agnostic (BAT0, CMB0, test_battery) @@ -229,6 +230,12 @@ let BACK="↩ Back" back() { printf '%s\n' "$BACK"; } + # dmenu mode is case-sensitive by default (dmenu compatibility), even + # when config.rasi has case-sensitive: false for drun/modi — so + # SUPER+Space (apps) matched "ste"→Steam while the main Menu filter + # did not match "sys"→System. Always pass -i on menu pickers. + rofi_menu() { command rofi -dmenu -i "$@"; } + case "''${1:-}" in power) choice=$( { @@ -239,7 +246,7 @@ let row "Reboot" system-reboot row "Shutdown" system-shutdown back - } | rofi -dmenu -show-icons -p Power) || exit 0 + } | rofi_menu -show-icons -p Power) || exit 0 case "$choice" in "$BACK") exec "$0" ;; *Lock) loginctl lock-session ;; @@ -274,7 +281,7 @@ let esac done back - } | rofi -dmenu -show-icons -p "profile (now: $cur)") || exit 0 + } | rofi_menu -show-icons -p "profile (now: $cur)") || exit 0 [ "$choice" = "$BACK" ] && exec "$0" system [ -n "$choice" ] && powerprofilesctl set "$choice" ;; @@ -313,7 +320,7 @@ let row "Charge limit: Off (100%)" battery-100 fi back - } | rofi -dmenu -show-icons -p "Power — profile: ''${curp:-n/a}, limit: ''${curc:-default}") || exit 0 + } | rofi_menu -show-icons -p "Power — profile: ''${curp:-n/a}, limit: ''${curc:-default}") || exit 0 # Persist in-flake + apply live to sysfs (udev makes the node # group-writable for users — Bernardo 2026-07-10). set_limit() { @@ -346,14 +353,14 @@ ${themeSlugMap} choice=$( { ${themeRows} back - } | rofi -dmenu -show-icons -p Theme -theme-str ${themeGridThemeStr}) || exit 0 + } | rofi_menu -show-icons -p Theme -theme-str ${themeGridThemeStr}) || exit 0 [ "$choice" = "$BACK" ] && exec "$0" choice="''${choice% ✓}" # drop the active marker if present slug="''${THEME_SLUG[$choice]:-}" [ -n "$slug" ] && exec nomarchy-theme-sync apply "$slug" ;; clipboard) - sel=$( { cliphist list; printf '%s\n' "$BACK"; } | rofi -dmenu -p clip) || exit 0 + sel=$( { cliphist list; printf '%s\n' "$BACK"; } | rofi_menu -p clip) || exit 0 [ "$sel" = "$BACK" ] && exec "$0" tools printf '%s' "$sel" | cliphist decode | wl-copy ;; @@ -368,7 +375,7 @@ ${themeRows} files) sel=$( { fd . "$HOME" --type f --hidden --exclude .git --exclude .cache 2>/dev/null \ | head -n 50000 | sed "s|^$HOME/||"; printf '%s\n' "$BACK"; } \ - | rofi -dmenu -p file) || exit 0 + | rofi_menu -p file) || exit 0 [ "$sel" = "$BACK" ] && exec "$0" tools [ -n "$sel" ] && exec xdg-open "$HOME/$sel" ;; @@ -379,7 +386,7 @@ ${themeRows} exec rofi -show emoji -modi emoji ;; web) - q=$(rofi -dmenu -p search < /dev/null) || exit 0 + q=$(rofi_menu -p search < /dev/null) || exit 0 [ -n "$q" ] || exit 0 exec xdg-open "https://www.google.com/search?q=$(urlencode "$q")" ;; @@ -421,7 +428,7 @@ ${themeRows} row "Output device" audio-volume-high row "Input device" audio-input-microphone back - } | rofi -dmenu -show-icons -p Audio) || exit 0 + } | rofi_menu -show-icons -p Audio) || exit 0 case "$choice" in "$BACK") exec "$0" system ;; *Output*) exec rofi-pulse-select sink ;; @@ -454,7 +461,7 @@ ${themeRows} [ -n "$profs" ] && printf 'Profiles ›\n' printf '%s' "$mons" | jq -r '.[] | "\(.name) · \(.width)x\(.height)@\(.refreshRate|round)Hz"' printf '%s\n' "$BACK" - } | rofi -dmenu -p Display ) || exit 0 + } | rofi_menu -p Display ) || exit 0 [ "$name" = "$BACK" ] && exec "$0" system [ "$name" = "Profiles ›" ] && exec "$0" display-profile name=''${name%% ·*} # strip the " · WxH@R" hint @@ -474,7 +481,7 @@ ${themeRows} printf '%s' "$mons" | jq -r --arg n "$name" '.[]|select(.name==$n)|.availableModes[]' \ | sed 's/Hz$//' | awk -F@ '{ printf "%s@%d\n", $1, $2 + 0.5 }' | sort -rV -u printf '%s\n' "$BACK" - } | rofi -dmenu -p "$name (now $cur)" ) || exit 0 + } | rofi_menu -p "$name (now $cur)" ) || exit 0 [ "$mode" = "$BACK" ] && exec "$0" "$modeBack" [ -n "$mode" ] || exit 0 @@ -509,7 +516,7 @@ ${themeRows} fi fi back - } | rofi -dmenu -show-icons -markup-rows -p Capture) || exit 0 + } | rofi_menu -show-icons -markup-rows -p Capture) || exit 0 dir="$HOME/Pictures/Screenshots" file="$dir/$(date +%Y%m%d-%H%M%S).png" case "$choice" in @@ -551,7 +558,7 @@ ${themeRows} else row "Night light (off)" weather-clear-night fi back - } | rofi -dmenu -show-icons -markup-rows -p "Look & Feel") || exit 0 + } | rofi_menu -show-icons -markup-rows -p "Look & Feel") || exit 0 case "$choice" in "$BACK") exec "$0" ;; *Theme*) exec "$0" theme ;; @@ -578,7 +585,7 @@ ${themeRows} else printf 'Auto-switch (off)\n' fi printf '%s\n' "$BACK" - } | rofi -dmenu -p Profiles ) || exit 0 + } | rofi_menu -p Profiles ) || exit 0 case "$choice" in "$BACK") exec "$0" display ;; "Base layout") exec nomarchy-display-profile base ;; @@ -612,7 +619,7 @@ ${themeRows} # Enter on a row is a deliberate no-op (nothing to launch); ↩ Back # returns to the root picker, which is also where it's launched. sel=$( { cat ${cheatsheetFile}; printf '%s\n' "$BACK"; } \ - | rofi -dmenu -i -p keys ) || exit 0 + | rofi_menu -p keys ) || exit 0 [ "$sel" = "$BACK" ] && exec "$0" exit 0 ;; @@ -621,7 +628,7 @@ ${themeRows} # Pulled fresh from npm via npx rather than nixpkgs' claude-code, # which lags behind model releases; npx caches after first run. The # REPL stays open for follow-ups. - q=$(rofi -dmenu -p claude < /dev/null) || exit 0 + q=$(rofi_menu -p claude < /dev/null) || exit 0 [ -n "$q" ] || exit 0 exec ${cfg.terminal} -e npx --yes @anthropic-ai/claude-code@latest "$q" ;; @@ -728,7 +735,7 @@ ${themeRows} row "Delete all" edit-delete row "$pam_label" system-lock-screen back - } | rofi -dmenu -show-icons -p Fingerprint) || exit 0 + } | rofi_menu -show-icons -p Fingerprint) || exit 0 case "$choice" in "$BACK") exec "$0" system ;; *Enroll*) @@ -794,7 +801,7 @@ ${themeRows} && row "System files → Snapshots" timeshift row "System config → boot an older generation (how)" help-about back - } | rofi -dmenu -show-icons -p Rollback) || exit 0 + } | rofi_menu -show-icons -p Rollback) || exit 0 case "$choice" in "$BACK") exec "$0" system ;; "Desktop gen "*) @@ -830,7 +837,7 @@ ${themeRows} command -v hyprpicker >/dev/null 2>&1 && row "Color picker${menuHint "colorpicker"}" preferences-desktop-color row "Ask Claude${menuHint "ask"}" internet-chat back - } | rofi -dmenu -show-icons -markup-rows -p Tools) || exit 0 + } | rofi_menu -show-icons -markup-rows -p Tools) || exit 0 case "$choice" in "$BACK") exec "$0" ;; *"Install Nomarchy"*) @@ -888,7 +895,7 @@ ${themeRows} # expose it), like Power profile above. has_charge_threshold && row "Battery limit" battery-080 back - } | rofi -dmenu -show-icons -markup-rows -p System) || exit 0 + } | rofi_menu -show-icons -markup-rows -p System) || exit 0 case "$choice" in "$BACK") exec "$0" ;; *Network*) exec "$0" network ;; @@ -926,7 +933,7 @@ ${themeRows} row "Off — charge to 100%" battery-100 row "Custom…" battery back - } | rofi -dmenu -show-icons -p "Battery limit (now: ''${cur:-default})") || exit 0 + } | rofi_menu -show-icons -p "Battery limit (now: ''${cur:-default})") || exit 0 set_limit() { nomarchy-theme-sync --quiet set settings.power.batteryChargeLimit "$1" --no-switch n="$1"; [ "$n" = null ] && n=100 @@ -945,7 +952,7 @@ ${themeRows} "60%"*) set_limit 60 "Set to 60%" ;; "Off"*) set_limit null "Off — charges to 100%" ;; "Custom"*) - limit=$(rofi -dmenu -p "Charge limit % (50–100)" < /dev/null) || exit 0 + limit=$(rofi_menu -p "Charge limit % (50–100)" < /dev/null) || exit 0 [ -n "$limit" ] || exit 0 case "$limit" in *[!0-9]*) notify-send "Battery limit" "Not a whole number: $limit"; exit 0 ;; @@ -968,7 +975,7 @@ ${themeRows} row "System" preferences-system row "Power${menuHint "power"}" system-shutdown row "Keybindings${menuHint "keybinds"}" preferences-desktop-keyboard - } | rofi -dmenu -show-icons -markup-rows -p Menu) || exit 0 + } | rofi_menu -show-icons -markup-rows -p Menu) || exit 0 case "$choice" in *Apps*) exec rofi -show drun -theme launcher ;; *Look*) exec "$0" lookfeel ;; @@ -1020,7 +1027,7 @@ ${themeRows} file=$( { fd -e conf -e ovpn . "$HOME" --type f --hidden \ --exclude .git --exclude .cache 2>/dev/null \ | sed "s|^$HOME/||"; printf '%s\n' "$BACK"; } \ - | rofi -dmenu -p "Import VPN config" ) || return + | rofi_menu -p "Import VPN config" ) || return { [ -z "$file" ] || [ "$file" = "$BACK" ]; } && return case "$file" in *.ovpn) type=openvpn ;; *) type=wireguard ;; esac if nmcli connection import type "$type" file "$HOME/$file" >/dev/null 2>&1; then @@ -1040,7 +1047,7 @@ ${themeRows} } ts_exit_node() { node=$( { printf 'none\n'; tailscale exit-node list 2>/dev/null | awk 'NR>1 && $2 {print $2}'; \ - printf '%s\n' "$BACK"; } | rofi -dmenu -p "Exit node" ) || return + printf '%s\n' "$BACK"; } | rofi_menu -p "Exit node" ) || return { [ -z "$node" ] || [ "$node" = "$BACK" ]; } && return [ "$node" = none ] && node="" ts_priv set --exit-node="$node" @@ -1052,7 +1059,7 @@ ${themeRows} if [ "$st" = Running ]; then printf 'Disconnect\n'; else printf 'Connect\n'; fi printf 'Exit node…\n' printf '%s\n' "$BACK" - } | rofi -dmenu -p "Tailscale ($st)" ) || return + } | rofi_menu -p "Tailscale ($st)" ) || return case "$choice" in "$BACK"|"") return ;; # Authed-but-down → bring it up inline; otherwise it needs an @@ -1072,7 +1079,7 @@ ${themeRows} printf 'Import config…\n' [ -n "$have_ts" ] && printf 'Tailscale ›\n' printf '%s\n' "$BACK" - } | rofi -dmenu -p VPN ) || exit 0 + } | rofi_menu -p VPN ) || exit 0 case "$choice" in "$BACK"|"") exec nomarchy-menu system ;; "Import config…") import_config ;; @@ -1114,7 +1121,9 @@ in force = true; text = '' [dmenu] - dmenu_command = rofi + # -i: networkmanager_dmenu uses dmenu mode (case-sensitive by + # default); match nomarchy-menu's case-insensitive filter. + dmenu_command = rofi -i rofi_highlight = True compact = True wifi_chars = ▂▄▆█