feat(hyprland): launch-or-focus binds (item 17)
All checks were successful
Check / eval (push) Successful in 3m4s
All checks were successful
Check / eval (push) Successful in 3m4s
nomarchy.launchOrFocus (opt-in, commented template example): each entry gives a key that FOCUSES the app's existing window (case-insensitive class match via jq + a "(?i)" focuswindow regex) or launches it when none is open. One shared nomarchy-focus-or-launch script; a bind whose command was removed from the suite fires a "not installed" toast instead of failing silently. The same entries render into the SUPER+? cheatsheet through prettyKeys — bind and documentation stay one source. README row added. Verified: V0; V1 — a scratch downstream with two entries renders both binds (default command = lowercased class; custom mods/command/desc honored), the script passes bash -n with a usage guard, and the cheatsheet carries both rows. Focus behaviour needs a session -> V3 (HARDWARE-QUEUE). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -31,6 +31,34 @@ let
|
||||
${pkgs.swayosd}/bin/swayosd-client --custom-icon "$icon" --custom-progress "$2"
|
||||
'';
|
||||
|
||||
# Launch-or-focus (nomarchy.launchOrFocus, item 17): focus the app's
|
||||
# window if one exists (case-insensitive class match), launch it
|
||||
# otherwise. Self-gates: an uninstalled command notifies instead of
|
||||
# failing silently, so a bind survives the app being removed from the
|
||||
# suite. rofi.nix renders the same entries into the SUPER+? cheatsheet.
|
||||
focusOrLaunch = pkgs.writeShellScriptBin "nomarchy-focus-or-launch" ''
|
||||
class="''${1:-}"; shift || true
|
||||
[ -n "$class" ] && [ $# -gt 0 ] || {
|
||||
echo "usage: nomarchy-focus-or-launch <class> <command...>" >&2; exit 64
|
||||
}
|
||||
if hyprctl clients -j 2>/dev/null \
|
||||
| ${pkgs.jq}/bin/jq -e --arg c "$class" \
|
||||
'any(.[]; (.class | ascii_downcase) == ($c | ascii_downcase))' >/dev/null; then
|
||||
exec hyprctl dispatch focuswindow "class:(?i)^$class\$"
|
||||
fi
|
||||
command -v "$1" >/dev/null 2>&1 \
|
||||
|| { notify-send "Launch" "$1 is not installed."; exit 0; }
|
||||
exec "$@"
|
||||
'';
|
||||
lofEntries = map
|
||||
(e: e // {
|
||||
command = if e.command == "" then lib.toLower e.class else e.command;
|
||||
})
|
||||
config.nomarchy.launchOrFocus;
|
||||
lofBinds = map
|
||||
(e: "${e.mods}, ${e.key}, exec, ${focusOrLaunch}/bin/nomarchy-focus-or-launch ${e.class} ${e.command}")
|
||||
lofEntries;
|
||||
|
||||
# SUPER+1..9 / SUPER+SHIFT+1..9 workspace binds, generated.
|
||||
workspaceBinds = builtins.concatLists (builtins.genList
|
||||
(i:
|
||||
@@ -393,7 +421,8 @@ in
|
||||
bind = map mkBind (keybinds.binds
|
||||
++ lib.optionals (lib.hasInfix "," config.nomarchy.keyboard.layout)
|
||||
keybinds.multiLayoutBinds)
|
||||
++ workspaceBinds;
|
||||
++ workspaceBinds
|
||||
++ lofBinds;
|
||||
|
||||
# Media keys via swayosd-client: it performs the action AND shows
|
||||
# the on-screen display (the nomarchy.osd module). e = repeat,
|
||||
|
||||
@@ -237,6 +237,52 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
launchOrFocus = lib.mkOption {
|
||||
type = lib.types.listOf (lib.types.submodule {
|
||||
options = {
|
||||
key = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
example = "B";
|
||||
description = "The key (with `mods`) that focuses-or-launches the app.";
|
||||
};
|
||||
mods = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "$mod";
|
||||
description = "Modifier string, Hyprland syntax (\"$mod\", \"$mod SHIFT\").";
|
||||
};
|
||||
class = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
example = "firefox";
|
||||
description = "Window class to focus (case-insensitive; see `hyprctl clients`).";
|
||||
};
|
||||
command = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "";
|
||||
description = "Command to launch when no window matches (defaults to the class).";
|
||||
};
|
||||
desc = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "";
|
||||
description = "Cheatsheet label (defaults to \"Focus or launch <command>\").";
|
||||
};
|
||||
};
|
||||
});
|
||||
default = [ ];
|
||||
example = lib.literalExpression ''
|
||||
[
|
||||
{ key = "B"; class = "firefox"; }
|
||||
{ key = "O"; class = "obsidian"; }
|
||||
]
|
||||
'';
|
||||
description = ''
|
||||
Launch-or-focus binds: the key focuses the app's existing window
|
||||
(case-insensitive class match) or launches it if none is open. Each
|
||||
entry generates a Hyprland bind AND a SUPER+? cheatsheet row. The
|
||||
launcher self-gates: a bind whose command isn't installed notifies
|
||||
instead of failing silently.
|
||||
'';
|
||||
};
|
||||
|
||||
displayProfiles = lib.mkOption {
|
||||
type = lib.types.attrsOf (lib.types.listOf monitorType);
|
||||
default = { };
|
||||
|
||||
@@ -125,6 +125,12 @@ let
|
||||
map (b: padRight 22 (prettyKeys b) + b.desc) (keybinds.binds
|
||||
++ lib.optionals (lib.hasInfix "," cfg.keyboard.layout)
|
||||
keybinds.multiLayoutBinds)
|
||||
# Launch-or-focus binds (nomarchy.launchOrFocus, generated in
|
||||
# hyprland.nix) — same renderer, so they land in the cheatsheet too.
|
||||
++ map (e: padRight 22 (prettyKeys e)
|
||||
+ (if e.desc != "" then e.desc
|
||||
else "Focus or launch ${if e.command == "" then lib.toLower e.class else e.command}"))
|
||||
cfg.launchOrFocus
|
||||
++ map (e: padRight 22 e.keys + e.desc) keybinds.extra;
|
||||
cheatsheetFile = pkgs.writeText "nomarchy-keybinds.txt"
|
||||
(lib.concatStringsSep "\n" cheatRows + "\n");
|
||||
|
||||
Reference in New Issue
Block a user