From 87047b5b1b14a7a423b70ced84e30acb6e549c0b Mon Sep 17 00:00:00 2001 From: Lucien Cartier-Tilet Date: Sun, 2 Nov 2025 17:56:58 +0100 Subject: [PATCH] feat: add wlr-which module and config --- users/modules/desktop/default.nix | 2 + users/modules/desktop/hyprland.nix | 9 +- users/modules/desktop/wlr-which-key.nix | 189 +++++++++++++++ users/modules/dev/editors/emacs.nix | 25 -- users/phundrak/email.nix | 4 +- users/phundrak/home.nix | 52 ++++- .../phundrak/wlr-which-key/center-window.nix | 4 + users/phundrak/wlr-which-key/close-window.nix | 4 + users/phundrak/wlr-which-key/default.nix | 221 ++++++++++++++++++ users/phundrak/wlr-which-key/float-window.nix | 5 + users/phundrak/wlr-which-key/focus-urgent.nix | 4 + users/phundrak/wlr-which-key/fullscreen.nix | 4 + 12 files changed, 484 insertions(+), 39 deletions(-) create mode 100644 users/modules/desktop/wlr-which-key.nix create mode 100644 users/phundrak/wlr-which-key/center-window.nix create mode 100644 users/phundrak/wlr-which-key/close-window.nix create mode 100644 users/phundrak/wlr-which-key/default.nix create mode 100644 users/phundrak/wlr-which-key/float-window.nix create mode 100644 users/phundrak/wlr-which-key/focus-urgent.nix create mode 100644 users/phundrak/wlr-which-key/fullscreen.nix diff --git a/users/modules/desktop/default.nix b/users/modules/desktop/default.nix index 6b1e8b1..dd28fda 100644 --- a/users/modules/desktop/default.nix +++ b/users/modules/desktop/default.nix @@ -16,6 +16,7 @@ in { ./rofi ./swaync.nix ./waybar.nix + ./wlr-which-key.nix ./wlsunset.nix ]; @@ -28,5 +29,6 @@ in { obs.enable = mkDefault cfg.fullDesktop; qt.enable = mkDefault cfg.fullDesktop; rofi.enable = mkDefault cfg.fullDesktop; + wlr-which-key.enable = mkDefault cfg.fullDesktop; }; } diff --git a/users/modules/desktop/hyprland.nix b/users/modules/desktop/hyprland.nix index 8ca43ad..6326987 100644 --- a/users/modules/desktop/hyprland.nix +++ b/users/modules/desktop/hyprland.nix @@ -117,8 +117,8 @@ in { $menu = rofi -combi-modi drun,calc -show combi bind = SUPER, Return, exec, ${pkgs.kitty}/bin/kitty ${pkgs.tmux}/bin/tmux - bind = SUPER, Space, submap, leader - bind = , Print, submap, screenshot + bind = SUPER, Space, exec, ${pkgs.wlr-which-key}/bin/wlr-which-key + bind = , Print, exec, ${pkgs.wlr-which-key}/bin/wlr-which-key -k s submap = leader bind = , l, exec, plock @@ -147,11 +147,13 @@ in { bind = , u, submap, reset bind = , escape, submap, reset bind = CTRL, g, submap, reset + submap = buffers bind = , d, killactive, bind = , d, submap, reset bind = , escape, submap, reset bind = CTRL, g, submap, reset + submap = resize binde = , $left, resizeactive, -10 0 binde = , $right, resizeactive, 10 0 @@ -160,6 +162,7 @@ in { bind = , q, submap, reset bind = , escape, submap, reset bind = CTRL, g, submap, reset + submap = rofi bind = , b, exec, rofi-bluetooth bind = , b, submap, reset @@ -173,6 +176,7 @@ in { bind = , y, submap, reset bind = , escape, submap, reset bind = CTRL, g, submap, reset + submap = screenshot bind = , Print, exec, screenshot bind = , Print, submap, reset @@ -188,6 +192,7 @@ in { bind = Shift, s, submap, reset bind = , escape, submap, reset bind = CTRL, g, submap, reset + submap = windows bind = , period, submap, resize bind = , $left, movefocus, l diff --git a/users/modules/desktop/wlr-which-key.nix b/users/modules/desktop/wlr-which-key.nix new file mode 100644 index 0000000..8882371 --- /dev/null +++ b/users/modules/desktop/wlr-which-key.nix @@ -0,0 +1,189 @@ +{ + config, + lib, + pkgs, + ... +}: let + inherit + (lib) + literalExpression + mkIf + mkOption + mkEnableOption + types + ; + cfg = config.home.desktop.wlr-which-key; + yamlFormat = pkgs.formats.yaml {}; + + # Convert kebab-case to snake_case + toSnakeCase = str: builtins.replaceStrings ["-"] ["_"] str; + + # Recursively filter out null values and convert kebab-case keys to snake_case + filterNulls = value: + if lib.isAttrs value + then lib.mapAttrs' (n: v: lib.nameValuePair (toSnakeCase n) (filterNulls v)) (lib.filterAttrs (n: v: v != null) value) + else if lib.isList value + then map filterNulls value + else value; + menuEntryType = types.submodule { + freeformType = yamlFormat.type; + options = with types; { + key = mkOption { + type = str; + example = "p"; + }; + desc = mkOption { + type = str; + example = "Power"; + }; + cmd = mkOption { + type = nullOr str; + default = null; + example = "echo example"; + }; + keep-open = mkOption { + type = nullOr bool; + default = null; + example = true; + }; + submenu = mkOption { + type = nullOr (listOf menuEntryType); + default = null; + example = literalExpression '' + [ + { key = "s"; desc = "Suspend"; cmd = "systemctl suspend"; } + { key = "r"; desc = "Reboot"; cmd = "systemctl reboot"; } + { key = "o"; desc = "Poweroff"; cmd = "systemctl poweroff"; } + ] + ''; + }; + }; + }; + settingsType = types.submodule { + freeformType = yamlFormat.type; + options = with types; { + background = mkOption { + type = nullOr str; + default = null; + example = "#282828FF"; + }; + color = mkOption { + type = nullOr str; + default = null; + example = "#FBF1C7FF"; + }; + border = mkOption { + type = nullOr str; + default = null; + example = "#8EC07CFF"; + }; + anchor = mkOption { + type = nullOr (enum ["center" "top" "bottom" "left" "right" "top-left" "top-right" "bottom-left" "bottom-right"]); + default = null; + example = "top-left"; + }; + margin-top = mkOption { + type = nullOr int; + default = null; + example = "0"; + }; + margin-right = mkOption { + type = nullOr int; + default = null; + example = "0"; + }; + margin-bottom = mkOption { + type = nullOr int; + default = null; + example = "0"; + }; + margin-left = mkOption { + type = nullOr int; + default = null; + example = "0"; + }; + font = mkOption { + type = nullOr str; + default = null; + example = "monospace 10"; + }; + separator = mkOption { + type = nullOr str; + default = null; + example = " ➜ "; + }; + border-width = mkOption { + type = nullOr (either float int); + default = null; + example = 4.0; + }; + corder-r = mkOption { + type = nullOr (either float int); + default = null; + example = 20.0; + }; + padding = mkOption { + type = nullOr (either float int); + default = null; + example = 15.0; + }; + rows-per-column = mkOption { + type = nullOr int; + default = null; + example = 5; + }; + column-padding = mkOption { + type = nullOr (either float int); + default = null; + example = 25.0; + }; + inhibit-compositor-keyboard-shortcuts = mkOption { + type = bool; + default = true; + example = false; + }; + auto_kbd_layout = mkOption { + type = bool; + default = true; + example = false; + }; + namespace = mkOption { + type = nullOr str; + default = null; + example = "wlr_which_key"; + }; + menu = mkOption { + type = listOf menuEntryType; + default = []; + example = literalExpression '' + [ + { + key = "p"; + desc = "Power"; + submenu = [ + { key = "s"; desc = "Suspend"; cmd = "systemctl suspend"; } + { key = "r"; desc = "Reboot"; cmd = "systemctl reboot"; } + { key = "o"; desc = "Poweroff"; cmd = "systemctl poweroff"; } + ]; + } + ] + ''; + }; + }; + }; +in { + options.home.desktop.wlr-which-key = { + enable = mkEnableOption "Enables wlr-which-key"; + package = lib.mkPackageOption pkgs "wlr-which-key" {}; + settings = mkOption { + type = settingsType; + default = {}; + description = "Configuration written to {file}`$XDG_CONFIG_HOME/wlr-which-key/config.yaml`."; + }; + }; + config = mkIf cfg.enable { + xdg.configFile = { + "wlr-which-key/config.yaml".source = yamlFormat.generate "wlr-which-key-config.yml" (filterNulls cfg.settings); + }; + }; +} diff --git a/users/modules/dev/editors/emacs.nix b/users/modules/dev/editors/emacs.nix index 893b850..2c85ffb 100644 --- a/users/modules/dev/editors/emacs.nix +++ b/users/modules/dev/editors/emacs.nix @@ -10,31 +10,6 @@ with lib; let with epkgs; [ mu4e pdf-tools - tree-sitter - tree-sitter-langs - (treesit-grammars.with-grammars (grammar: - with grammar; [ - tree-sitter-bash - tree-sitter-c - tree-sitter-cpp - tree-sitter-css - tree-sitter-dockerfile - tree-sitter-http - tree-sitter-javascript - tree-sitter-jsdoc - tree-sitter-json - tree-sitter-just - tree-sitter-markdown - tree-sitter-markdown-inline - tree-sitter-nix - tree-sitter-rust - tree-sitter-sql - tree-sitter-toml - tree-sitter-typescript - tree-sitter-typst - tree-sitter-vue - tree-sitter-yaml - ])) ] )); cfg = config.home.dev.editors.emacs; diff --git a/users/phundrak/email.nix b/users/phundrak/email.nix index 77f8d91..fb364bc 100644 --- a/users/phundrak/email.nix +++ b/users/phundrak/email.nix @@ -6,8 +6,8 @@ Sent from GNU/Emacs - *** Sauvez un arbre, mangez un castor *** - *** Save a tree, eat a beaver *** + @@@ Sauvez un arbre, mangez un castor @@@ + @@@ Save a tree, eat a beaver @@@ ''; in { home.file.".signature" = { diff --git a/users/phundrak/home.nix b/users/phundrak/home.nix index b65eb2f..b688f4a 100644 --- a/users/phundrak/home.nix +++ b/users/phundrak/home.nix @@ -7,15 +7,42 @@ ./light-home.nix ./packages.nix ./email.nix + ./wlr-which-key ../modules ]; config = let - emacsPkg = with pkgs; ((emacsPackagesFor emacs).emacsWithPackages ( - epkgs: [ - epkgs.mu4e - epkgs.pdf-tools - ] + emacsPackage = with pkgs; ((emacsPackagesFor emacs).emacsWithPackages ( + epkgs: + with epkgs; [ + mu4e + pdf-tools + tree-sitter + tree-sitter-langs + (treesit-grammars.with-grammars (grammar: + with grammar; [ + tree-sitter-bash + tree-sitter-c + tree-sitter-cpp + tree-sitter-css + tree-sitter-dockerfile + tree-sitter-http + tree-sitter-javascript + tree-sitter-jsdoc + tree-sitter-json + tree-sitter-just + tree-sitter-markdown + tree-sitter-markdown-inline + tree-sitter-nix + tree-sitter-rust + tree-sitter-sql + tree-sitter-toml + tree-sitter-typescript + tree-sitter-typst + tree-sitter-vue + tree-sitter-yaml + ])) + ] )); askpass = import ../modules/cli/scripts/askpass.nix {inherit pkgs;}; launchWithEmacsclient = import ../modules/cli/scripts/launch-with-emacsclient.nix { @@ -30,18 +57,23 @@ home = { sessionVariables = { - EDITOR = "${emacsPkg}/bin/emacsclient -c -a ${emacsPkg}/bin/emacs"; + EDITOR = "${config.home.dev.editors.emacs.package}/bin/emacsclient -c -a ${config.home.dev.editors.emacs.package}/bin/emacs"; LAUNCH_EDITOR = "${launchWithEmacsclient}/bin/launch-with-emacsclient"; SUDO_ASKPASS = "${askpass}/bin/askpass"; LSP_USE_PLISTS = "true"; }; - desktop.waybar.style = ./config/waybar/style.css; - dev.ai.claude.enable = true; + dev = { + ai.claude.enable = true; + editors.emacs.package = emacsPackage; + vcs.jj.signing.enable = true; + }; fullDesktop = true; - shell.fish.enable = true; }; - manual.html.enable = true; + manual = { + html.enable = true; + manpages.enable = true; + }; }; } diff --git a/users/phundrak/wlr-which-key/center-window.nix b/users/phundrak/wlr-which-key/center-window.nix new file mode 100644 index 0000000..12d86fb --- /dev/null +++ b/users/phundrak/wlr-which-key/center-window.nix @@ -0,0 +1,4 @@ +{pkgs, ...}: +pkgs.writeShellScriptBin "center-window" '' + pidof -x Hyprland && hyprctl dispatch centerwindow +'' diff --git a/users/phundrak/wlr-which-key/close-window.nix b/users/phundrak/wlr-which-key/close-window.nix new file mode 100644 index 0000000..d55d3ff --- /dev/null +++ b/users/phundrak/wlr-which-key/close-window.nix @@ -0,0 +1,4 @@ +{pkgs, ...}: +pkgs.writeShellScriptBin "close-window" '' + pidof -x Hyprland && hyprctl dispatch killactive +'' diff --git a/users/phundrak/wlr-which-key/default.nix b/users/phundrak/wlr-which-key/default.nix new file mode 100644 index 0000000..5fc2322 --- /dev/null +++ b/users/phundrak/wlr-which-key/default.nix @@ -0,0 +1,221 @@ +{ + config, + pkgs, + ... +}: { + config.home.desktop.wlr-which-key.settings = { + font = "Cascadia Code 12"; + background = "#3b4252d0"; + color = "#eceff4"; + border = "#2e3440"; + border_width = 2; + corner_r = 10; + rows_per_column = 5; + column_padding = 25; + inhibit_compositor_keyboard_shortcuts = true; + auto_kbd_layout = true; + menu = let + left = "c"; + down = "t"; + up = "s"; + right = "r"; + center-window = import ./center-window.nix {inherit pkgs;}; + close-window = import ./close-window.nix {inherit pkgs;}; + float-window = import ./float-window.nix {inherit pkgs;}; + focus-urgent = import ./focus-urgent.nix {inherit pkgs;}; + fullscreen = import ./fullscreen.nix {inherit pkgs;}; + ytplay = import ../../modules/cli/scripts/ytplay.nix {inherit pkgs;}; + in [ + { + key = "a"; + desc = "Apps"; + submenu = [ + { + key = "b"; + desc = "Browser"; + cmd = "zen"; + } + { + key = "B"; + desc = "Qutebrowser"; + cmd = "${pkgs.qutebrowser}/bin/qutebrowser"; + } + { + key = "d"; + desc = "Discord"; + cmd = "${pkgs.vesktop}/bin/vesktop"; + } + { + key = "e"; + desc = "Emacs"; + cmd = "${config.home.dev.editors.emacs.package}/bin/emacsclient -c -n"; + } + { + key = "g"; + desc = "Gimp"; + cmd = "${pkgs.gimp}/bin/gimp"; + } + { + key = "n"; + desc = "Nemo"; + cmd = "${pkgs.nemo}/bin/nemo"; + } + { + key = "N"; + desc = "Nextcloud"; + cmd = "${pkgs.nextcloud-client}/bin/nextcloud"; + } + { + key = "r"; + desc = "Rofi"; + submenu = [ + { + key = "b"; + desc = "Bluetooth"; + cmd = "${pkgs.rofi-bluetooth}/bin/rofi-bluetooth"; + } + { + key = "e"; + desc = "Emoji"; + cmd = "rofi -show emoji"; + } + { + key = "r"; + desc = "App Menu"; + cmd = "rofi -combi-modi drun,calc -show combi"; + } + { + key = "s"; + desc = "SSH"; + cmd = "rofi -show ssh"; + } + { + key = "y"; + desc = "YouTube"; + cmd = "${ytplay}/bin/ytplay"; + } + ]; + } + ]; + } + { + key = "b"; + desc = "Buffers"; + submenu = [ + { + key = "c"; + desc = "Center"; + cmd = "${center-window}/bin/center-window"; + } + { + key = "d"; + desc = "Close"; + cmd = "${close-window}/bin/close-window"; + } + { + key = "f"; + desc = "Fullscreen"; + cmd = "${fullscreen}/bin/fullscreen"; + } + { + key = "F"; + desc = "Float"; + cmd = "${float-window}/bin/float-window"; + } + { + key = "u"; + desc = "Urgent"; + cmd = "${focus-urgent}/bin/focus-urgent"; + } + { + key = "."; + desc = "Resize"; + submenu = [ + { + key = left; + desc = "Decrease Width"; + cmd = "echo decrease width"; + keep-open = true; + } + { + key = down; + desc = "Increase Height"; + cmd = "echo decrease height"; + keep-open = true; + } + { + key = up; + desc = "Decrease Height"; + cmd = "echo decrease height"; + keep-open = true; + } + { + key = right; + desc = "Increase Width"; + cmd = "echo increase width"; + keep-open = true; + } + ]; + } + ]; + } + { + key = "p"; + desc = "Power"; + submenu = [ + { + key = "s"; + desc = "Suspend"; + cmd = "systemctl suspend"; + } + { + key = "r"; + desc = "Reboot"; + cmd = "systemctl reboot"; + } + { + key = "o"; + desc = "Poweroff"; + cmd = "systemctl poweroff"; + } + ]; + } + { + key = "s"; + desc = "Screenshots"; + submenu = [ + { + key = "Print"; + desc = "Screenshot"; + cmd = "screenshot"; + } + { + key = "d"; + desc = "Delayed"; + cmd = "screenshot -d 3"; + } + { + key = "D"; + desc = "Select, Delay, Edit, and Copy"; + cmd = "screenshot -secd 3"; + } + { + key = "e"; + desc = "Select, Edit, and Copy"; + cmd = "screenshot -sec"; + } + { + key = "g"; + desc = "Select, Gimp, and Copy"; + cmd = "screenshot -sgc"; + } + { + key = "s"; + desc = "Select and Copy"; + cmd = "screenshot -sc"; + } + ]; + } + ]; + }; +} diff --git a/users/phundrak/wlr-which-key/float-window.nix b/users/phundrak/wlr-which-key/float-window.nix new file mode 100644 index 0000000..43ff4b7 --- /dev/null +++ b/users/phundrak/wlr-which-key/float-window.nix @@ -0,0 +1,5 @@ +{pkgs, ...}: +pkgs.writeShellScriptBin "float" '' + pidof -x Hyprland && hyprctl dispatch togglefloating + echo test +'' diff --git a/users/phundrak/wlr-which-key/focus-urgent.nix b/users/phundrak/wlr-which-key/focus-urgent.nix new file mode 100644 index 0000000..5751382 --- /dev/null +++ b/users/phundrak/wlr-which-key/focus-urgent.nix @@ -0,0 +1,4 @@ +{pkgs, ...}: +pkgs.writeShellScriptBin "focus-urgent" '' + pidof -x Hyprland && hyprctl dispatch focusurgentorlast +'' diff --git a/users/phundrak/wlr-which-key/fullscreen.nix b/users/phundrak/wlr-which-key/fullscreen.nix new file mode 100644 index 0000000..d05070d --- /dev/null +++ b/users/phundrak/wlr-which-key/fullscreen.nix @@ -0,0 +1,4 @@ +{pkgs, ...}: +pkgs.writeShellScriptBin "fullscreen" '' + pidof -x Hyprland && hyprctl dispatch fullscreen +''