@@ -0,0 +1,111 @@
1+use std::collections::HashMap;
2+use std::sync::{Arc, Mutex};
3+
4+use crate::tui::{AppState, VibeboxCommands};
5+use crate::vm::IoControl;
6+
7+#[derive(Clone, Copy)]
8+enum CommandKind {
9+ Help,
10+ Exit,
11+}
12+
13+struct CommandSpec {
14+ name: &'static str,
15+ description: &'static str,
16+ kind: CommandKind,
17+ shell_alias: Option<&'static str>,
18+}
19+
20+const COMMAND_SPECS: &[CommandSpec] = &[
21+ CommandSpec {
22+ name: ":help",
23+ description: "Show Vibebox commands.",
24+ kind: CommandKind::Help,
25+ shell_alias: Some("vibebox_help"),
26+ },
27+ CommandSpec {
28+ name: ":exit",
29+ description: "Exit Vibebox.",
30+ kind: CommandKind::Exit,
31+ shell_alias: Some("exit"),
32+ },
33+];
34+
35+pub struct CommandHandlers {
36+ handlers: HashMap<String, Box<dyn Fn() + Send + Sync>>,
37+}
38+
39+impl CommandHandlers {
40+ fn new() -> Self {
41+ Self {
42+ handlers: HashMap::new(),
43+ }
44+ }
45+
46+ fn register<F>(&mut self, name: &str, handler: F)
47+ where
48+ F: Fn() + Send + Sync + 'static,
49+ {
50+ self.handlers.insert(name.to_string(), Box::new(handler));
51+ }
52+
53+ pub fn handle(&self, line: &str) -> bool {
54+ if let Some(handler) = self.handlers.get(line) {
55+ handler();
56+ true
57+ } else {
58+ false
59+ }
60+ }
61+}
62+
63+pub fn build_commands() -> VibeboxCommands {
64+ let mut commands = VibeboxCommands::new_empty();
65+ for spec in COMMAND_SPECS {
66+ commands.add_command(spec.name, spec.description);
67+ }
68+ commands
69+}
70+
71+pub fn render_shell_script() -> String {
72+ let mut lines = Vec::new();
73+ lines.push("vibebox_help() {".to_string());
74+ lines.push(" cat <<'VIBEBOX_HELP'".to_string());
75+ lines.push("Vibebox Commands".to_string());
76+ for spec in COMMAND_SPECS {
77+ lines.push(format!("{} {}", spec.name, spec.description));
78+ }
79+ lines.push("VIBEBOX_HELP".to_string());
80+ lines.push("}".to_string());
81+ for spec in COMMAND_SPECS {
82+ if let Some(alias) = spec.shell_alias {
83+ lines.push(format!("alias {}='{}'", spec.name, alias));
84+ }
85+ }
86+ lines.join("\n")
87+}
88+
89+pub fn build_handlers(app: Arc<Mutex<AppState>>, io_control: Arc<IoControl>) -> CommandHandlers {
90+ let mut handlers = CommandHandlers::new();
91+ for spec in COMMAND_SPECS {
92+ match spec.kind {
93+ CommandKind::Help => {
94+ let app = app.clone();
95+ handlers.register(spec.name, move || {
96+ if let Ok(mut locked) = app.lock() {
97+ let _ = crate::tui::render_commands_component(&mut locked);
98+ }
99+ });
100+ }
101+ CommandKind::Exit => {
102+ let io_control = io_control.clone();
103+ handlers.register(spec.name, move || {
104+ io_control.request_terminal_restore();
105+ std::process::exit(0);
106+ });
107+ }
108+ }
109+ }
110+ handlers
111+}