From d43ab37bcc264aba31ece59b3a67b63552522c2b Mon Sep 17 00:00:00 2001 From: Myned Date: Sun, 9 Feb 2025 18:43:55 -0600 Subject: [PATCH] menu: refactor menus and switch to rofi Signed-off-by: Myned --- options/custom/default.nix | 1 + options/custom/desktops/niri/binds.nix | 18 +- options/custom/desktops/niri/default.nix | 3 - options/custom/desktops/niri/misc.nix | 8 +- options/custom/{programs => menus}/anyrun.nix | 6 +- options/custom/menus/default.nix | 34 +++ options/custom/{programs => menus}/fuzzel.nix | 4 +- options/custom/menus/rofi/clipboard.sh | 50 ++++ options/custom/menus/rofi/custom.rasi | 85 ++++++ options/custom/menus/rofi/default.nix | 131 +++++++++ options/custom/menus/walker/default.nix | 276 ++++++++++++++++++ .../{programs => menus}/walker/search.sh | 0 .../{programs => menus}/walker/style.css | 0 options/custom/{programs => menus}/wofi.nix | 4 +- options/custom/programs/bitwarden-menu.nix | 49 ++-- .../custom/programs/networkmanager-dmenu.nix | 36 ++- options/custom/programs/rbw.nix | 48 ++- options/custom/programs/rofi-rbw.nix | 21 -- options/custom/programs/rofi.nix | 182 ------------ options/custom/programs/walker/default.nix | 250 ---------------- options/custom/scripts/bwm.sh | 50 ---- options/custom/scripts/default.nix | 18 +- options/custom/scripts/vault.sh | 74 +++++ 23 files changed, 766 insertions(+), 582 deletions(-) rename options/custom/{programs => menus}/anyrun.nix (88%) create mode 100644 options/custom/menus/default.nix rename options/custom/{programs => menus}/fuzzel.nix (87%) create mode 100644 options/custom/menus/rofi/clipboard.sh create mode 100644 options/custom/menus/rofi/custom.rasi create mode 100644 options/custom/menus/rofi/default.nix create mode 100644 options/custom/menus/walker/default.nix rename options/custom/{programs => menus}/walker/search.sh (100%) rename options/custom/{programs => menus}/walker/style.css (100%) rename options/custom/{programs => menus}/wofi.nix (91%) delete mode 100644 options/custom/programs/rofi-rbw.nix delete mode 100644 options/custom/programs/rofi.nix delete mode 100644 options/custom/programs/walker/default.nix delete mode 100644 options/custom/scripts/bwm.sh create mode 100644 options/custom/scripts/vault.sh diff --git a/options/custom/default.nix b/options/custom/default.nix index 3d177bd..9b2928a 100644 --- a/options/custom/default.nix +++ b/options/custom/default.nix @@ -43,6 +43,7 @@ in { }; lockscreen = mkOption {default = "hyprlock";}; + menu = mkOption {default = "rofi";}; wallpaper = mkOption {default = false;}; browser = { diff --git a/options/custom/desktops/niri/binds.nix b/options/custom/desktops/niri/binds.nix index b805332..db4a866 100644 --- a/options/custom/desktops/niri/binds.nix +++ b/options/custom/desktops/niri/binds.nix @@ -10,6 +10,7 @@ with lib; let audio = config.home-manager.users.${config.custom.username}.home.file.".local/bin/audio".source; bash = "${pkgs.bash}/bin/bash"; + bitwarden = "${pkgs.bitwarden-desktop}/bin/bitwarden"; cat = "${pkgs.coreutils}/bin/cat"; codium = "${config.home-manager.users.${config.custom.username}.programs.vscode.package}/bin/codium"; ghostty = "${hm.programs.ghostty.package}/bin/ghostty"; @@ -29,13 +30,10 @@ with lib; let playerctl = "${pkgs.playerctl}/bin/playerctl"; power = config.home-manager.users.${config.custom.username}.home.file.".local/bin/power".source; remote = config.home-manager.users.${config.custom.username}.home.file.".local/bin/remote".source; - rm = "${pkgs.coreutils}/bin/rm"; steam = "${config.programs.steam.package}/bin/steam"; swayosd-client = "${pkgs.swayosd}/bin/swayosd-client"; virt-manager = "${config.programs.virt-manager.package}/bin/virt-manager"; - walker = "${config.home-manager.users.${config.custom.username}.programs.walker.package}/bin/walker"; waydroid = "${pkgs.waydroid}/bin/waydroid"; - _1password = "${config.programs._1password-gui.package}/bin/1password"; youtube-music = "${pkgs.youtube-music}/bin/youtube-music"; in { options.custom.desktops.niri.binds = { @@ -133,9 +131,9 @@ in { (key "M" "Mod" (spawn youtube-music)) (key "Minus" "Mod" (spawn [swayosd-client "--output-volume" "lower"])) (key "O" "Mod" (spawn [loupe "/tmp/wallpaper.png"])) - (key "P" "Ctrl+Alt" (spawn [pkill "1password"])) - (key "P" "Mod" (spawn _1password)) - (key "P" "Mod+Shift" (spawn [_1password "--quick-access"])) + (key "P" "Ctrl+Alt" (spawn [pkill "bitwarden"])) + (key "P" "Mod" (spawn [bash "-c" config.custom.menus.vault.show])) + (key "P" "Mod+Shift" (spawn bitwarden)) (key "Q" "Mod" close-window) (key "R" "Mod" focus-window-or-workspace-down) (key "R" "Mod+Shift" move-window-down-or-to-workspace-down) @@ -154,9 +152,9 @@ in { (key "T" "Mod" (spawn ghostty)) (key "Tab" "Mod" switch-focus-between-floating-and-tiling) (key "Up" "Mod" (spawn [swayosd-client "--brightness" "raise"])) - (key "V" "Mod" (spawn [walker "--modules" "clipboard"])) + (key "V" "Mod" (spawn [bash "-c" config.custom.menus.clipboard.show])) (key "V" "Mod+Ctrl" (spawn vm)) - (key "V" "Mod+Shift" (spawn [bash "-c" "${rm} ~/.cache/walker/clipboard.gob && ${notify-send} menu 'Clipboard cleared' --urgency low"])) + (key "V" "Mod+Shift" (spawn [bash "-c" config.custom.menus.clipboard.clear])) (key "W" "Mod" focus-window-or-workspace-up) (key "W" "Mod+Shift" move-window-up-or-to-workspace-up) (key "WheelScrollDown" "Mod" focus-window-or-workspace-down) @@ -181,9 +179,9 @@ in { # TODO: Uncomment when fixed #// (key "Shift_L" "Mod" focus-workspace-previous) # TODO: Use "Super_L" when fixed - (key "Space" "Mod" (spawn walker)) + (key "Space" "Mod" (spawn [bash "-c" config.custom.menus.show])) (key "Space" "Mod+Ctrl+Shift" (spawn networkmanager_dmenu)) - (key "Space" "Mod+Shift" (spawn [walker "--modules" "search"])) + (key "Space" "Mod+Shift" (spawn [bash "-c" config.custom.menus.search.show])) # Media keys # https://github.com/xkbcommon/libxkbcommon/blob/master/include/xkbcommon/xkbcommon-keysyms.h diff --git a/options/custom/desktops/niri/default.nix b/options/custom/desktops/niri/default.nix index d608200..d3081e2 100644 --- a/options/custom/desktops/niri/default.nix +++ b/options/custom/desktops/niri/default.nix @@ -38,9 +38,6 @@ in { services = { # Enable rootless Xwayland xwayland-satellite.enable = cfg.xwayland; - - # Enable X11/Wayland clipboard sync - clipsync.enable = true; }; }; diff --git a/options/custom/desktops/niri/misc.nix b/options/custom/desktops/niri/misc.nix index 4b4db98..a846e7f 100644 --- a/options/custom/desktops/niri/misc.nix +++ b/options/custom/desktops/niri/misc.nix @@ -9,8 +9,8 @@ with lib; let hm = config.home-manager.users.${config.custom.username}; audio = config.home-manager.users.${config.custom.username}.home.file.".local/bin/audio".source; + bash = "${pkgs.bash}/bin/bash"; niri = "${config.programs.niri.package}/bin/niri"; - rm = "${pkgs.coreutils}/bin/rm"; sway-audio-idle-inhibit = "${pkgs.sway-audio-idle-inhibit}/bin/sway-audio-idle-inhibit"; wallpaper = "${config.home-manager.users.${config.custom.username}.home.file.".local/bin/wallpaper".source}"; in { @@ -49,12 +49,10 @@ in { #!! Not executed in a shell # https://github.com/YaLTeR/niri/wiki/Configuration:-Key-Bindings#spawn # https://github.com/sodiboo/niri-flake/blob/main/docs.md#programsnirisettingsspawn-at-startup - spawn-at-startup = let - home = hm.home.homeDirectory; - in + spawn-at-startup = [ {command = [audio "--init"];} # Enforce audio profile state - {command = [rm "${home}/.cache/walker/clipboard.gob"];} # Clear clipboard history + {command = [bash "-c" config.custom.menus.clipboard.clear];} # Clear clipboard history {command = [sway-audio-idle-inhibit];} # Inhibit while audio is playing ] ++ optionals config.custom.wallpaper [ diff --git a/options/custom/programs/anyrun.nix b/options/custom/menus/anyrun.nix similarity index 88% rename from options/custom/programs/anyrun.nix rename to options/custom/menus/anyrun.nix index f4a589c..eea7057 100644 --- a/options/custom/programs/anyrun.nix +++ b/options/custom/menus/anyrun.nix @@ -6,13 +6,11 @@ ... }: with lib; let - cfg = config.custom.programs.anyrun; + cfg = config.custom.menus.anyrun; in { - options.custom.programs.anyrun.enable = mkOption {default = false;}; + options.custom.menus.anyrun.enable = mkOption {default = false;}; config.home-manager.users.${config.custom.username} = mkIf cfg.enable { - imports = [inputs.anyrun.homeManagerModules.default]; - # https://github.com/Kirottu/anyrun programs.anyrun = { enable = true; diff --git a/options/custom/menus/default.nix b/options/custom/menus/default.nix new file mode 100644 index 0000000..46b6149 --- /dev/null +++ b/options/custom/menus/default.nix @@ -0,0 +1,34 @@ +{ + config, + lib, + ... +}: +with lib; let + cfg = config.custom.menus; +in { + options.custom.menus = { + enable = mkOption {default = config.custom.full;}; + show = mkOption {default = "";}; + + clipboard = { + clear = mkOption {default = "";}; + show = mkOption {default = "";}; + }; + + dmenu.show = mkOption {default = "";}; + emoji.show = mkOption {default = "";}; + network.show = mkOption {default = "";}; + search.show = mkOption {default = "";}; + vault.show = mkOption {default = "";}; + }; + + config = mkIf cfg.enable { + custom.menus = { + anyrun.enable = config.custom.menu == "anyrun"; + fuzzel.enable = config.custom.menu == "fuzzel"; + rofi.enable = config.custom.menu == "rofi"; + walker.enable = config.custom.menu == "walker"; + wofi.enable = config.custom.menu == "wofi"; + }; + }; +} diff --git a/options/custom/programs/fuzzel.nix b/options/custom/menus/fuzzel.nix similarity index 87% rename from options/custom/programs/fuzzel.nix rename to options/custom/menus/fuzzel.nix index 50f4da4..5b9f5d0 100644 --- a/options/custom/programs/fuzzel.nix +++ b/options/custom/menus/fuzzel.nix @@ -4,9 +4,9 @@ ... }: with lib; let - cfg = config.custom.programs.fuzzel; + cfg = config.custom.menus.fuzzel; in { - options.custom.programs.fuzzel.enable = mkOption {default = false;}; + options.custom.menus.fuzzel.enable = mkOption {default = false;}; config.home-manager.users.${config.custom.username} = mkIf cfg.enable { # https://codeberg.org/dnkl/fuzzel diff --git a/options/custom/menus/rofi/clipboard.sh b/options/custom/menus/rofi/clipboard.sh new file mode 100644 index 0000000..612ac0a --- /dev/null +++ b/options/custom/menus/rofi/clipboard.sh @@ -0,0 +1,50 @@ +#! /usr/bin/env bash + +TMPDIR=/tmp/cliphist + +# Clean up tmp dir +rm -rf "$TMPDIR" + +# TODO: Add keybinds +# https://github.com/lbonn/rofi/blob/wayland/doc/rofi-script.5.markdown#environment +case "$ROFI_RETV" in + # List entries + 0) + mkdir -p "$TMPDIR" + + # Parse over clipboard + cliphist list | while read -r line; do + # Skip over HTML elements + # https://github.com/sentriz/cliphist/commit/95c193604fce7c5ec094ff9bf1c62cc6f5395750 + if [[ "$line" == *meta\ http-equiv=* ]]; then + continue + fi + + # Isolate index and entry name + id="$(cut -f 1 - <<< "$line")" + name="$(cut -f 2 - <<< "$line")" + + # Check for image entries + if [[ "$line" =~ ^([0-9]+)[[:space:]]+\[\[\ binary.*(jpg|jpeg|png|bmp) ]]; then + # Set image extension and icon path + extension="${BASH_REMATCH[2]}" + icon="$TMPDIR/$id.$extension" + + # Write decoded image to tmp dir + if ! [[ -f "$icon" ]]; then + cliphist decode "$id" > "$icon" + fi + + # Pass entry to rofi + printf '%s\x0icon\x1f%s\x1finfo\x1f%s\n' "$name" "$icon" "$id" + else + printf '%s\x0info\x1f%s\n' "$name" "$id" + fi + done + ;; + # Select entry + 1) + # Decode from env var and copy to clipboard + cliphist decode "$ROFI_INFO" | wl-copy + ;; +esac diff --git a/options/custom/menus/rofi/custom.rasi b/options/custom/menus/rofi/custom.rasi new file mode 100644 index 0000000..aad9c24 --- /dev/null +++ b/options/custom/menus/rofi/custom.rasi @@ -0,0 +1,85 @@ +/*** +https://github.com/lbonn/rofi/blob/wayland/doc/rofi-theme.5.markdown +https://github.com/newmanls/rofi-themes-collection/blob/master/themes/rounded-common.rasi +https://github.com/newmanls/rofi-themes-collection/blob/master/themes/rounded-pink-dark.rasi +***/ + +* { + background-color: transparent; + font: 'sans-serif 14'; + margin: 0; + padding: 0; + spacing: 0; + text-color: #93a1a1; +} + +window { + background-color: #002b36; + border-color: #073642; + border-radius: 30px; + location: north; + width: 750; + y-offset: calc(50% - 25% / 2); +} + +mainbox { + padding: 4px; +} + +inputbar { + background-color: #073642; + border-color: #d33682; + border-radius: 30px; + padding: 8px 8px 8px 4px; + spacing: 4px; +} + +prompt { + font: 'monospace 16'; + padding: 4px 4px 4px 8px; + text-color: #93a1a1; + vertical-align: 0.5; +} + +entry { + font: 'monospace 18'; + placeholder-color: #586e7580; + vertical-align: 0.5; +} + +message { + padding: 8px 8px 4px 8px; +} + +textbox { + font: 'sans-serif 10'; +} + +listview { + background-color: transparent; + columns: 1; + fixed-height: false; + lines: 5; + margin: 4px 0 0; +} + +element { + border-radius: 30px; + padding: 12px; + spacing: 8px; +} + +element selected normal, +element selected active { + background-color: #586e7540; +} + +element-icon { + size: 32px; + vertical-align: 0.5; +} + +element-text { + text-color: inherit; + vertical-align: 0.5; +} diff --git a/options/custom/menus/rofi/default.nix b/options/custom/menus/rofi/default.nix new file mode 100644 index 0000000..779da74 --- /dev/null +++ b/options/custom/menus/rofi/default.nix @@ -0,0 +1,131 @@ +{ + config, + lib, + pkgs, + ... +}: +with lib; let + cfg = config.custom.menus.rofi; + hm = config.home-manager.users.${config.custom.username}; + + cliphist = getExe hm.services.cliphist.package; + networkmanager_dmenu = getExe pkgs.networkmanager_dmenu; + notify-send = getExe pkgs.libnotify; + pkill = getExe' pkgs.procps "pkill"; + rofi = getExe hm.programs.rofi.finalPackage; + rofi-rbw = getExe pkgs.rofi-rbw; + rofimoji = getExe pkgs.rofimoji; +in { + options.custom.menus.rofi = { + enable = mkOption {default = false;}; + }; + + config = mkIf cfg.enable { + custom = mkIf (config.custom.menu == "rofi") { + menus = let + quit = "${pkill} --exact rofi"; + in { + show = "${quit} || ${rofi} -show combi -show-icons"; + + clipboard = { + show = "${quit} || ${rofi} -show clipboard -show-icons"; + clear = "${cliphist} wipe && ${notify-send} '> cliphist' 'Clipboard cleared' --urgency low"; + }; + + dmenu.show = "${quit} || ${rofi} -dmenu"; + emoji.show = "${quit} || ${rofimoji} --prompt 󰞅"; + network.show = "${quit} || ${rofi} -dmenu -p "; + search.show = ""; + vault.show = "${quit} || ${rofi-rbw} --prompt "; + }; + + services = { + cliphist.enable = true; + }; + }; + + environment.systemPackages = [ + pkgs.rofimoji # https://github.com/fdw/rofimoji + ]; + + home-manager.sharedModules = [ + { + #!! Creates package derivation + #?? hm.programs.rofi.finalPackage + # https://github.com/davatorium/rofi + programs.rofi = { + enable = true; + + # https://github.com/lbonn/rofi + # https://github.com/lbonn/rofi/tree/wayland/doc + package = pkgs.rofi-wayland; # Wayland fork + + plugins = with pkgs; [ + rofi-calc # https://github.com/svenstaro/rofi-calc + ]; + + #?? rofi-theme-selector + theme = "custom"; + + # https://github.com/lbonn/rofi/blob/wayland/CONFIG.md + # https://github.com/lbonn/rofi/blob/wayland/doc/rofi.1.markdown + # https://www.nerdfonts.com/cheat-sheet + extraConfig = { + combi-hide-mode-prefix = true; + combi-modes = ["drun" "run" "calc"]; + cycle = false; + display-calc = "󱖦"; + display-clipboard = "󰅌"; + display-combi = ""; + display-dmenu = "󰗧"; + display-drun = ""; + display-keys = ""; + display-run = ""; + display-ssh = ""; + drun-display-format = "{name}"; # Display only names + drun-match-fields = "name"; # Disable matching of invisible desktop attributes + matching = "prefix"; # Match beginning of words + + # https://github.com/lbonn/rofi/blob/wayland/doc/rofi.1.markdown#available-modes + modes = [ + "calc" + "clipboard" + "combi" + "drun" + "keys" + "run" + "ssh" + ]; + }; + }; + + xdg.configFile = { + # https://github.com/lbonn/rofi/blob/wayland/doc/rofi-theme.5.markdown + "rofi/custom.rasi".text = '' + ${readFile ./custom.rasi} + + window, inputbar { + border: ${toString config.custom.border}px; + } + ''; + + # https://github.com/lbonn/rofi/blob/wayland/doc/rofi-script.5.markdown + # https://github.com/sentriz/cliphist?tab=readme-ov-file#picker-examples + "rofi/scripts/clipboard" = { + #// source = getExe' hm.services.cliphist.package "cliphist-rofi-img"; + + # HACK: Cannot easily hide index via display-columns without dmenu mode + # https://github.com/sentriz/cliphist/issues/130 + # https://github.com/davatorium/rofi/discussions/1993#discussioncomment-9971764 + # https://github.com/sentriz/cliphist/pull/124 + source = getExe (pkgs.writeShellApplication { + name = "clipboard.sh"; + runtimeInputs = with pkgs; [coreutils gnused wl-clipboard]; + text = readFile ./clipboard.sh; + }); + }; + }; + } + ]; + }; +} diff --git a/options/custom/menus/walker/default.nix b/options/custom/menus/walker/default.nix new file mode 100644 index 0000000..02ac1c2 --- /dev/null +++ b/options/custom/menus/walker/default.nix @@ -0,0 +1,276 @@ +{ + config, + lib, + inputs, + pkgs, + ... +}: +with lib; let + cfg = config.custom.menus.walker; + hm = config.home-manager.users.${config.custom.username}; + + notify-send = getExe pkgs.libnotify; + rm = getExe' pkgs.coreutils "rm"; + walker = getExe hm.programs.walker.package; +in { + options.custom.menus.walker = { + enable = mkOption {default = false;}; + icons = mkOption {default = ["edit-find" "terminal"];}; + }; + + config = mkIf cfg.enable { + custom = { + menus = mkIf (config.custom.menu == "walker") { + show = walker; + + clipboard = { + show = "${walker} --modules clipboard"; + clear = "${rm} ~/.cache/walker/clipboard.gob && ${notify-send} '> walker' 'Clipboard cleared' --urgency low"; + }; + + dmenu.show = "${walker} --modules dmenu"; + emoji.show = "${walker} --modules emojis"; + search.show = "${walker} --modules search"; + vault.show = ""; + }; + + services = { + clipnotify.enable = true; + }; + }; + + home-manager.sharedModules = [ + { + # https://github.com/abenz1267/walker + # https://github.com/abenz1267/walker?tab=readme-ov-file#building-from-source + # https://github.com/abenz1267/walker/blob/master/nix/hm-module.nix + programs.walker = { + enable = true; + + #!! Service must be restarted for changes to take effect + #?? systemctl --user restart walker.service + runAsService = true; + + # https://github.com/abenz1267/walker/wiki/Basic-Configuration + # https://github.com/abenz1267/walker/blob/master/internal/config/config.default.toml + config = { + activation_mode.disabled = true; # Key chords + close_when_open = true; + disable_click_to_close = true; + force_keyboard_focus = true; + hotreload_theme = true; + ignore_mouse = true; + + list = { + placeholder = ""; + }; + + search = { + placeholder = ""; + #// resume_last_query = true; + }; + + # https://github.com/abenz1267/walker/wiki/Modules + # https://github.com/PapirusDevelopmentTeam/papirus-icon-theme/tree/master/Papirus/64x64 + disabled = [ + "ai" + "commands" + "custom_commands" + "finder" + "websearch" # Replaced by custom plugin + "windows" + ]; + + builtins = let + in { + applications = { + actions.enabled = false; + hide_without_query = true; + placeholder = ""; + show_generic = false; + switcher_only = false; + }; + + bookmarks = { + icon = "user-bookmarks"; + placeholder = ""; + prefix = "b "; + switcher_only = false; + }; + + calc = { + icon = "accessories-calculator"; + min_chars = 1; + placeholder = ""; + prefix = "="; + show_icon_when_single = true; + switcher_only = false; + }; + + clipboard = { + max_entries = 50; + placeholder = ""; + switcher_only = true; + }; + + dmenu = { + keep_sort = true; + placeholder = "Input"; + switcher_only = true; + }; + + emojis = { + placeholder = ""; + prefix = "`"; + switcher_only = false; + }; + + finder = { + icon = "filetypes"; + placeholder = ""; + prefix = "//"; + show_icon_when_single = true; + switcher_only = false; + }; + + runner = { + icon = "utilities-x-terminal"; + placeholder = ""; + prefix = ">"; + show_icon_when_single = true; + switcher_only = false; + }; + + ssh = { + icon = "folder-remote-symbolic"; + placeholder = ""; + prefix = "ssh "; + show_icon_when_single = true; + switcher_only = false; + }; + + switcher = { + icon = "application-default-icon"; + prefix = "/"; + show_icon_when_single = true; + }; + + symbols = { + placeholder = ""; + prefix = "sym "; + switcher_only = false; + }; + + translation = { + icon = "translator"; + placeholder = ""; + prefix = "tr "; + switcher_only = false; + }; + + websearch = { + placeholder = "system-search"; + switcher_only = false; + entries = [{}]; + }; + }; + + # TODO: Keybinds + # https://github.com/abenz1267/walker/wiki/Keybinds + + # https://github.com/abenz1267/walker/wiki/Plugins + plugins = [ + { + # Search engines by keyword prefix + name = "search"; + placeholder = ""; + show_icon_when_single = true; + switcher_only = false; + + src = "${pkgs.writeShellApplication { + name = "search"; + text = readFile ./search.sh; + runtimeInputs = with pkgs; [coreutils jq xdg-utils]; + }}/bin/search '%TERM%'"; + } + ]; + }; + + # https://github.com/abenz1267/walker/wiki/Theming + theme = { + style = '' + #box { + border: ${toString config.custom.border}px #073642 solid; + font: larger ${config.custom.settings.fonts.sans-serif}; + } + + ${readFile ./style.css} + ''; + + # https://github.com/abenz1267/walker/blob/master/internal/config/layout.default.toml + layout.ui.window = let + w = 750; + h = 300; + in { + width = w; + height = h; + + box = { + h_align = "fill"; + width = -1; + height = -1; + + scroll = { + h_align = "fill"; + h_scrollbar_policy = "external"; + v_scrollbar_policy = "external"; + + list = { + width = -1; + height = -1; + min_width = -1; + min_height = -1; + max_width = w; + max_height = h; + + item = { + text = { + sub = { + hide = true; # Subtext + }; + }; + }; + }; + }; + }; + }; + }; + }; + } + ]; + + # # HACK: Create theme files for module prompt icons + # #?? MODULE.theme = "icon-ICON" + # # https://github.com/abenz1267/walker/blob/bb584eab3b0cc48ebfbac1a5da019864d74781c4/nix/hm-module.nix#L86 + # xdg.configFile = listToAttrs (flatten (forEach cfg.icons ( + # icon: [ + # { + # name = "walker/themes/icon-${icon}.css"; + # value = {text = hm.programs.walker.theme.style;}; + # } + # { + # name = "walker/themes/icon-${icon}.json"; + # value = { + # text = builtins.toJSON (recursiveUpdate hm.programs.walker.theme.layout { + # ui.window.box.search.prompt.icon = icon; + # }); + # }; + # } + # ] + # ))); + + # HACK: Allow child processes to live, otherwise applications launched through service are killed on stop + # https://www.freedesktop.org/software/systemd/man/latest/systemd.kill.html#KillMode= + systemd.user.services.walker.Service.KillMode = "process"; + }; +} diff --git a/options/custom/programs/walker/search.sh b/options/custom/menus/walker/search.sh similarity index 100% rename from options/custom/programs/walker/search.sh rename to options/custom/menus/walker/search.sh diff --git a/options/custom/programs/walker/style.css b/options/custom/menus/walker/style.css similarity index 100% rename from options/custom/programs/walker/style.css rename to options/custom/menus/walker/style.css diff --git a/options/custom/programs/wofi.nix b/options/custom/menus/wofi.nix similarity index 91% rename from options/custom/programs/wofi.nix rename to options/custom/menus/wofi.nix index 5f574f6..609bf05 100644 --- a/options/custom/programs/wofi.nix +++ b/options/custom/menus/wofi.nix @@ -4,9 +4,9 @@ ... }: with lib; let - cfg = config.custom.programs.wofi; + cfg = config.custom.menus.wofi; in { - options.custom.programs.wofi.enable = mkOption {default = false;}; + options.custom.menus.wofi.enable = mkOption {default = false;}; config.home-manager.users.${config.custom.username} = mkIf cfg.enable { # https://hg.sr.ht/~scoopta/wofi diff --git a/options/custom/programs/bitwarden-menu.nix b/options/custom/programs/bitwarden-menu.nix index d48c1c2..4f31101 100644 --- a/options/custom/programs/bitwarden-menu.nix +++ b/options/custom/programs/bitwarden-menu.nix @@ -1,31 +1,46 @@ { config, lib, + pkgs, ... }: with lib; let - wofi = "${config.home-manager.users.${config.custom.username}.programs.wofi.package}/bin/wofi"; - cfg = config.custom.programs.bitwarden-menu; + hm = config.home-manager.users.${config.custom.username}; + + walker = getExe hm.programs.walker.package; in { - options.custom.programs.bitwarden-menu.enable = mkOption {default = false;}; + options.custom.programs.bitwarden-menu = { + enable = mkOption {default = false;}; + }; - config.home-manager.users.${config.custom.username} = mkIf cfg.enable { + config = { # https://github.com/firecat53/bitwarden-menu - #!! Options not available, files written directly - # https://github.com/firecat53/bitwarden-menu/blob/main/docs/configure.md - xdg.configFile."bwm/config.ini".text = '' - [dmenu] - dmenu_command = ${wofi} --dmenu + environment.systemPackages = with pkgs; [ + bitwarden-cli + bitwarden-menu + ]; - [dmenu_passphrase] - obscure = True + home-manager.sharedModules = mkIf cfg.enable [ + { + # TODO: Check for official options + # https://github.com/firecat53/bitwarden-menu/blob/main/docs/configure.md + xdg.configFile."bwm/config.ini".text = generators.toINI {} { + dmenu = { + dmenu_command = "${walker} --dmenu --forceprint"; + }; - # FIXME: Login options taking effect - [vault] - server = https://vault.bitwarden.com - twofactor = 0 - session_timeout_min = 720 - ''; + dmenu_passphrase = { + obscure = true; + }; + + vault = { + server_1 = "https://vault.${config.custom.domain}"; + login_1 = "${config.custom.username}@${config.custom.domain}"; + twofactor_1 = 0; + }; + }; + } + ]; }; } diff --git a/options/custom/programs/networkmanager-dmenu.nix b/options/custom/programs/networkmanager-dmenu.nix index 831efae..bb3ea98 100644 --- a/options/custom/programs/networkmanager-dmenu.nix +++ b/options/custom/programs/networkmanager-dmenu.nix @@ -1,26 +1,36 @@ { config, lib, + pkgs, ... }: with lib; let - menu = config.home-manager.users.${config.custom.username}.home.file.".local/bin/menu".source; - cfg = config.custom.programs.networkmanager-dmenu; + + bash = getExe pkgs.bash; in { options.custom.programs.networkmanager-dmenu.enable = mkOption {default = false;}; - config.home-manager.users.${config.custom.username} = mkIf cfg.enable { + config = mkIf cfg.enable { # https://github.com/firecat53/networkmanager-dmenu - # https://github.com/firecat53/networkmanager-dmenu/blob/main/config.ini.example - #!! Option not available, files written directly - xdg.configFile."networkmanager-dmenu/config.ini".text = '' - [dmenu] - compact = true - dmenu_command = ${menu} input - active_chars =  - wifi_icons = 󰤯󰤟󰤢󰤥󰤨 - format = {icon} {name} - ''; + environment.systemPackages = [pkgs.networkmanager_dmenu]; + + home-manager.users.${config.custom.username} = { + # https://github.com/firecat53/networkmanager-dmenu/blob/main/config.ini.example + #!! Option not available, files written directly + xdg.configFile."networkmanager-dmenu/config.ini".text = '' + [dmenu] + compact = true + dmenu_command = ${bash} -c '${config.custom.menus.network.show}' + list_saved = true + active_chars =  + highlight = true + wifi_icons = 󰤯󰤟󰤢󰤥󰤨 + format = {icon} {name} + + [dmenu_passphrase] + obscure = true + ''; + }; }; } diff --git a/options/custom/programs/rbw.nix b/options/custom/programs/rbw.nix index 240e909..b1f1a18 100644 --- a/options/custom/programs/rbw.nix +++ b/options/custom/programs/rbw.nix @@ -7,21 +7,41 @@ with lib; let cfg = config.custom.programs.rbw; in { - options.custom.programs.rbw.enable = mkOption {default = false;}; + options.custom.programs.rbw = { + enable = mkOption {default = false;}; + }; - config.home-manager.users.${config.custom.username} = mkIf cfg.enable { - # https://github.com/doy/rbw - #!! Register with API secrets before using - #?? rbw register - #?? rbw login - programs.rbw = { - enable = true; + config = { + # https://github.com/fdw/rofi-rbw + environment.systemPackages = [pkgs.rofi-rbw]; - # https://github.com/doy/rbw?tab=readme-ov-file#configuration - settings = { - email = "myned@bjork.tech"; - pinentry = pkgs.pinentry-gnome3; - }; - }; + home-manager.sharedModules = mkIf cfg.enable [ + { + # https://github.com/doy/rbw + #!! Register with API secrets before using + #?? rbw register + #?? rbw login + programs.rbw = { + enable = true; + + # https://github.com/doy/rbw?tab=readme-ov-file#configuration + settings = { + base_url = "https://vault.${config.custom.domain}"; + email = "${config.custom.username}@${config.custom.domain}"; + pinentry = pkgs.pinentry-gnome3; + }; + }; + + # TODO: Enable input emulation when merged (uinput.enable?) + # https://github.com/NixOS/nixpkgs/pull/303745 + # https://github.com/fdw/rofi-rbw?tab=readme-ov-file#configuration + xdg.configFile = { + "rofi-rbw.rc".text = '' + action=copy + selector=${config.custom.menu} + ''; + }; + } + ]; }; } diff --git a/options/custom/programs/rofi-rbw.nix b/options/custom/programs/rofi-rbw.nix deleted file mode 100644 index 61e88d8..0000000 --- a/options/custom/programs/rofi-rbw.nix +++ /dev/null @@ -1,21 +0,0 @@ -{ - config, - lib, - ... -}: -with lib; let - cfg = config.custom.programs.rofi-rbw; -in { - options.custom.programs.rofi-rbw.enable = mkOption {default = false;}; - - config.home-manager.users.${config.custom.username} = mkIf cfg.enable { - # https://github.com/fdw/rofi-rbw - #!! Options not available, files written directly - # https://github.com/fdw/rofi-rbw?tab=readme-ov-file#configuration - # TODO: Enable input emulation when merged (uinput.enable?) - # https://github.com/NixOS/nixpkgs/pull/303745 - xdg.configFile."rofi-rbw.rc".text = '' - action=copy - ''; - }; -} diff --git a/options/custom/programs/rofi.nix b/options/custom/programs/rofi.nix deleted file mode 100644 index 20487c7..0000000 --- a/options/custom/programs/rofi.nix +++ /dev/null @@ -1,182 +0,0 @@ -{ - config, - lib, - pkgs, - ... -}: -with lib; let - cfg = config.custom.programs.rofi; -in { - options.custom.programs.rofi.enable = mkOption {default = false;}; - - config.home-manager.users.${config.custom.username} = mkIf cfg.enable { - #!! Creates package derivation - #?? config.home-manager.users.${config.custom.username}.programs.rofi.finalPackage - # https://github.com/lbonn/rofi - programs.rofi = { - enable = true; - package = pkgs.rofi-wayland; # Wayland fork - - # TODO: Look into rofi plugins - plugins = with pkgs; [ - rofi-rbw # Bitwarden - rofimoji # Character picker - - # TODO: Remove when rofi v1.7.6 released - # Build against rofi-wayland due to ABI incompatibility with upstream - # https://github.com/lbonn/rofi/issues/96 - # https://github.com/NixOS/nixpkgs/issues/298539 - (rofi-calc.override {rofi-unwrapped = rofi-wayland-unwrapped;}) # Calculator - (rofi-top.override {rofi-unwrapped = rofi-wayland-unwrapped;}) # System monitor - ]; - - #?? rofi-theme-selector - theme = "custom"; - font = "${config.custom.settings.fonts.monospace} 16"; - - # https://github.com/davatorium/rofi/blob/next/CONFIG.md - extraConfig = { - modi = "drun,run,calc"; - matching = "prefix"; # Match beginning of words - drun-display-format = "{name}"; # Display only names - drun-match-fields = "name"; # Disable matching of invisible desktop attributes - }; - }; - - # https://github.com/davatorium/rofi/blob/next/doc/rofi-theme.5.markdown - # https://github.com/davatorium/rofi/blob/next/themes/paper-float.rasi - # TODO: Clean up theme - home.file.".config/rofi/custom.rasi".text = '' - * { - background: #073642ff; - alternate: #002b36ff; - text: #eee8d5ff; - accent: #d33682ff; - - spacing: 2; - text-color: @text; - background-color: #00000000; - border-color: @accent; - anchor: north; - location: center; - } - window { - transparency: "real"; - background-color: #00000000; - border: 0; - padding: 0% 0% 1em 0%; - x-offset: 0; - y-offset: -10%; - } - mainbox { - padding: 0px; - border: 0; - spacing: 1%; - } - message { - border: 2px; - padding: 1em; - background-color: @background; - text-color: @text; - } - textbox normal { - text-color: @text; - padding: 0; - border: 0; - } - listview { - fixed-height: 1; - border: 2px; - padding: 1em; - reverse: false; - - columns: 1; - background-color: @background; - } - element { - border: 0; - padding: 2px; - highlight: bold ; - } - element-text { - background-color: inherit; - text-color: inherit; - } - element normal.normal { - text-color: @text; - background-color: @background; - } - element normal.urgent { - text-color: @text; - background-color: @background; - } - element normal.active { - text-color: @text; - background-color: @background; - } - element selected.normal { - text-color: @text; - background-color: @accent; - } - element selected.urgent { - text-color: @text; - background-color: @accent; - } - element selected.active { - text-color: @text; - background-color: @accent; - } - element alternate.normal { - text-color: @text; - background-color: @alternate; - } - element alternate.urgent { - text-color: @text; - background-color: @alternate; - } - element alternate.active { - text-color: @text; - background-color: @alternate; - } - scrollbar { - border: 0; - padding: 0; - } - inputbar { - spacing: 0; - border: 2px; - padding: 0.5em 1em; - background-color: @background; - index: 0; - } - inputbar normal { - foreground-color: @text; - background-color: @background; - } - mode-switcher { - border: 2px; - padding: 0.5em 1em; - background-color: @background; - index: 10; - } - button selected { - text-color: @accent; - } - inputbar { - children: [ prompt,textbox-prompt-colon,entry,case-indicator ]; - } - textbox-prompt-colon { - expand: false; - str: ":"; - margin: 0px 0.3em 0em 0em ; - text-color: @text; - } - error-message { - border: 2px; - padding: 1em; - background-color: @background; - text-color: @text; - } - ''; - }; -} diff --git a/options/custom/programs/walker/default.nix b/options/custom/programs/walker/default.nix deleted file mode 100644 index aebed52..0000000 --- a/options/custom/programs/walker/default.nix +++ /dev/null @@ -1,250 +0,0 @@ -{ - config, - lib, - inputs, - pkgs, - ... -}: -with lib; let - cfg = config.custom.programs.walker; - hm = config.home-manager.users.${config.custom.username}; -in { - options.custom.programs.walker = { - enable = mkOption {default = false;}; - icons = mkOption {default = ["edit-find" "terminal"];}; - }; - - config.home-manager.users.${config.custom.username} = mkIf cfg.enable { - imports = [inputs.walker.homeManagerModules.default]; - - # https://github.com/abenz1267/walker - # https://github.com/abenz1267/walker?tab=readme-ov-file#building-from-source - # https://github.com/abenz1267/walker/blob/master/nix/hm-module.nix - programs.walker = { - enable = true; - - #!! Service must be restarted for changes to take effect - #?? systemctl --user restart walker.service - runAsService = true; - - # https://github.com/abenz1267/walker/wiki/Basic-Configuration - # https://github.com/abenz1267/walker/blob/master/internal/config/config.default.toml - config = { - activation_mode.disabled = true; # Key chords - close_when_open = true; - disable_click_to_close = true; - force_keyboard_focus = true; - hotreload_theme = true; - ignore_mouse = true; - - list = { - placeholder = ""; - }; - - search = { - placeholder = ""; - #// resume_last_query = true; - }; - - # https://github.com/abenz1267/walker/wiki/Modules - # https://github.com/PapirusDevelopmentTeam/papirus-icon-theme/tree/master/Papirus/64x64 - disabled = [ - "ai" - "commands" - "custom_commands" - "finder" - "websearch" # Replaced by custom plugin - "windows" - ]; - - builtins = let - in { - applications = { - actions.enabled = false; - hide_without_query = true; - placeholder = ""; - show_generic = false; - switcher_only = false; - }; - - bookmarks = { - icon = "user-bookmarks"; - placeholder = ""; - prefix = "b"; - switcher_only = false; - }; - - calc = { - icon = "accessories-calculator"; - min_chars = 1; - placeholder = ""; - prefix = "="; - show_icon_when_single = true; - switcher_only = false; - }; - - clipboard = { - max_entries = 50; - placeholder = ""; - switcher_only = true; - }; - - dmenu = { - keep_sort = true; - placeholder = "Input"; - switcher_only = true; - }; - - emojis = { - placeholder = ""; - prefix = "`"; - switcher_only = false; - }; - - finder = { - icon = "filetypes"; - placeholder = ""; - prefix = "//"; - show_icon_when_single = true; - switcher_only = false; - }; - - runner = { - icon = "utilities-x-terminal"; - placeholder = ""; - prefix = ">"; - show_icon_when_single = true; - switcher_only = false; - }; - - ssh = { - icon = "folder-remote-symbolic"; - placeholder = ""; - prefix = "ssh"; - show_icon_when_single = true; - switcher_only = false; - }; - - switcher = { - icon = "application-default-icon"; - prefix = "/"; - show_icon_when_single = true; - }; - - symbols = { - placeholder = ""; - prefix = "sym"; - switcher_only = false; - }; - - translation = { - icon = "translator"; - placeholder = ""; - prefix = "tr"; - switcher_only = false; - }; - - websearch = { - placeholder = "system-search"; - switcher_only = false; - entries = [{}]; - }; - }; - - # TODO: Keybinds - # https://github.com/abenz1267/walker/wiki/Keybinds - - # https://github.com/abenz1267/walker/wiki/Plugins - plugins = [ - { - # Search engines by keyword prefix - name = "search"; - placeholder = ""; - show_icon_when_single = true; - switcher_only = false; - - src = "${pkgs.writeShellApplication { - name = "search"; - text = readFile ./search.sh; - runtimeInputs = with pkgs; [coreutils jq xdg-utils]; - }}/bin/search '%TERM%'"; - } - ]; - }; - - # https://github.com/abenz1267/walker/wiki/Theming - theme = { - style = '' - #box { - border: ${toString config.custom.border}px #073642 solid; - font: larger ${config.custom.settings.fonts.sans-serif}; - } - - ${readFile ./style.css} - ''; - - # https://github.com/abenz1267/walker/blob/master/internal/config/layout.default.toml - layout.ui.window = let - w = 750; - h = 300; - in { - width = w; - height = h; - - box = { - h_align = "fill"; - width = -1; - height = -1; - - scroll = { - h_align = "fill"; - h_scrollbar_policy = "external"; - v_scrollbar_policy = "external"; - - list = { - width = -1; - height = -1; - min_width = -1; - min_height = -1; - max_width = w; - max_height = h; - - item = { - text = { - sub = { - hide = true; # Subtext - }; - }; - }; - }; - }; - }; - }; - }; - }; - - # # HACK: Create theme files for module prompt icons - # #?? MODULE.theme = "icon-ICON" - # # https://github.com/abenz1267/walker/blob/bb584eab3b0cc48ebfbac1a5da019864d74781c4/nix/hm-module.nix#L86 - # xdg.configFile = listToAttrs (flatten (forEach cfg.icons ( - # icon: [ - # { - # name = "walker/themes/icon-${icon}.css"; - # value = {text = hm.programs.walker.theme.style;}; - # } - # { - # name = "walker/themes/icon-${icon}.json"; - # value = { - # text = builtins.toJSON (recursiveUpdate hm.programs.walker.theme.layout { - # ui.window.box.search.prompt.icon = icon; - # }); - # }; - # } - # ] - # ))); - - # HACK: Allow child processes to live, otherwise applications launched through service are killed on stop - # https://www.freedesktop.org/software/systemd/man/latest/systemd.kill.html#KillMode= - systemd.user.services.walker.Service.KillMode = "process"; - }; -} diff --git a/options/custom/scripts/bwm.sh b/options/custom/scripts/bwm.sh deleted file mode 100644 index 0d3a2c4..0000000 --- a/options/custom/scripts/bwm.sh +++ /dev/null @@ -1,50 +0,0 @@ -#! /usr/bin/env bash - -# Bitwarden dmenu -# TODO: Clear clipboard after timer - -SESSIONFILE="$XDG_RUNTIME_DIR/bwm" - -# Use current session if exists -if test -f "$SESSIONFILE"; then - BW_SESSION="$(cat "$SESSIONFILE")" && export BW_SESSION -fi - -# Unlock vault if needed -if ! bw unlock --check; then - # Prompt for obfuscated password - password="$(wofi --dmenu --password --lines 3 <<< 'Vault locked. Enter master password.')" - - # Save session to /tmp - BW_SESSION="$(bw unlock "$password" --raw)" && export BW_SESSION - touch "$SESSIONFILE" - chmod u=rw,g=,o= "$SESSIONFILE" - echo "$BW_SESSION" > "$SESSIONFILE" -fi - -# Prompt for search term -search="$(wofi --dmenu --lines 3 <<< 'Enter item to search.')" - -# Gather and parse results -items="$(bw list items --search "$search")" -usernames="$(jq -r '.[].login.username' <<< "$items")" -passwords="$(jq -r '.[].login.password' <<< "$items")" - -# Prompt to select username -username="$(wofi --dmenu <<< "$usernames")" - -# Find matching password line number -count=1 - -while IFS= read -r username; do - if [[ "$username" == "$username" ]]; then - break - else - ((count++)) - fi -done <<< "$usernames" - -# Copy line to clipboard -tail --lines "+$count" <<< "$passwords" | head -1 | tee >(xclip -rmlastnl -selection clipboard &> /dev/null) >(wl-copy --trim-newline &> /dev/null) - -notify-send '> bwm' 'Copied' --urgency low diff --git a/options/custom/scripts/default.nix b/options/custom/scripts/default.nix index f82f729..46f8931 100644 --- a/options/custom/scripts/default.nix +++ b/options/custom/scripts/default.nix @@ -51,15 +51,6 @@ in { easyeffects libnotify ]) - (bash "bwm" [ - bitwarden-cli - coreutils - jq - libnotify - wl-clipboard - wofi - xclip - ]) (bash "calc" [ coreutils libnotify @@ -179,6 +170,15 @@ in { jq libnotify ]) + (bash "vault" [ + argc + bitwarden-cli + coreutils + jq + libnotify + walker + wl-clipboard + ]) (bash "vpn" [ gnused jq diff --git a/options/custom/scripts/vault.sh b/options/custom/scripts/vault.sh new file mode 100644 index 0000000..0ed3600 --- /dev/null +++ b/options/custom/scripts/vault.sh @@ -0,0 +1,74 @@ +#! /usr/bin/env bash + +# @describe Bitwarden menu client +# +# https://github.com/sigoden/argc + +# @meta combine-shorts + +eval "$(argc --argc-eval "$0" "$@")" + +SESSIONFILE="$XDG_RUNTIME_DIR/vault" + +# Use current session if exists +if test -f "$SESSIONFILE"; then + BW_SESSION="$(cat "$SESSIONFILE")" && export BW_SESSION +fi + +# Unlock vault if needed +if ! bw unlock --check; then + # Log in if needed + if ! bw login --check; then + # Prompt for server URL + BW_SERVER="$(walker --dmenu --forceprint <<< "Logged out. Enter server URL.")" + + # Use server in bw config + bw config server "$BW_SERVER" + + # Prompt for email and password + BW_EMAIL="$(walker --dmenu --forceprint <<< "Saved. Enter email address.")" + BW_PASSWORD="$(walker --dmenu --forceprint <<< "Saved. Enter master password.")" + + # Log in to vault + BW_SESSION="$(bw login --raw "$BW_EMAIL" "$BW_PASSWORD")" && export BW_SESSION + else + # BUG: Walker crashes in password mode + # Prompt for obfuscated password + BW_PASSWORD="$(walker --dmenu --forceprint <<< "Vault locked. Enter master password.")" + + # Unlock vault + BW_SESSION="$(bw unlock --raw "$BW_PASSWORD")" && export BW_SESSION + fi + + # Save session to file + touch "$SESSIONFILE" + chmod u=rw,g=,o= "$SESSIONFILE" + echo "$BW_SESSION" > "$SESSIONFILE" +fi + +# Prompt for search term +search="$(walker --dmenu --forceprint <<< "Enter item to search.")" + +# Gather and parse results +items="$(bw list items --search "$search")" +usernames="$(jq -r ".[].login.username" <<< "$items")" +passwords="$(jq -r ".[].login.password" <<< "$items")" + +# Prompt to select username +username="$(walker --dmenu <<< "$usernames")" + +# Find matching password line number +count=1 + +while IFS= read -r username; do + if [[ "$username" == "$username" ]]; then + break + else + ((count++)) + fi +done <<< "$usernames" + +# Copy line to clipboard +tail --lines "+$count" <<< "$passwords" | head -1 | wl-copy --trim-newline &> /dev/null + +notify-send "> bwm" "Copied" --urgency low