Expand description
Keybinding sequence detection and action mapping.
This module implements the keybinding policy specification (bd-2vne.1) for detecting multi-key sequences like Esc Esc and mapping keys to actions based on application state.
§Key Concepts
-
SequenceDetector: State machine that detects Esc Esc sequences with configurable timeout. Single Esc is emitted after timeout or when another key is pressed.
-
SequenceConfig: Configuration for sequence detection including timeout windows and debounce settings.
-
ActionMapper: Maps key events to high-level actions based on application state (input buffer, running tasks, modals, overlays). Integrates with SequenceDetector to handle Esc sequences.
-
AppState: Runtime state flags that affect action resolution.
-
Action: High-level commands like ClearInput, CancelTask, ToggleTreeView.
§State Machine
┌─────────────────────────────────────┐
│ │
▼ │
┌──────────┐ Esc ┌────────────────────┐ timeout ┌─────────┐ │
│ Idle │───────▶│ AwaitingSecondEsc │────────────▶│ Emit(Esc)│ │
└──────────┘ └────────────────────┘ └─────────┘ │
▲ │ │
│ │ Esc (within timeout) │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Emit(EscEsc) │──────────────────────────────────┘
│ └─────────────────┘
│
│ other key
└───────────────────────────────────────────────────────────────────§Example
use std::time::{Duration, Instant};
use ftui_core::keybinding::{SequenceDetector, SequenceConfig, SequenceOutput};
use ftui_core::event::{KeyCode, KeyEvent, Modifiers, KeyEventKind};
let mut detector = SequenceDetector::new(SequenceConfig::default());
let now = Instant::now();
// First Esc: starts the sequence
let esc = KeyEvent::new(KeyCode::Escape);
let output = detector.feed(&esc, now);
assert!(matches!(output, SequenceOutput::Pending));
// Second Esc within timeout: emits EscEsc
let later = now + Duration::from_millis(100);
let output = detector.feed(&esc, later);
assert!(matches!(output, SequenceOutput::EscEsc));§Action Mapping Example
use std::time::Instant;
use ftui_core::keybinding::{ActionMapper, ActionConfig, AppState, Action};
use ftui_core::event::{KeyCode, KeyEvent, Modifiers};
let mut mapper = ActionMapper::new(ActionConfig::default());
let now = Instant::now();
// Ctrl+C with non-empty input: clears input
let state = AppState { input_nonempty: true, ..Default::default() };
let ctrl_c = KeyEvent::new(KeyCode::Char('c')).with_modifiers(Modifiers::CTRL);
let action = mapper.map(&ctrl_c, &state, now);
assert!(matches!(action, Some(Action::ClearInput)));
// Ctrl+C with empty input and no task: quits (by default)
let idle_state = AppState::default();
let action = mapper.map(&ctrl_c, &idle_state, now);
assert!(matches!(action, Some(Action::Quit)));Structs§
- Action
Config - Configuration for action mapping behavior.
- Action
Mapper - Maps key events to high-level actions based on application state.
- AppState
- Runtime state flags that affect keybinding resolution.
- Sequence
Config - Configuration for the sequence detector.
- Sequence
Detector - Stateful detector for multi-key sequences (currently Esc Esc).
Enums§
- Action
- High-level actions that can result from keybinding resolution.
- CtrlC
Idle Action - Behavior when Ctrl+C is pressed with empty input and no running task.
- Sequence
Output - Output from the sequence detector after processing a key event.
Constants§
- DEFAULT_
ESC_ DEBOUNCE_ MS - Default debounce before emitting single Esc.
- DEFAULT_
ESC_ SEQ_ TIMEOUT_ MS - Default timeout for detecting Esc Esc sequence.
- MAX_
ESC_ DEBOUNCE_ MS - Maximum allowed value for Esc debounce.
- MAX_
ESC_ SEQ_ TIMEOUT_ MS - Maximum allowed value for Esc sequence timeout.
- MIN_
ESC_ DEBOUNCE_ MS - Minimum allowed value for Esc debounce.
- MIN_
ESC_ SEQ_ TIMEOUT_ MS - Minimum allowed value for Esc sequence timeout.