From 0c483f951217a574bbe8742e1daca59b31c53673 Mon Sep 17 00:00:00 2001 From: Bernardo Magri Date: Sat, 20 Jun 2026 18:23:21 +0100 Subject: [PATCH] feat(menu): network + audio modules; case-insensitive fuzzy search MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - network: replace the nmtui-in-a-terminal flow with networkmanager_dmenu (native rofi wifi/VPN picker), configured via xdg config.ini to drive rofi with rofi_highlight; editing a connection drops to nmtui. - audio: new System -> Audio sink/source switcher via rofi-pulse-select, self-gated on the PipeWire/pulse socket. - search: case-insensitive fuzzy matching with fzf sorting across every menu module and the launcher (so "system" finds "System"). Secrets module (rbw/pass) deferred — no Bitwarden/pass setup here. Co-Authored-By: Claude Opus 4.8 --- docs/ROADMAP.md | 18 +++++++++---- modules/home/rofi.nix | 60 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 67 insertions(+), 11 deletions(-) diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 0e9799a..c0a64bb 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -72,11 +72,19 @@ how to override it. Items marked ✓ are shipped. launcher, and yazi (SUPER+E) already covers real browsing. - **More menu modules from rofi tools:** the script-based counterparts (run via `rofi -dmenu`, like the hand-rolled modules), each a deliberate - replacement of an existing flow: **rofi-network-manager** (a keyboard - wifi/VPN picker vs today's `nmtui`-in-terminal `network`), **rofi-rbw / - rofi-pass** (a secrets module — Bitwarden via rbw, or `pass` — pairs with - `keys.nix`), and **rofi-pulse-select** (an audio sink/source switcher). - Decide per-module whether it earns replacing the current path. + replacement of an existing flow. + - ✓ **Network** (`networkmanager_dmenu`): a native rofi wifi/VPN picker + replacing the old `nmtui`-in-terminal `network` flow. Configured (xdg + `networkmanager-dmenu/config.ini`) to drive rofi with `rofi_highlight` + for connected/available rows; editing a connection drops to nmtui in the + terminal. Inherits the generated theme like every other module. + - ✓ **Audio** (`rofi-pulse-select`): a PipeWire/pulse sink/source switcher + under System → Audio (Output/Input), self-gated on the pulse socket. + - Deferred: **rofi-rbw / rofi-pass** secrets module — no Bitwarden/`pass` + setup here today (secrets are gpg/ssh + gnome-keyring, see `keys.nix`), + so it'd mean adopting a new secret manager. Revisit if that changes. + - Also: menu search is now **case-insensitive fuzzy** (`matching = fuzzy`, + `sorting-method = fzf`) across every module + the launcher. - **Theme parity with legacy:** summer-day/night now carry their legacy bar layouts as `waybar.jsonc` whole-swaps (adapted: dead legacy script modules dropped, Nerd-Fonts-v2 codepoints remapped to FontAwesome/v3, diff --git a/modules/home/rofi.nix b/modules/home/rofi.nix index e6b614c..0aea889 100644 --- a/modules/home/rofi.nix +++ b/modules/home/rofi.nix @@ -241,13 +241,32 @@ ${themeRows} exec xdg-open "https://www.google.com/search?q=$(urlencode "$q")" ;; network) - # nmtui in a terminal (NetworkManager is the system network stack). - exec ${cfg.terminal} -e nmtui ;; + # Native rofi wifi/VPN picker (networkmanager_dmenu) over the system + # NetworkManager — replaces the old nmtui-in-a-terminal flow. Reads + # its config from xdg.configFile below (told to drive rofi). + exec networkmanager_dmenu ;; bluetooth) # blueman-manager GUI (services.blueman.enable, system-side). exec blueman-manager ;; + audio) + # PipeWire (pulse) sink/source switcher via rofi-pulse-select. Self- + # gated in the System menu on the pulse socket; guarded here too. + if [ ! -e "''${XDG_RUNTIME_DIR:-/run/user/$(id -u)}/pulse/native" ]; then + notify-send "Audio" "No PipeWire/PulseAudio socket (nomarchy.audio off?)."; exit 0 + fi + choice=$( { + row "Output device" audio-volume-high + row "Input device" audio-input-microphone + back + } | rofi -dmenu -show-icons -p Audio) || exit 0 + case "$choice" in + "$BACK") exec "$0" system ;; + *Output*) exec rofi-pulse-select sink ;; + *Input*) exec rofi-pulse-select source ;; + esac ;; + capture) choice=$( { row "Region → clipboard" applets-screenshooter @@ -339,6 +358,8 @@ ${themeRows} choice=$( { row "Network" network-wireless row "Bluetooth" bluetooth + [ -e "''${XDG_RUNTIME_DIR:-/run/user/$(id -u)}/pulse/native" ] \ + && row "Audio" audio-volume-high row "Do Not Disturb" notification-disabled systemctl --user cat hyprsunset.service >/dev/null 2>&1 \ && row "Night light" weather-clear-night @@ -352,6 +373,7 @@ ${themeRows} "$BACK") exec "$0" ;; *Network*) exec "$0" network ;; *Bluetooth*) exec "$0" bluetooth ;; + *Audio*) exec "$0" audio ;; *"Do Not Disturb"*) exec "$0" dnd ;; *"Night light"*) exec "$0" nightlight ;; *Snapshots*) exec "$0" snapshot ;; @@ -380,7 +402,7 @@ ${themeRows} esac ;; *) - echo "usage: nomarchy-menu [tools|system|power|power-profile|theme|clipboard|calc|files|emoji|web|network|bluetooth|capture|keybinds|ask|dnd|nightlight|snapshot]" >&2 + echo "usage: nomarchy-menu [tools|system|power|power-profile|theme|clipboard|calc|files|emoji|web|network|bluetooth|audio|capture|keybinds|ask|dnd|nightlight|snapshot]" >&2 exit 64 ;; esac ''; @@ -389,11 +411,29 @@ in config = lib.mkIf cfg.rofi.enable { home.packages = [ nomarchy-menu - pkgs.fd # files module (fuzzy search over $HOME) - pkgs.xdg-utils # xdg-open for the files + web modules - pkgs.nodejs # npx, for the Ask Claude module (claude-code from npm) + pkgs.fd # files module (fuzzy search over $HOME) + pkgs.xdg-utils # xdg-open for the files + web modules + pkgs.nodejs # npx, for the Ask Claude module (claude-code from npm) + pkgs.networkmanager_dmenu # network module: rofi wifi/VPN picker + pkgs.rofi-pulse-select # audio module: sink/source switcher ]; + # networkmanager_dmenu drives rofi (not bare dmenu) and uses rofi's + # active/urgent row styling for the connected/available networks, so it + # inherits the generated theme like every other menu module. Editing a + # connection drops to nmtui in the configured terminal. + xdg.configFile."networkmanager-dmenu/config.ini".text = '' + [dmenu] + dmenu_command = rofi + rofi_highlight = True + compact = False + wifi_chars = ▂▄▆█ + + [editor] + terminal = ${cfg.terminal} + gui_if_available = False + ''; + programs.rofi = { enable = true; terminal = cfg.terminal; @@ -416,6 +456,14 @@ in # reserving `lines` (8) — so a 6-entry menu doesn't leave empty space, # while the app launcher still fills + scrolls past `lines`. fixed-num-lines = false; + # Search: case-insensitive fuzzy across every menu + the launcher, so + # "system" finds "System" and "fzr" finds "Firefox". fzf sorting ranks + # the closest match to the top (the per-keystroke modules — calc/emoji + # — opt out per-invocation with -no-sort). + matching = "fuzzy"; + case-sensitive = false; + sort = true; + sorting-method = "fzf"; }; # Whole-swap themes bring their own rofi.rasi; otherwise the theme