Skip to main content

vtcode_ui/design/
keys.rs

1//! Shared keyboard and interaction copy for list modals and command menus.
2//!
3//! One source of truth so footer hints cannot drift across surfaces. Pair
4//! these with `design::list` row kinds: nested views use [`BACK`], top-level
5//! pickers use [`CANCEL`], filter-aware lists append [`FILTER`].
6
7/// Move selection.
8pub const NAVIGATE: &str = "↑↓ select";
9/// Commit the highlighted row.
10pub const APPLY: &str = "Enter apply";
11/// Change a setting value without cycling the row.
12pub const ADJUST: &str = "←→ value";
13/// Type-to-filter affordance (when the list has a search field).
14pub const FILTER: &str = "type to filter";
15/// Nested view: leave this level (root Esc closes).
16pub const BACK: &str = "Esc back";
17/// Top-level picker: dismiss (after clearing a non-empty filter).
18pub const CANCEL: &str = "Esc cancel";
19/// Vim-style movement used by standalone ratatui pickers.
20pub const MOVE_VIM: &str = "↑↓/jk move";
21/// Jump to first/last row.
22pub const ENDS: &str = "Home/End";
23/// Confirm in standalone pickers.
24pub const CONFIRM: &str = "Enter confirm";
25/// Standalone picker Esc: clear filter, then cancel.
26pub const CLEAR_OR_CANCEL: &str = "Esc clear/cancel";
27
28const SEP: &str = " · ";
29
30/// Footer for shared list modals with a search field (settings, model picker).
31pub fn list_hint() -> String {
32    [NAVIGATE, APPLY, ADJUST, FILTER, BACK].join(SEP)
33}
34
35/// Footer for standalone choice pickers (`run_interactive_selection`).
36pub fn choice_hint() -> String {
37    [MOVE_VIM, ENDS, CONFIRM, CLEAR_OR_CANCEL].join(SEP)
38}
39
40#[cfg(test)]
41mod tests {
42    use super::*;
43
44    #[test]
45    fn list_hint_includes_filter_and_back() {
46        let hint = list_hint();
47        assert!(hint.contains(FILTER));
48        assert!(hint.contains(BACK));
49        assert!(hint.contains(NAVIGATE));
50    }
51
52    #[test]
53    fn choice_hint_matches_standalone_picker_verb_set() {
54        let hint = choice_hint();
55        assert!(hint.contains(MOVE_VIM));
56        assert!(hint.contains(CLEAR_OR_CANCEL));
57    }
58}