Skip to content

desktops: see a hand-written shortcut without claiming it - #100

Merged
davidboulay merged 1 commit into
mainfrom
fix/detect-unmanaged-shortcut
Sep 19, 2026
Merged

davidboulay merged 1 commit into
mainfrom
fix/detect-unmanaged-shortcut

Conversation

@davidboulay

Copy link
Copy Markdown
Owner

read_shortcut() reads only the managed block, so a binding the user wrote themselves is invisible. clippy status prints shortcut: not set beside a binding that plainly works, and setup-shortcut tells them to do a job already done. Following that advice into the settings picker makes it worse: the picker writes our block without noticing theirs, and now two binds fire on one press.

Reading only our own block is right for writing — Clippy must never rewrite a line it did not write — but it was also being used to answer "is a shortcut set", which is a different question.

The fix

read_unmanaged_shortcut(), read-only by construction. Omarchy loads bindings.lua after its defaults, so a hand-written bind sits there beside ours; plain Hyprland gets a file of our own, so the user's own binding is in hyprland.conf instead. Our managed block is stripped before scanning, or we would report ourselves.

Matching is anchored on the executable name and the subcommand together (clippy toggle|show|hide). Matching clippy loose would claim any binding whose path merely contains the word — a checkout under ~/src/clippy, a wrapper named clippy-debug — and claiming someone else's binding is a worse failure than missing our own.

Three call sites:

  • clippy status reports it, marked (set by hand; Clippy's settings won't change it) so the distinction stays visible
  • the settings window shows it on the button instead of falling back to a stale saved value
  • the picker now says a hand-written bind is still live after saving, rather than leaving a duplicate to be discovered by pressing the key

Shortcut stays Tuple[List[str], str] — adding a managed field would have changed the shape at all three call sites for a flag only one of them wants. The setup.py wrapper is getattr-guarded so a backend predating this reads as "none found" rather than raising through status.

Testing

unmanaged_shortcut_test.py holds the line that matters: after set_shortcut and again after remove_shortcut, the hand-written line is still there byte for byte. Seeing is not owning. It also covers the overmatch cases above and the plain-Hyprland file.

Verified on an Omarchy install with a hand-written SUPER+SHIFT+V: status went from not set to Super+Shift+V (set by hand…).

🤖 Generated with Claude Code

read_shortcut() reads only the managed block, so a binding the user wrote
themselves is invisible. `clippy status` prints "shortcut: not set" beside a
binding that plainly works, and setup-shortcut tells them to do a job already
done. Following that advice into the settings picker makes it worse: the picker
writes our block without noticing theirs, and now two binds fire on one press.

Reading only our own block is right for *writing* -- Clippy must never rewrite a
line it did not write -- but it was also being used to answer "is a shortcut
set", which is a different question.

So add read_unmanaged_shortcut(), read-only by construction. Omarchy loads
bindings.lua after its defaults, so a hand-written bind sits there beside ours;
plain Hyprland gets a file of our own, so the user's own binding is in
hyprland.conf instead. Our managed block is stripped before scanning, or we
would report ourselves.

Matching is anchored on the executable name and the subcommand together
(`clippy toggle|show|hide`). Matching "clippy" loose would claim any binding
whose path merely contains the word -- a checkout under ~/src/clippy, a wrapper
named clippy-debug -- and claiming someone else's binding is a worse failure
than missing our own.

Three call sites: `clippy status` reports it, marked "(set by hand; Clippy's
settings won't change it)" so the distinction stays visible; the settings window
shows it on the button instead of falling back to a stale saved value; and the
picker now says a hand-written bind is still live after saving, rather than
leaving a duplicate to be discovered by pressing the key.

Shortcut stays Tuple[List[str], str] -- adding a "managed" field would have
changed the shape at all three call sites for a flag only one of them wants.
The setup.py wrapper is getattr-guarded so a backend predating this reads as
"none found" rather than raising through status.

unmanaged_shortcut_test.py holds the line that matters: after set_shortcut and
again after remove_shortcut, the hand-written line is still there byte for byte.
Seeing is not owning.

Verified on an Omarchy install with a hand-written SUPER+SHIFT+V: status went
from "not set" to "Super+Shift+V  (set by hand…)".

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011QAnwJ7J3jePDGsQsKB47R
@davidboulay
davidboulay merged commit 5c20ba8 into main Sep 19, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant