返回 CodeWhale
hotbar.rs
根目录 / crates / tui / src / commands / groups / core / hotbar.rs
1 //! `/hotbar` command.
2
3 use crate::commands::traits::{CommandInfo, RegisterCommand};
4 use crate::localization::MessageId;
5 use crate::tui::app::{App, AppAction};
6
7 use super::CommandResult;
8
9 pub(in crate::commands) const COMMAND_INFO: CommandInfo = CommandInfo {
10 name: "hotbar",
11 aliases: &["hotkeys"],
12 usage: "/hotbar",
13 description_id: MessageId::CmdHotbarDescription,
14 };
15
16 pub(in crate::commands) struct HotbarCmd;
17
18 impl RegisterCommand for HotbarCmd {
19 fn info() -> &'static CommandInfo {
20 &COMMAND_INFO
21 }
22
23 fn execute(_app: &mut App, arg: Option<&str>) -> CommandResult {
24 match arg.map(str::trim).filter(|arg| !arg.is_empty()) {
25 None | Some("setup" | "edit" | "configure" | "config") => {
26 CommandResult::action(AppAction::OpenHotbarSetup)
27 }
28 // Hide the Hotbar: persist `hotbar = []` and clear the live slots.
29 Some("off" | "disable" | "hide") => CommandResult::action(AppAction::DisableHotbar),
30 // Restore the default recommended slots (explicit reset).
31 Some("on" | "reset" | "defaults" | "default") => {
32 CommandResult::action(AppAction::RestoreHotbarDefaults)
33 }
34 Some("help" | "?") => CommandResult::message(
35 "Hotbar gives you Alt+1 through Alt+8 shortcuts (Option key on macOS, Alt \
36 elsewhere). Use `/hotbar` to customize, `/hotbar off` to hide it \
37 (`hotbar = []`), and `/hotbar on` to restore the default slots. \
38 Hotbar slots dispatch only when no modal, inline picker, or \
39 onboarding surface owns input. Bare 1-8 insert text in the \
40 composer. Cmd-number and F-keys are not Hotbar shortcuts unless \
41 a future release documents and implements them.",
42 ),
43 Some(other) => CommandResult::error(format!(
44 "Unknown /hotbar target '{other}'. Try `/hotbar`, `/hotbar off`, \
45 `/hotbar on`, or `/hotbar help`."
46 )),
47 }
48 }
49 }
50
51 #[cfg(test)]
52 mod tests {
53 use super::*;
54 use crate::config::Config;
55 use crate::tui::app::TuiOptions;
56 use std::path::PathBuf;
57
58 fn test_app() -> App {
59 let options = TuiOptions {
60 ..crate::test_support::test_tui_options(PathBuf::from("."))
61 };
62 App::new(options, &Config::default())
63 }
64
65 #[test]
66 fn hotbar_command_opens_setup_view() {
67 let mut app = test_app();
68
69 let result = HotbarCmd::execute(&mut app, None);
70
71 assert_eq!(result.action, Some(AppAction::OpenHotbarSetup));
72 assert!(result.message.is_none());
73 }
74
75 #[test]
76 fn hotbar_setup_alias_opens_setup_view() {
77 let mut app = test_app();
78
79 let result = HotbarCmd::execute(&mut app, Some("setup"));
80
81 assert_eq!(result.action, Some(AppAction::OpenHotbarSetup));
82 assert!(result.message.is_none());
83 }
84
85 #[test]
86 fn hotbar_help_arg_explains_customize_and_disable() {
87 let mut app = test_app();
88
89 let result = HotbarCmd::execute(&mut app, Some("help"));
90
91 assert!(!result.is_error);
92 assert!(result.action.is_none());
93 let message = result
94 .message
95 .as_deref()
96 .expect("help should return a message");
97 assert!(
98 message.contains("/hotbar")
99 && message.contains("customize")
100 && message.contains("Alt+1 through Alt+8"),
101 "help should point at /hotbar to customize: {message:?}"
102 );
103 assert!(
104 message.contains("hotbar = []"),
105 "help should mention the explicit disabled config: {message:?}"
106 );
107 assert!(
108 message.contains("/hotbar off") && message.contains("/hotbar on"),
109 "help should mention both disable and restore paths: {message:?}"
110 );
111 assert!(message.contains("Bare 1-8 insert text"));
112 assert!(message.contains("Cmd-number and F-keys are not Hotbar shortcuts"));
113 }
114
115 #[test]
116 fn hotbar_off_and_disable_aliases_return_disable_action() {
117 for arg in ["off", "disable", "hide"] {
118 let mut app = test_app();
119 let result = HotbarCmd::execute(&mut app, Some(arg));
120 assert_eq!(
121 result.action,
122 Some(AppAction::DisableHotbar),
123 "`/hotbar {arg}` should disable the hotbar"
124 );
125 assert!(
126 result.message.is_none(),
127 "`/hotbar {arg}` should not also emit a message"
128 );
129 }
130 }
131
132 #[test]
133 fn hotbar_on_and_reset_aliases_return_restore_action() {
134 for arg in ["on", "reset", "defaults", "default"] {
135 let mut app = test_app();
136 let result = HotbarCmd::execute(&mut app, Some(arg));
137 assert_eq!(
138 result.action,
139 Some(AppAction::RestoreHotbarDefaults),
140 "`/hotbar {arg}` should restore default hotbar slots"
141 );
142 assert!(result.message.is_none());
143 }
144 }
145
146 #[test]
147 fn hotbar_unknown_arg_reports_error() {
148 let mut app = test_app();
149
150 let result = HotbarCmd::execute(&mut app, Some("bogus"));
151
152 assert!(result.is_error);
153 assert!(result.action.is_none());
154 assert!(
155 result
156 .message
157 .as_deref()
158 .is_some_and(|message| message.contains("Unknown /hotbar target 'bogus'"))
159 );
160 }
161 }
162
162 lines RUST