tui/focus.rs
1//! Focus-target resolver.
2//!
3//! A single canonical precedence order governs both key translation and event
4//! dispatch: **Overlay > CmdLine > ConsoleInput > ViewPane**. Both
5//! [`crate::keymap::translate`] and [`crate::event::apply`] call
6//! [`current_focus`] so neither can drift from the other.
7
8use crate::app::App;
9
10#[cfg(test)]
11mod tests;
12
13/// Which layer currently owns keyboard input.
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub enum FocusTarget {
16 /// An overlay (modal/form) is open and intercepts all input.
17 Overlay,
18 /// The command-line palette is active.
19 CmdLine,
20 /// The console input prompt has focus.
21 ConsoleInput,
22 /// The active view pane owns input (default).
23 ViewPane,
24}
25
26/// Canonical focus resolver — both translate and apply must call this.
27///
28/// Precedence: Overlay > CmdLine > ConsoleInput > ViewPane.
29/// States are structurally mutually exclusive for the higher layers:
30/// opening the cmdline or an overlay is the only way to gain that focus,
31/// and closing it restores the layer below.
32#[must_use]
33pub fn current_focus(app: &App) -> FocusTarget {
34 if !app.overlays.is_empty() {
35 FocusTarget::Overlay
36 } else if app.cmdline.active {
37 FocusTarget::CmdLine
38 } else if app.console_focused {
39 FocusTarget::ConsoleInput
40 } else {
41 FocusTarget::ViewPane
42 }
43}