keymap-core 0.1.1

Environment-aware keymap resolution core for terminal UIs
Documentation
# Changelog

All notable changes to `keymap-core` are recorded here. The format follows
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); the crate follows the
[Cargo pre-1.0 SemVer interpretation](https://doc.rust-lang.org/cargo/reference/semver.html)
(`0.MINOR.PATCH`, where a MINOR bump is breaking).

## [Unreleased]

## [0.1.1] - 2026-06-13

All changes are **additive**; no existing public API is removed or altered.

### Added

- `cmd::CommandIndex<A>` — command-palette index backed by a `BTreeMap<String, A>`.
  `bind(name, action)` (last-write-wins, returns the old value like `Keymap::bind`),
  `get(name) -> Option<&A>` for exact dispatch, `complete(prefix) -> impl Iterator`
  for front-prefix enumeration (lexicographic order is a specification, not an
  implementation detail), and `iter()` for full listing. Module-scoped so a future
  `keymap-cmd` crate extraction is non-destructive (module→crate via shim is
  reversible; the reverse is not).
- `validate_rebind<A>(layers, target, proposed, reserved) -> RebindVerdict<'_, A>`  opt-in advisory validator for runtime rebinding. Checks whether `proposed` collides
  with `reserved` keys (including legacy-terminal collisions via `legacy_form`) before
  any live mutation. **Contract note:** reserved chords are rejected unconditionally —
  this includes re-binding a key to the same action it already holds (strict, no
  same-action exception). The before/after semantic difference from a
  clone-simulate approach is documented here: the example's approach compared the
  resolved action; `validate_rebind` compares the chord itself against the reserved
  set and does not inspect the action value. Callers who want same-action re-binds to
  succeed should filter the reserved set themselves before calling. Not a gate on
  `Keymap::bind` — advisory only; `Keymap::bind` is unchanged.
- `RebindVerdict<'_, A>` (`#[non_exhaustive]`) — result of `validate_rebind`:
  `Allowed { legacy_form: LegacyForm }`, `Blocked { reason: BreakReason }`.
- `BreakReason` (`#[non_exhaustive]`) — reason a rebind was blocked:
  `Reserved { chord: KeyInput }`, `LegacyCollision { chord: KeyInput, collapses_to: KeyInput }`.

## [0.1.0] - 2026-05-28

### Added

- Initial public API: `Key`, `Modifiers`, `KeyInput` (with the `FromStr` /
  `Display` chord grammar and the `KeyInput::normalized` Shift-folding rule),
  and the generic binding table `Keymap<A>` keyed on a caller-defined action
  type `A`.
- `resolve_layered(layers, input)` for lexical-scope-style context resolution
  (first hit wins, miss falls outward), and `resolve_passthrough(layers, input,
  raw) -> Resolution` for PTY-aware misses that carry the original bytes back
  out as `Resolution::Passthrough`.
- `legacy_lints(&Keymap<A>) -> Vec<LegacyLint>` plus `KeyInput::legacy_form()`
  for the static, terminal-independent legacy-C0 survivability lower bound.
- Optional `crossterm` feature: `TryFrom<crossterm::event::KeyEvent> for
  KeyInput`. Gated so a crossterm major bump is not a `keymap-core` major bump
  for default builds.

[Unreleased]: https://github.com/S-Nakamur-a/keymap-rs/commits/main
[0.1.1]: https://crates.io/crates/keymap-core/0.1.1
[0.1.0]: https://crates.io/crates/keymap-core/0.1.0