From 3eb05515a1de3a4fd87354d0e6a42d21ff891ce8 Mon Sep 17 00:00:00 2001 From: Ivan Malison Date: Tue, 28 Apr 2026 14:53:28 -0700 Subject: [PATCH] Restore hyprexpo on Hyprland Lua branch --- docs/hyprland-lua-migration-checklist.md | 17 +++++--- dotfiles/config/hypr/hyprland.lua | 50 +++++++++++++++++++++--- nixos/flake.lock | 32 +++++++++++++++ nixos/flake.nix | 7 ++++ nixos/hyprland.nix | 9 +++-- 5 files changed, 100 insertions(+), 15 deletions(-) diff --git a/docs/hyprland-lua-migration-checklist.md b/docs/hyprland-lua-migration-checklist.md index a183f9e5..09053633 100644 --- a/docs/hyprland-lua-migration-checklist.md +++ b/docs/hyprland-lua-migration-checklist.md @@ -16,9 +16,10 @@ Guiding rule for shelling out: - [x] Update/confirm Hyprland Lua input at latest usable upstream target. - [x] Keep stable Hyprland path intact until Lua path is proven. -- [x] Keep hy3/hyprexpo out of the Lua branch. +- [x] Keep hy3 out of the Lua branch. - [x] Keep hyprNStack following the Lua Hyprland input. - [x] Rebuild hyprNStack against the Lua Hyprland branch. +- [x] Add a forked hyprexpo input for the Lua Hyprland branch. - [x] Keep a cheap Lua check: parse config, execute against stub, reject `hyprctl` in the Lua config's window/workspace manipulation path. - [x] Add a real Hyprland Lua verifier check for the config parser path. @@ -26,7 +27,8 @@ Guiding rule for shelling out: Current upstream note: latest Hyprland release observed during this migration is `v0.54.3`; the Lua config input tracks PR 13817 and was already at the current PR head `c35a8a5` dated 2026-04-26. The non-Lua fallback remains pinned to the older -hy3/hyprexpo-compatible stack. +hy3/hyprexpo-compatible stack; the Lua branch uses forked hyprexpo branch +`colonelpanic8/hyprland-plugins:hyprexpo-lua-hyprland`. ## 1. Core Layout @@ -98,9 +100,9 @@ verifier mode. ## 5. Overview And Window Discovery -- [x] Replace hyprexpo with the first-pass Lua numbered window picker. -- [x] Implement first-pass `Super+Tab` overview via Lua window picker. -- [x] Implement first-pass `Super+Shift+Tab` bring overview via Lua window picker. +- [x] Restore visual hyprexpo for `Super+Tab` overview. +- [x] Restore visual hyprexpo `bring` mode for `Super+Shift+Tab`. +- [x] Keep first-pass Lua numbered window picker on secondary bindings. - [x] Implement first-pass Lua-native go-to-window picker. - [x] Implement first-pass Lua-native bring-window picker. - [x] Implement first-pass Lua-native replace-window picker. @@ -116,6 +118,10 @@ The first pass therefore uses Lua-native numbered submaps and notifications. A final rofi/icon picker would need either a small IPC bridge or an upstream Lua process-output/callback primitive. +Hyprexpo decision: hyprexpo is kept as the visual overview. The forked Lua +branch exposes `hl.plugin.hyprexpo.expo(...)`, so the Lua config can invoke +`toggle` and `bring` directly without shelling out to `hyprctl`. + ## 6. Scratchpads - [x] Preserve named scratchpads: element, gmail, htop, messages, slack, @@ -191,6 +197,7 @@ needs a live readback check. - [x] `hyprctl` rejection in Lua config for window/workspace manipulation. - [x] Real `Hyprland --verify-config` check. - [x] hyprNStack flake build check. +- [x] hyprexpo Lua-branch flake build check. - [x] `ryzen-shine` system dry-run. - [x] Re-run checks after Hyprland/Lua input confirmation. - [ ] Try live compositor smoke test again after version bump. diff --git a/dotfiles/config/hypr/hyprland.lua b/dotfiles/config/hypr/hyprland.lua index 42d74dc3..3583f1a1 100644 --- a/dotfiles/config/hypr/hyprland.lua +++ b/dotfiles/config/hypr/hyprland.lua @@ -83,6 +83,22 @@ local function exec(command) return hl.dsp.exec_cmd(command) end +local function hyprexpo(action) + return function() + if hl.plugin and hl.plugin.hyprexpo and hl.plugin.hyprexpo.expo then + hl.plugin.hyprexpo.expo(action) + else + hl.notification.create({ + text = "hyprexpo is not loaded", + duration = 1800, + icon = "warning", + color = "rgba(edb443ff)", + font_size = 13, + }) + end + end +end + local function apply_nstack_config() if verify_config then return @@ -108,6 +124,27 @@ local function apply_nstack_config() }) end +local function apply_hyprexpo_config() + if verify_config then + return + end + + hl.config({ + plugin = { + hyprexpo = { + columns = 3, + gap_size = 5, + bg_col = "rgba(111111ff)", + workspace_method = "center current", + skip_empty = false, + show_workspace_numbers = true, + workspace_number_color = "rgba(edb443ff)", + gesture_distance = 200, + }, + }, + }) +end + local function active_workspace() return hl.get_active_workspace() end @@ -998,6 +1035,9 @@ local function toggle_scratchpad(name) end hl.plugin.load("/run/current-system/sw/lib/libhyprNStack.so") +if not verify_config then + hl.plugin.load("/run/current-system/sw/lib/libhyprexpo.so") +end hl.env("XCURSOR_SIZE", "24") hl.env("HYPRCURSOR_SIZE", "24") @@ -1127,12 +1167,8 @@ bind(main_mod .. " + SHIFT + C", hl.dsp.window.close()) bind(main_mod .. " + SHIFT + Q", hl.dsp.exit()) bind(main_mod .. " + E", exec("emacsclient --eval '(emacs-everywhere)'")) bind(main_mod .. " + V", exec("wl-paste | xdotool type --file -")) -bind(main_mod .. " + Tab", function() - enter_window_picker("go") -end) -bind(main_mod .. " + SHIFT + Tab", function() - enter_window_picker("bring") -end) +bind(main_mod .. " + Tab", hyprexpo("toggle")) +bind(main_mod .. " + SHIFT + Tab", hyprexpo("bring")) bind(main_mod .. " + G", function() enter_window_picker("go") end) @@ -1351,6 +1387,7 @@ bind(main_mod .. " + mouse:273", hl.dsp.window.resize()) hl.on("hyprland.start", function() apply_nstack_config() + apply_hyprexpo_config() hl.exec_cmd("sh -lc 'export IMALISON_SESSION_TYPE=wayland; dbus-update-activation-environment --systemd WAYLAND_DISPLAY DISPLAY XAUTHORITY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP XDG_SESSION_TYPE IMALISON_SESSION_TYPE; systemctl --user start graphical-session.target hyprland-session.target'") hl.exec_cmd("hypridle") hl.exec_cmd("wl-paste --type text --watch cliphist store") @@ -1361,6 +1398,7 @@ hl.on("hyprland.start", function() end) hl.on("config.reloaded", apply_nstack_config) +hl.on("config.reloaded", apply_hyprexpo_config) hl.on("window.open", schedule_nstack_count_update) hl.on("window.destroy", schedule_nstack_count_update) diff --git a/nixos/flake.lock b/nixos/flake.lock index fb1051f7..ed1b2792 100644 --- a/nixos/flake.lock +++ b/nixos/flake.lock @@ -1121,6 +1121,37 @@ "type": "github" } }, + "hyprland-plugins-lua": { + "inputs": { + "hyprland": [ + "hyprland-lua-config" + ], + "nixpkgs": [ + "hyprland-plugins-lua", + "hyprland", + "nixpkgs" + ], + "systems": [ + "hyprland-plugins-lua", + "hyprland", + "systems" + ] + }, + "locked": { + "lastModified": 1777412965, + "narHash": "sha256-lVGYGUWf9ynV5lR8QAygAfmYRkko1btIe26UcQ1bGXw=", + "owner": "colonelpanic8", + "repo": "hyprland-plugins", + "rev": "fd5a23b732d881233941402984cbc4903e6ed927", + "type": "github" + }, + "original": { + "owner": "colonelpanic8", + "ref": "hyprexpo-lua-hyprland", + "repo": "hyprland-plugins", + "type": "github" + } + }, "hyprland-protocols": { "inputs": { "nixpkgs": [ @@ -2132,6 +2163,7 @@ "hyprland": "hyprland", "hyprland-lua-config": "hyprland-lua-config", "hyprland-plugins": "hyprland-plugins", + "hyprland-plugins-lua": "hyprland-plugins-lua", "hyprscratch": "hyprscratch", "imalison-taffybar": "imalison-taffybar", "kanshi-sni": "kanshi-sni", diff --git a/nixos/flake.nix b/nixos/flake.nix index e444d49d..d95e060e 100644 --- a/nixos/flake.nix +++ b/nixos/flake.nix @@ -119,6 +119,11 @@ inputs.hyprland.follows = "hyprland"; }; + hyprland-plugins-lua = { + url = "github:colonelpanic8/hyprland-plugins?ref=hyprexpo-lua-hyprland"; + inputs.hyprland.follows = "hyprland-lua-config"; + }; + hyprscratch = { url = "github:colonelpanic8/hyprscratch/reapply-rules-on-toggle"; inputs.nixpkgs.follows = "nixpkgs"; @@ -498,10 +503,12 @@ kat-org-agenda-api = containerLib.containers.kat; } // lib.optionalAttrs pkgs.stdenv.isLinux { hyprNStack = inputs.hyprNStack.packages.${system}.hyprNStack; + hyprexpo-lua = inputs.hyprland-plugins-lua.packages.${system}.hyprexpo; }; checks = lib.optionalAttrs pkgs.stdenv.isLinux { hyprNStack = inputs.hyprNStack.packages.${system}.hyprNStack; + hyprexpo-lua = inputs.hyprland-plugins-lua.packages.${system}.hyprexpo; hyprland-lua-config-syntax = pkgs.runCommand "hyprland-lua-config-syntax" { nativeBuildInputs = [ pkgs.lua5_4 ]; } '' diff --git a/nixos/hyprland.nix b/nixos/hyprland.nix index be5cb8f8..def4286d 100644 --- a/nixos/hyprland.nix +++ b/nixos/hyprland.nix @@ -9,6 +9,7 @@ let else inputs.hyprland; luaPluginPackages = lib.optionals cfg.useLuaConfigBranch [ inputs.hyprNStack.packages.${system}.hyprNStack + inputs.hyprland-plugins-lua.packages.${system}.hyprexpo ]; hyprexpoPatched = inputs.hyprland-plugins.packages.${system}.hyprexpo.overrideAttrs (old: { patches = (old.patches or [ ]) ++ [ @@ -162,8 +163,8 @@ let jq ] ++ luaPluginPackages ++ lib.optionals enableExternalPluginPackages [ # External plugin packages are pinned to the stable 0.53 stack. - # PR 13817's Hyprland branch builds, but hy3 / hyprexpo do not yet build - # against it, so keep them out of the experimental Lua branch for now. + # Keep hy3 on the stable stack; the Lua branch uses hyprNStack and the + # forked Lua-compatible hyprexpo input instead. inputs.hy3.packages.${system}.hy3 hyprexpoPatched ]; @@ -176,8 +177,8 @@ enabledModule // { default = false; description = '' Use the experimental Hyprland PR 13817 Lua-config branch for the - Hyprland package itself. The experimental package set excludes hy3 and - hyprexpo, and includes the Lua-branch build of hyprNStack instead. When + Hyprland package itself. The experimental package set excludes hy3, and + includes the Lua-branch builds of hyprNStack and hyprexpo instead. When a sibling `hyprland.lua` is present, the Lua config manager picks it before `hyprland.conf`. '';