From f814639556592cb78b0a96d99cdcff60cdfd9403 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Mon, 28 Sep 2026 11:48:28 +0200 Subject: [PATCH] Hand the terminal launcher the focused window's pid from Lua (#13521) To open a new terminal in the focused terminal's directory, the launcher asked Hyprland for the active window with hyprctl, ~10ms on every SUPER+RETURN. The binding now reads the pid from hl.get_active_window() and passes it as --pid. Without one, from the menu or a shell, the launcher asks Hyprland as before. The bind is now a Lua function, which Hyprland reports only as __lua, so o.bind_commands records the command it stands for and the keybindings menu still launches a terminal when the entry is picked. Co-authored-by: Claude Opus 5.5 --- bin/omarchy-cmd-terminal-cwd | 3 ++- bin/omarchy-launch-terminal | 10 ++++++++-- bin/omarchy-menu-keybindings | 5 ++++- default/hypr/bindings/applications.lua | 2 +- default/hypr/helpers.lua | 20 ++++++++++++++++++++ test/shell.d/keybindings-menu-test.sh | 12 ++++++++++++ test/shell.d/terminal-cwd-test.sh | 12 ++++++++++++ 7 files changed, 59 insertions(+), 5 deletions(-) diff --git a/bin/omarchy-cmd-terminal-cwd b/bin/omarchy-cmd-terminal-cwd index f44f1636..60586185 100755 --- a/bin/omarchy-cmd-terminal-cwd +++ b/bin/omarchy-cmd-terminal-cwd @@ -1,9 +1,10 @@ #!/bin/bash # omarchy:summary=Print the current working directory of the active terminal window +# omarchy:args=[terminal-pid] # omarchy:hidden=true -terminal_pid=$(hyprctl activewindow | awk '/pid:/ {print $2}') +terminal_pid=${1:-$(hyprctl activewindow | awk '/pid:/ {print $2}')} kitty_socket="$XDG_RUNTIME_DIR/omarchy-kitty-$terminal_pid" cwd="" diff --git a/bin/omarchy-launch-terminal b/bin/omarchy-launch-terminal index a07a1dde..bd0acbf0 100755 --- a/bin/omarchy-launch-terminal +++ b/bin/omarchy-launch-terminal @@ -1,6 +1,12 @@ #!/bin/bash # omarchy:summary=Launch a terminal in the active terminal's current directory -# omarchy:args=[command...] +# omarchy:args=[--pid=] [command...] -exec setsid uwsm-app -- xdg-terminal-exec --dir="$(omarchy-cmd-terminal-cwd)" "$@" +pid="" +if [[ ${1:-} == --pid=* ]]; then + pid=${1#--pid=} + shift +fi + +exec setsid uwsm-app -- xdg-terminal-exec --dir="$(omarchy-cmd-terminal-cwd "$pid")" "$@" diff --git a/bin/omarchy-menu-keybindings b/bin/omarchy-menu-keybindings index 767b5dac..153a4d29 100755 --- a/bin/omarchy-menu-keybindings +++ b/bin/omarchy-menu-keybindings @@ -210,6 +210,9 @@ hl = setmetatable({ elseif type(bind_dispatcher) == "string" and bind_dispatcher ~= "" then kind = "exec" arg = bind_dispatcher + elseif o and o.bind_commands and o.bind_commands[bind_dispatcher] then + kind = "exec" + arg = o.bind_commands[bind_dispatcher] end print(table.concat({ tostring(modmask), opts.description, key, kind, arg }, "\t")) @@ -530,7 +533,7 @@ output_binding_records_uncached() { keybindings_cache_key() { { - printf 'v13\n' + printf 'v14\n' hyprctl devices 2>/dev/null | grep -F 'active keymap:' hyprctl binds 2>/dev/null } | sha256sum | awk '{ print $1 }' diff --git a/default/hypr/bindings/applications.lua b/default/hypr/bindings/applications.lua index 0c990e64..e4428a9f 100644 --- a/default/hypr/bindings/applications.lua +++ b/default/hypr/bindings/applications.lua @@ -1,5 +1,5 @@ -- Essential application bindings. -o.bind("SUPER + RETURN", "Terminal", { omarchy = "terminal" }) +o.bind("SUPER + RETURN", "Terminal", o.launch_terminal()) o.bind("SUPER + SHIFT + RETURN", "Browser", { omarchy = "browser" }) o.bind("SUPER + SHIFT + F", "File manager", { omarchy = "nautilus" }) o.bind("SUPER + ALT + SHIFT + F", "File manager (cwd)", { omarchy = "nautilus-cwd" }) diff --git a/default/hypr/helpers.lua b/default/hypr/helpers.lua index f75e9091..05f8f91e 100644 --- a/default/hypr/helpers.lua +++ b/default/hypr/helpers.lua @@ -160,6 +160,26 @@ function o.launch(command) return "uwsm-app -- " .. command end +-- The command each function bind stands for, so the keybindings menu can still +-- run a bind that Hyprland only reports as Lua. +o.bind_commands = {} + +-- Hand the launcher the focused window's pid, which it would otherwise ask +-- Hyprland for, to open the new terminal in that terminal's directory. +function o.launch_terminal() + local function launch() + local window = hl.get_active_window() + if window and window.pid then + hl.exec_cmd("omarchy-launch-terminal --pid=" .. window.pid) + else + hl.exec_cmd("omarchy-launch-terminal") + end + end + + o.bind_commands[launch] = "omarchy-launch-terminal" + return launch +end + function o.exec_on_start(command) hl.on("hyprland.start", function() hl.exec_cmd(command) diff --git a/test/shell.d/keybindings-menu-test.sh b/test/shell.d/keybindings-menu-test.sh index 3e0da288..5f962e6a 100755 --- a/test/shell.d/keybindings-menu-test.sh +++ b/test/shell.d/keybindings-menu-test.sh @@ -220,3 +220,15 @@ for action in "${expected_alternatives[@]}"; do fail "every action named as having an alternative is bound twice" "$action" done pass "every action named as having an alternative is bound twice" + +# The terminal bind is a Lua function Hyprland reports only as __lua, so picking +# it from the menu has to run the command the function stands for. +stub_hyprctl </dev/null +grep -qP '→ Terminal\texec\tomarchy-launch-terminal$' "$tmpdir"/cache/omarchy/keybindings-*.records || + fail "picking the terminal bind from the menu launches a terminal" "$(cat "$tmpdir"/cache/omarchy/keybindings-*.records)" +pass "picking the terminal bind from the menu launches a terminal" diff --git a/test/shell.d/terminal-cwd-test.sh b/test/shell.d/terminal-cwd-test.sh index 4584f698..ecbd8eb6 100644 --- a/test/shell.d/terminal-cwd-test.sh +++ b/test/shell.d/terminal-cwd-test.sh @@ -43,3 +43,15 @@ pass "a new terminal opens in the focused terminal's shell directory" output=$(PATH="$stub_bin:$PATH" XDG_RUNTIME_DIR="$test_tmp" HOME="$test_tmp" "$ROOT/bin/omarchy-cmd-terminal-cwd" 2>&1) [[ $output == "$test_tmp" ]] || fail "with no focused terminal the new one opens in HOME" "got: $output" pass "with no focused terminal the new one opens in HOME, quietly" + +# The Super+Return binding hands over the focused window's pid, so Hyprland is +# not asked again; a hyprctl that fails the test proves it goes unasked. +cat >"$stub_bin/hyprctl" <<'SH' +#!/bin/bash +echo "hyprctl was asked for the active window" >&2 +exit 1 +SH + +cwd=$(PATH="$stub_bin:$PATH" XDG_RUNTIME_DIR="$test_tmp" "$ROOT/bin/omarchy-cmd-terminal-cwd" "$terminal_pid" 2>&1) +[[ $cwd == "$work_dir" ]] || fail "a terminal pid passed in finds its shell directory without hyprctl" "got: $cwd" +pass "a terminal pid passed in finds its shell directory without hyprctl"