hypr: make Super+Alt+C toggle a runtime-selectable AI scratchpad
Super+Alt+C now toggles whichever AI app is currently selected (Codex or Claude Desktop) instead of always Codex. The selection is read from $XDG_STATE_HOME/hypr/ai-scratchpad at keypress time, so switching is dynamic and needs no Hyprland reload. Hyper+C opens a rofi chooser (rofi_ai_scratchpad.sh) to pick between the two, replacing the old "Open Codex session menu" binding. It writes the choice and brings the selected scratchpad into view. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -68,7 +68,7 @@ function M.setup(ctx)
|
|||||||
bind(hyper .. " + V", exec([[cliphist list | rofi -dmenu -p "Clipboard" | cliphist decode | wl-copy]]), desc("Open clipboard history"))
|
bind(hyper .. " + V", exec([[cliphist list | rofi -dmenu -p "Clipboard" | cliphist decode | wl-copy]]), desc("Open clipboard history"))
|
||||||
bind(hyper .. " + P", exec("rofi-pass"), desc("Open password menu"))
|
bind(hyper .. " + P", exec("rofi-pass"), desc("Open password menu"))
|
||||||
bind(hyper .. " + N", exec("rofi_codex_desktop_project.sh"), desc("Start Codex Desktop thread from project"))
|
bind(hyper .. " + N", exec("rofi_codex_desktop_project.sh"), desc("Start Codex Desktop thread from project"))
|
||||||
bind(hyper .. " + C", exec("rofi_tmcodex.sh"), desc("Open Codex session menu"))
|
bind(hyper .. " + C", exec("rofi_ai_scratchpad.sh"), desc("Choose AI scratchpad (Codex/Claude)"))
|
||||||
bind(hyper .. " + SHIFT + C", exec("rofi_tmcodex.sh resume"), desc("Resume Codex session"))
|
bind(hyper .. " + SHIFT + C", exec("rofi_tmcodex.sh resume"), desc("Resume Codex session"))
|
||||||
bind(hyper .. " + L", exec("hypr_rofi_layout"), desc("Open Hyprland layout menu"))
|
bind(hyper .. " + L", exec("hypr_rofi_layout"), desc("Open Hyprland layout menu"))
|
||||||
bind(hyper .. " + K", exec("rofi_kill_process.sh"), desc("Open process kill menu"))
|
bind(hyper .. " + K", exec("rofi_kill_process.sh"), desc("Open process kill menu"))
|
||||||
@@ -264,9 +264,7 @@ function M.setup(ctx)
|
|||||||
|
|
||||||
local function setup_scratchpad_bindings()
|
local function setup_scratchpad_bindings()
|
||||||
bind(main_mod .. " + SHIFT + X", hl.dsp.workspace.toggle_special("NSP"), desc("Toggle NSP special workspace"))
|
bind(main_mod .. " + SHIFT + X", hl.dsp.workspace.toggle_special("NSP"), desc("Toggle NSP special workspace"))
|
||||||
bind(mod_alt .. " + C", function()
|
bind(mod_alt .. " + C", toggle_active_ai_scratchpad, desc("Toggle AI scratchpad (Codex/Claude)"))
|
||||||
toggle_scratchpad("codex")
|
|
||||||
end, desc("Toggle Codex scratchpad"))
|
|
||||||
bind(mod_alt .. " + D", function()
|
bind(mod_alt .. " + D", function()
|
||||||
toggle_scratchpad("discord")
|
toggle_scratchpad("discord")
|
||||||
end, desc("Toggle Discord scratchpad"))
|
end, desc("Toggle Discord scratchpad"))
|
||||||
|
|||||||
@@ -17,6 +17,11 @@ function M.setup(ctx)
|
|||||||
class = "codex-desktop",
|
class = "codex-desktop",
|
||||||
allow_tiling = true,
|
allow_tiling = true,
|
||||||
},
|
},
|
||||||
|
claude = {
|
||||||
|
command = "claude-desktop",
|
||||||
|
class = "claude-desktop",
|
||||||
|
allow_tiling = true,
|
||||||
|
},
|
||||||
htop = {
|
htop = {
|
||||||
command = "alacritty --class htop-scratch --title htop -e htop",
|
command = "alacritty --class htop-scratch --title htop -e htop",
|
||||||
class = "htop-scratch",
|
class = "htop-scratch",
|
||||||
@@ -517,6 +522,49 @@ function M.setup(ctx)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Which AI scratchpad SUPER+ALT+C targets. Selected at runtime (no reload)
|
||||||
|
-- by rofi_ai_scratchpad.sh, which writes the chosen name to this file.
|
||||||
|
local ai_scratchpad_default = "codex"
|
||||||
|
|
||||||
|
local function ai_scratchpad_state_path()
|
||||||
|
local base = os.getenv("XDG_STATE_HOME") or ((os.getenv("HOME") or "") .. "/.local/state")
|
||||||
|
return base .. "/hypr/ai-scratchpad"
|
||||||
|
end
|
||||||
|
|
||||||
|
local function active_ai_scratchpad()
|
||||||
|
local file = io.open(ai_scratchpad_state_path(), "r")
|
||||||
|
if not file then
|
||||||
|
return ai_scratchpad_default
|
||||||
|
end
|
||||||
|
|
||||||
|
local value = file:read("*l")
|
||||||
|
file:close()
|
||||||
|
value = value and value:gsub("%s+", "")
|
||||||
|
if scratchpads[value] then
|
||||||
|
return value
|
||||||
|
end
|
||||||
|
return ai_scratchpad_default
|
||||||
|
end
|
||||||
|
|
||||||
|
local function toggle_active_ai_scratchpad()
|
||||||
|
toggle_scratchpad(active_ai_scratchpad())
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Used by rofi_ai_scratchpad.sh after a selection: bring the chosen
|
||||||
|
-- scratchpad into view if it isn't already, without hiding it when it is.
|
||||||
|
local function show_active_ai_scratchpad()
|
||||||
|
local name = active_ai_scratchpad()
|
||||||
|
for _, window in ipairs(matching_scratchpad_windows(name)) do
|
||||||
|
if scratchpad_is_visible(window) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
toggle_scratchpad(name)
|
||||||
|
end
|
||||||
|
|
||||||
|
_G.im_hyprland_toggle_ai_scratchpad = toggle_active_ai_scratchpad
|
||||||
|
_G.im_hyprland_show_ai_scratchpad = show_active_ai_scratchpad
|
||||||
|
|
||||||
ctx.lower_contains = lower_contains
|
ctx.lower_contains = lower_contains
|
||||||
ctx.lower_contains_any = lower_contains_any
|
ctx.lower_contains_any = lower_contains_any
|
||||||
ctx.scratchpad_window_matches = scratchpad_window_matches
|
ctx.scratchpad_window_matches = scratchpad_window_matches
|
||||||
@@ -552,6 +600,9 @@ function M.setup(ctx)
|
|||||||
ctx.refresh_shell_workarea_and_scratchpads = refresh_shell_workarea_and_scratchpads
|
ctx.refresh_shell_workarea_and_scratchpads = refresh_shell_workarea_and_scratchpads
|
||||||
ctx.adopt_matching_scratchpad_window = adopt_matching_scratchpad_window
|
ctx.adopt_matching_scratchpad_window = adopt_matching_scratchpad_window
|
||||||
ctx.toggle_scratchpad = toggle_scratchpad
|
ctx.toggle_scratchpad = toggle_scratchpad
|
||||||
|
ctx.active_ai_scratchpad = active_ai_scratchpad
|
||||||
|
ctx.toggle_active_ai_scratchpad = toggle_active_ai_scratchpad
|
||||||
|
ctx.show_active_ai_scratchpad = show_active_ai_scratchpad
|
||||||
end
|
end
|
||||||
|
|
||||||
return M
|
return M
|
||||||
|
|||||||
39
dotfiles/lib/bin/rofi_ai_scratchpad.sh
Executable file
39
dotfiles/lib/bin/rofi_ai_scratchpad.sh
Executable file
@@ -0,0 +1,39 @@
|
|||||||
|
#!/usr/bin/env zsh
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Choose which AI app SUPER+ALT+C toggles as a scratchpad: Codex or Claude
|
||||||
|
# Desktop. The choice is written to a state file that the Hyprland Lua config
|
||||||
|
# reads at keypress time, so switching is dynamic and needs no reload.
|
||||||
|
|
||||||
|
state_file="${XDG_STATE_HOME:-$HOME/.local/state}/hypr/ai-scratchpad"
|
||||||
|
mkdir -p "${state_file:h}"
|
||||||
|
|
||||||
|
names=(codex claude)
|
||||||
|
labels=("Codex" "Claude Desktop")
|
||||||
|
|
||||||
|
current=codex
|
||||||
|
[[ -r "$state_file" ]] && current="$(<"$state_file")"
|
||||||
|
|
||||||
|
menu=""
|
||||||
|
for i in {1..${#names}}; do
|
||||||
|
marker=" "
|
||||||
|
[[ "${names[$i]}" == "$current" ]] && marker="● "
|
||||||
|
menu+="${marker}${labels[$i]}\n"
|
||||||
|
done
|
||||||
|
|
||||||
|
index="$(printf "$menu" | rofi -dmenu -i -p "AI scratchpad" -format i)" || exit 0
|
||||||
|
[[ -n "$index" ]] || exit 0
|
||||||
|
|
||||||
|
selected="${names[$((index + 1))]}"
|
||||||
|
[[ -n "$selected" ]] || exit 0
|
||||||
|
|
||||||
|
print -r -- "$selected" > "$state_file"
|
||||||
|
|
||||||
|
# Bring the freshly selected scratchpad into view (no-op if already visible).
|
||||||
|
if command -v hyprctl >/dev/null 2>&1; then
|
||||||
|
hyprctl -q eval "_G.im_hyprland_show_ai_scratchpad()" >/dev/null 2>&1 || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v notify-send >/dev/null 2>&1; then
|
||||||
|
notify-send "AI scratchpad" "Super+Alt+C now toggles ${labels[$((index + 1))]}" || true
|
||||||
|
fi
|
||||||
Reference in New Issue
Block a user