Skip to content

feat(keys): hint mode and plugin keyboard shortcuts - #64

Merged
Rfluid merged 2 commits into
mainfrom
feat/plugin-keyboard
Sep 25, 2026
Merged

Rfluid merged 2 commits into
mainfrom
feat/plugin-keyboard

Conversation

@Rfluid

@Rfluid Rfluid commented Sep 25, 2026

Copy link
Copy Markdown
Owner

Summary

Keyboard control for plugin panels, in two layers:

  • Hint mode (f, action hint_mode). Every button in a plugin's controls section gets a label (a, s, d… home row first; fixed length so none is a prefix of another). Typing a label presses the button. Confirm buttons arm on the first press and fire on the second. Esc, a click, or any tab/plugin/mode switch leaves hint mode. Works with every existing plugin; no protocol change.
  • Plugin keys. Sections can declare keys: [{ keys, action, label, confirm? }]. Each key sits behind a leader ([keybindings] plugin_leader, default space), so a plugin can never shadow an Aura shortcut. Pressing the leader opens a floating panel at the bottom right listing the section's keys; it narrows as strokes are typed. It waits until the shortcut completes or Esc, or for [keybindings] leader_timeout_ms when set (unset by default).

Design and decisions: docs/plans/plugin-keymaps.md.

How it works

  • Hint mode and leader mode drop the root's keymap contexts, so no binding matches and the root's key_down listener reads the keys. Only the leader itself is a GPUI binding (new plugin context between global and overlay). Aura matches the rest with GPUI's KeyBinding::match_keystrokes instead of binding whole sequences, because GPUI forgets a pending sequence after a fixed second, and Esc during one replayed into dismiss.
  • Clicks, hint labels and plugin keys share one press path (press_plugin_action), so confirm behaves the same everywhere. Esc (and q) disarm an armed button before closing anything.
  • Key resolution lives in aura-core (plugin/keys.rs): the leader goes in front, spellings are canonicalized, bad entries are skipped with warnings, duplicates keep the later entry, and a key that starts another is flagged (the shorter one runs immediately).
  • Remapping plugin keys is left to plugins; Aura installs what the panel declares.

Also in this PR

  • fix(plugin): aura plugin add --link now links to the absolute source path. A relative source (as install.sh --link passes) left a dangling symlink inside the plugins dir, and discovery silently skipped the plugin.
  • aura keys validate now prints its warnings when keybindings.toml doesn't exist (it used to exit 1 with no explanation).
  • CLI: aura plugin run prints each section's resolved keys and warnings on stderr; aura keys validate and aura doctor warn when the leader collides with a [global] binding.
  • Docs: keybindings.md, plugin-authoring.md, configuration.md, .design/components.md.

Testing

  • ./scripts/pre-pr.sh: all checks pass (rustfmt, clippy, test, selectable_text, gitleaks, cargo_audit, build_release).
  • New unit tests: hint labels/matching, key resolution and leader warnings, PluginSection.keys round-trip, absolute symlink target.
  • Manually tested in the modal against the Audio Hooks plugin (companion PR in Rfluid/aura-audio-hooks): hint mode, space panel, confirm keys.

A symlink target resolves against the link's own directory, so a
relative source such as target/release/foo dangled inside the plugins
dir and discovery silently skipped the plugin.
Hint mode (`f`) labels every button in a plugin's controls section;
typing a label presses it, confirm buttons need two presses.

Plugins can declare `keys` per section. Each sits behind a leader
(`[keybindings] plugin_leader`, default `space`) so it can never shadow
an Aura shortcut. Pressing the leader opens leader mode: a floating
panel lists the section's keys and narrows as strokes are typed. Aura
reads the strokes itself instead of binding whole GPUI sequences, so it
waits until the shortcut completes or Escape, or for
`[keybindings] leader_timeout_ms` when set.

Clicks, hint labels and plugin keys share one press path. The help
overlay lists the plugin's keys; `aura plugin run` prints them and any
problems; `aura keys validate` and `aura doctor` warn when the leader
collides with a global binding. `keys validate` now prints its warnings
when keybindings.toml doesn't exist.
@Rfluid
Rfluid merged commit 78ad754 into main Sep 25, 2026
10 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