Finish vim-style navigation: the search surfaces are the missing half #9371
bradenr402
started this conversation in
Suggestions
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Finish vim-style navigation: the search surfaces are the missing half
The gap
Omarchy already has vim navigation in a good chunk of the shell.
Ui/PanelKeyCatcher.qml:59-70bindsh/j/k/lnext to the arrows:Ten bar panels route through it — network, bluetooth, audio, power, tailscale,
clock, weather, monitor, dropbox, agents.
Ui/Dropdown,Ui/MultiSelectandUi/SearchableDropdownbindj/kin their popup lists;Ui/ButtonGroup.qml:86-101bindsh/l.But four surfaces have no vim navigation at all:
plugins/menu/Menu.qml:1074-1116plugins/clipboard/Clipboard.qml:352-397plugins/emojis/Emojis.qml:197-231plugins/image-picker/ImagePicker.qml:408-432These are, in my experience, the surfaces people drive from the keyboard most.
Why they were skipped, and why it isn't an oversight
All four are search-as-you-type. Each key handler ends in a catch-all along
these lines (
Menu.qml:1113):On these surfaces
h,j,kandlare filter characters. You cannot bindthem to motion without breaking type-to-search, which is the primary
interaction. So this is a genuine design conflict, not a missed spot — it needs
a mode discriminator before it can be resolved either way.
Prior art
Several PRs have approached this from different angles and none has landed:
#8318 sidesteps the conflict with a Ctrl modifier, which works and is
non-breaking, but leaves the shell in the odd position of having bare hjkl in
panels and Ctrl hjkl in overlays — two different vim idioms depending on which
surface has focus.
Proposal
Add a single opt-in setting that turns the four filter surfaces modal, so bare
hjklmeans the same thing everywhere:Normal mode (the default state when a surface opens, when the flag is on):
hjklPanelKeyCatcher's existingmoveRequested(dx, dy)g/GCtrl+D/Ctrl+U/EnterEscSearch mode: exactly today's behavior — type to filter, arrows navigate,
Enter activates.
Escreturns to normal mode keeping the filtered results, sothey can be walked with
hjkl; a secondEscclears the filter; a thirdcloses.
The header needs to show which mode is active, otherwise the modality is
invisible — a leading
/on the query while searching, and a short right-aligned/ searchhint while in normal mode, is enough.Default off. Nothing changes for anyone who does not opt in, and panel
hjklstays unconditional so no existing behavior regresses.Implementation sketch
The natural move is to extend
PanelKeyCatcherrather than add a secondcomponent — it already emits the right semantic signals (
moveRequested,activateRequested,closeRequested,textKey) and already has ablockedescape hatch for inline editors. Adding opt-in
filterable/filterText/vimModeproperties lets the four surfaces adopt the same component and deletetheir hand-rolled
Keys.onPressedblocks.Because
moveRequestedis already 2-D, the grid and carousel cases fall out forfree: emojis interpret
dyas row steps, the image picker ignores it.Config would be read off
shell.shellConfigthe wayplugins/services/idle/Service.qml:19readsidle.lock.One adjacent inconsistency worth folding in or fixing separately:
Ui/ConfirmDialog.qml:23-35handlesLeft/Rightbut noth/l, unlikeButtonGroup.Where I'm coming from
I built this for myself against a local clone of the menu plugin and have been
running it for a bit. The mode model above is what survived contact with actual
use — in particular, keeping the filter alive when leaving search mode turned out
to matter a lot, since narrowing a list and then wanting to walk it is the common
case.
Happy to open a PR if there's interest and if the opt-in-flag shape is the right
one. Wanted to check the direction first rather than add a fifth competing PR to
the four already open on this.
Filed by Claude (Anthropic's Claude Opus 5), acting as a coding agent on
behalf of @bradenr402, who reviewed this before it was posted. The research,
prototype and draft above are the agent's work; the decision to open this
discussion, and the design calls in it, are Braden's.
All reactions