bubbletea_widgets/list/keys.rs
1//! Key bindings for list component navigation and interaction.
2//!
3//! This module defines the `ListKeyMap` which contains all the key bindings used by the list component
4//! for navigation, filtering, and interaction. The key bindings follow common terminal UI conventions
5//! and vim-style navigation patterns.
6//!
7//! ## Navigation Keys
8//!
9//! - **Cursor Movement**: `↑/k` (up), `↓/j` (down)
10//! - **Page Navigation**: `→/l/pgdn/f/d` (next page), `←/h/pgup/b/u` (prev page)
11//! - **Jump Navigation**: `g/home` (go to start), `G/end` (go to end)
12//!
13//! ## Filtering Keys
14//!
15//! - **Start Filter**: `/` (enter filtering mode)
16//! - **Clear Filter**: `esc` (clear active filter)
17//! - **Cancel Filter**: `esc` (cancel filter input)
18//! - **Accept Filter**: `enter/tab/↑/↓` (apply filter and continue)
19//!
20//! ## Help and Quit Keys
21//!
22//! - **Help**: `?` (show/hide help)
23//! - **Quit**: `q/esc` (normal quit)
24//! - **Force Quit**: `ctrl+c` (immediate quit)
25//!
26//! ## Example
27//!
28//! ```rust
29//! use bubbletea_widgets::list::ListKeyMap;
30//! use bubbletea_widgets::key::KeyMap;
31//!
32//! let keymap = ListKeyMap::default();
33//! let help = keymap.short_help(); // Get key bindings for help display
34//! ```
35
36use crate::key;
37use crossterm::event::KeyCode;
38
39/// Key bindings for list navigation, filtering, help, and exit actions.
40#[derive(Debug, Clone)]
41pub struct ListKeyMap {
42 /// Move selection up one item.
43 pub cursor_up: key::Binding,
44 /// Move selection down one item.
45 pub cursor_down: key::Binding,
46 /// Go to the next page of items.
47 pub next_page: key::Binding,
48 /// Go to the previous page of items.
49 pub prev_page: key::Binding,
50 /// Jump to the first item.
51 pub go_to_start: key::Binding,
52 /// Jump to the last item.
53 pub go_to_end: key::Binding,
54 /// Enter filtering mode.
55 pub filter: key::Binding,
56 /// Clear the active filter.
57 pub clear_filter: key::Binding,
58 /// Cancel filtering mode.
59 pub cancel_filter: key::Binding,
60 /// Accept/apply the current filter input.
61 pub accept_filter: key::Binding,
62 /// Show the full help panel.
63 pub show_full_help: key::Binding,
64 /// Close the full help panel.
65 pub close_full_help: key::Binding,
66 /// Quit.
67 pub quit: key::Binding,
68 /// Force quit.
69 pub force_quit: key::Binding,
70}
71
72impl Default for ListKeyMap {
73 fn default() -> Self {
74 Self {
75 cursor_up: key::Binding::new(vec![KeyCode::Up, KeyCode::Char('k')])
76 .with_help("↑/k", "up"),
77 cursor_down: key::Binding::new(vec![KeyCode::Down, KeyCode::Char('j')])
78 .with_help("↓/j", "down"),
79 next_page: key::Binding::new(vec![
80 KeyCode::Right,
81 KeyCode::Char('l'),
82 KeyCode::PageDown,
83 KeyCode::Char('f'),
84 KeyCode::Char('d'),
85 ])
86 .with_help("→/l/pgdn", "next page"),
87 prev_page: key::Binding::new(vec![
88 KeyCode::Left,
89 KeyCode::Char('h'),
90 KeyCode::PageUp,
91 KeyCode::Char('b'),
92 KeyCode::Char('u'),
93 ])
94 .with_help("←/h/pgup", "prev page"),
95 go_to_start: key::Binding::new(vec![KeyCode::Home, KeyCode::Char('g')])
96 .with_help("g/home", "go to start"),
97 go_to_end: key::Binding::new(vec![KeyCode::End, KeyCode::Char('G')])
98 .with_help("G/end", "go to end"),
99 filter: key::Binding::new(vec![KeyCode::Char('/')]).with_help("/", "filter"),
100 clear_filter: key::Binding::new(vec![KeyCode::Esc]).with_help("esc", "clear filter"),
101 cancel_filter: key::Binding::new(vec![KeyCode::Esc]).with_help("esc", "cancel"),
102 // Simplify accept_filter: Enter, Tab, Up/Down
103 accept_filter: key::Binding::new(vec![
104 KeyCode::Enter,
105 KeyCode::Tab,
106 KeyCode::Up,
107 KeyCode::Down,
108 ])
109 .with_help("enter", "apply filter"),
110 show_full_help: key::Binding::new(vec![KeyCode::Char('?')]).with_help("?", "more"),
111 close_full_help: key::Binding::new(vec![KeyCode::Char('?')])
112 .with_help("?", "close help"),
113 quit: key::Binding::new(vec![KeyCode::Char('q'), KeyCode::Esc]).with_help("q", "quit"),
114 // Use parse string for ctrl+c via key module convenience
115 force_quit: key::new_binding(vec![key::with_keys_str(&["ctrl+c"])])
116 .with_help("ctrl+c", "force quit"),
117 }
118 }
119}
120
121impl key::KeyMap for ListKeyMap {
122 fn short_help(&self) -> Vec<&key::Binding> {
123 vec![&self.cursor_up, &self.cursor_down, &self.filter, &self.quit]
124 }
125
126 fn full_help(&self) -> Vec<Vec<&key::Binding>> {
127 vec![
128 // Column 1: Primary Navigation
129 vec![
130 &self.cursor_up,
131 &self.cursor_down,
132 &self.next_page,
133 &self.prev_page,
134 &self.go_to_start,
135 &self.go_to_end,
136 ],
137 // Column 2: Filtering Actions
138 vec![
139 &self.filter,
140 &self.clear_filter,
141 &self.accept_filter,
142 &self.cancel_filter,
143 ],
144 // Column 3: Help and Quit
145 vec![&self.show_full_help, &self.quit],
146 ]
147 }
148}