1use crate::cli::{Cli, Commands, CardOperation, BlendCommands};
2use crate::cards::CardManager;
3use crate::errors::{PocketError, PocketResult, IntoPocketError};
4use crate::logging;
5use log::{debug, info, warn, error, LevelFilter};
6use std::path::PathBuf;
7use colored::Colorize;
8
9pub fn handle_command(cli: Cli) -> PocketResult<()> {
11 let log_level = match cli.verbose {
13 0 => LevelFilter::Info,
14 1 => LevelFilter::Debug,
15 _ => LevelFilter::Trace,
16 };
17 logging::init(log_level);
18
19 debug!("Starting pocket CLI with verbosity level {}", cli.verbose);
20
21 let home_dir = std::env::var("HOME")
23 .map_err(|_| PocketError::Config("HOME environment variable not set".to_string()))?;
24 let data_dir = PathBuf::from(&home_dir).join(".pocket");
25
26 let card_dir = data_dir.join("cards");
28 let mut card_manager = CardManager::new(card_dir.clone());
29 card_manager.load_cards()
30 .map_err(|e| PocketError::Card(format!("Failed to load cards: {}", e)))?;
31
32 match cli.command {
34 Commands::Add { file, message, editor, backpack, clipboard, summarize } => {
35 let mut args = Vec::new();
37
38 if let Some(f) = file {
39 args.push(format!("--file={}", f));
40 }
41
42 if let Some(m) = message {
43 args.push(format!("--message={}", m));
44 }
45
46 if editor {
47 args.push("--editor".to_string());
48 }
49
50 if let Some(b) = backpack {
51 args.push(format!("--backpack={}", b));
52 }
53
54 if clipboard {
55 args.push("--clipboard".to_string());
56 }
57
58 if let Some(s) = summarize {
59 args.push(format!("--summarize={}", s));
60 }
61
62 card_manager.execute_command("snippet", "add", &args)
64 .map_err(|e| PocketError::Card(format!("Failed to add snippet: {}", e)))?;
65 },
66
67 Commands::List { all, backpack, json, limit } => {
68 let mut args = Vec::new();
70
71 if all {
72 args.push("--include-backpacks".to_string());
73 }
74
75 if let Some(b) = backpack {
76 args.push("--backpack".to_string());
77 args.push(b);
78 }
79
80 if json {
81 args.push("--json".to_string());
82 }
83
84 args.push("--limit".to_string());
85 args.push(limit.to_string());
86
87 card_manager.execute_command("core", "list", &args)
89 .map_err(|e| PocketError::Card(format!("Failed to list entries: {}", e)))?;
90 },
91
92 Commands::Remove { id, force, backpack } => {
93 let mut args = vec![id];
95
96 if force {
97 args.push("--force".to_string());
98 }
99
100 if let Some(b) = backpack {
101 args.push("--backpack".to_string());
102 args.push(b);
103 }
104
105 card_manager.execute_command("core", "remove", &args)
107 .map_err(|e| PocketError::Card(format!("Failed to remove entry: {}", e)))?;
108 },
109
110 Commands::Create { name, description } => {
111 let mut args = vec![name];
113
114 if let Some(d) = description {
115 args.push("--description".to_string());
116 args.push(d);
117 }
118
119 card_manager.execute_command("core", "create-backpack", &args)
121 .map_err(|e| PocketError::Card(format!("Failed to create backpack: {}", e)))?;
122 },
123
124 Commands::Search { query, limit, backpack, exact, package } => {
125 if package {
126 logging::warning("Package search is not yet migrated to the card system");
128 logging::warning("This will be implemented in a future version");
129 return Ok(());
130 }
131
132 let mut args = vec![query];
134
135 args.push("--limit".to_string());
136 args.push(limit.to_string());
137
138 if let Some(b) = backpack {
139 args.push("--backpack".to_string());
140 args.push(b);
141 }
142
143 if exact {
144 args.push("--exact".to_string());
145 }
146
147 card_manager.execute_command("core", "search", &args)
149 .map_err(|e| PocketError::Card(format!("Failed to search entries: {}", e)))?;
150 },
151
152 Commands::Insert { id, file, top, no_confirm, delimiter } => {
153 if let Some(id) = id {
154 if let Some(file_path) = file {
155 let mut args = vec![id, file_path];
157
158 if no_confirm {
159 args.push("--no-confirm".to_string());
160 }
161
162 if let Some(d) = delimiter {
163 args.push("--delimiter".to_string());
164 args.push(d);
165 }
166
167 card_manager.execute_command("core", "insert", &args)
169 .map_err(|e| PocketError::Card(format!("Failed to insert entry: {}", e)))?;
170 } else {
171 return Err(PocketError::Cli("Missing file path for insert".to_string()));
172 }
173 } else if top {
174 logging::warning("Top entry insertion is not yet fully migrated to the card system");
176 logging::warning("This will be improved in a future version");
177
178 let file_path = file.ok_or_else(|| PocketError::Cli("Missing file path".to_string()))?;
180
181 let mut list_args = vec!["--limit".to_string(), "1".to_string()];
183
184 logging::error("Top entry insertion not yet implemented in the card system");
189 return Err(PocketError::Cli("Operation not yet supported in the card system".to_string()));
190 } else {
191 return Err(PocketError::Cli("Missing entry ID or --top flag for insert".to_string()));
192 }
193 },
194
195 Commands::Reload => {
196 logging::info("Reloading all extensions and cards...");
197
198 card_manager = CardManager::new(card_dir.clone());
200 card_manager.load_cards()
201 .map_err(|e| PocketError::Card(format!("Failed to reload cards: {}", e)))?;
202
203 logging::success("Extensions and cards reloaded successfully");
204 },
205
206 Commands::ShowHelp { command, extensions } => {
207 if extensions {
208 let commands = card_manager.list_commands();
210
211 println!("{}", logging::header("Available extensions:"));
212 for (card_name, card_commands) in commands {
213 println!("\n{}", logging::title(&card_name));
214 for cmd in card_commands {
215 println!(" {} - {}", logging::key(&cmd.name), cmd.description);
216 println!(" Usage: {}", cmd.usage);
217 }
218 }
219 } else if let Some(cmd) = command {
220 logging::warning("Command-specific help not yet implemented in the card system");
223 logging::warning("This will be improved in a future version");
224 } else {
225 print_custom_help();
227 }
228 },
229
230 Commands::Lint { workflow } => {
231 logging::warning("Lint command not yet migrated to the card system");
233 logging::warning("This will be implemented in a future version");
234 },
235
236 Commands::DeleteWorkflow { name } => {
237 logging::warning("DeleteWorkflow command not yet migrated to the card system");
239 logging::warning("This will be implemented in a future version");
240 },
241
242 Commands::Version => {
243 println!("Pocket CLI v{}", env!("CARGO_PKG_VERSION"));
245 println!("A powerful tool for managing code snippets and shell integrations");
246 },
247
248 Commands::Edit { id, force, backpack } => {
249 let mut args = vec![id];
251
252 if force {
253 args.push("--force".to_string());
254 }
255
256 if let Some(b) = backpack {
257 args.push("--backpack".to_string());
258 args.push(b);
259 }
260
261 logging::warning("Edit command not yet fully migrated to the card system");
263 logging::warning("This will be improved in a future version");
264 },
265
266 Commands::Execute { name, args } => {
267 logging::warning("Execute command not yet migrated to the card system");
269 logging::warning("This will be implemented in a future version");
270 },
271
272 Commands::Cards { operation } => {
273 match operation {
274 Some(CardOperation::List { detail }) => {
275 println!("{}", logging::header("Available cards:"));
277 for (name, version, enabled) in card_manager.list_cards() {
278 let status = if enabled {
279 "[Enabled]".green().bold()
280 } else {
281 "[Disabled]".yellow().bold()
282 };
283
284 println!("{} {} v{}", status, logging::title(&name), version);
285
286 if detail {
288 if let Ok(commands) = card_manager.get_card_commands(&name) {
289 for cmd in commands {
290 println!(" - {}: {}", cmd.name, cmd.description);
291 }
292 }
293 }
294
295 println!();
296 }
297 },
298
299 Some(CardOperation::Enable { name }) => {
300 card_manager.enable_card(&name)
302 .map_err(|e| PocketError::Card(format!("Failed to enable card {}: {}", name, e)))?;
303
304 logging::success(&format!("Card {} enabled", name));
305 },
306
307 Some(CardOperation::Disable { name }) => {
308 card_manager.disable_card(&name)
310 .map_err(|e| PocketError::Card(format!("Failed to disable card {}: {}", name, e)))?;
311
312 logging::success(&format!("Card {} disabled", name));
313 },
314
315 Some(CardOperation::Add { name, url }) => {
316 card_manager.register_card_config(&name, &url)
318 .map_err(|e| PocketError::Card(format!("Failed to add card {}: {}", name, e)))?;
319
320 logging::success(&format!("Card {} added from {}", name, url));
321 },
322
323 Some(CardOperation::Remove { name, force }) => {
324 if !force {
326 println!("Are you sure you want to remove card {}? [y/N]", name);
327 let mut input = String::new();
328 std::io::stdin().read_line(&mut input)
329 .map_err(|e| PocketError::Cli(format!("Failed to read input: {}", e)))?;
330
331 if !input.trim().eq_ignore_ascii_case("y") {
332 logging::info("Operation cancelled");
333 return Ok(());
334 }
335 }
336
337 card_manager.remove_card_config(&name)
338 .map_err(|e| PocketError::Card(format!("Failed to remove card {}: {}", name, e)))?;
339
340 logging::success(&format!("Card {} removed", name));
341 },
342
343 Some(CardOperation::Build { name, release }) => {
344 card_manager.build_card(&name, release)
346 .map_err(|e| PocketError::Card(format!("Failed to build card {}: {}", name, e)))?;
347
348 logging::success(&format!("Card {} built successfully", name));
349 },
350
351 Some(CardOperation::Create { name, description }) => {
352 card_manager.create_card(&name, &description)
354 .map_err(|e| PocketError::Card(format!("Failed to create card {}: {}", name, e)))?;
355
356 logging::success(&format!("Card {} created successfully", name));
357 },
358
359 None => {
360 println!("{}", logging::header("Card Management:"));
362 println!(" Use the following commands to manage cards:");
363 println!(" pocket cards list - List all cards");
364 println!(" pocket cards enable - Enable a card");
365 println!(" pocket cards disable - Disable a card");
366 println!(" pocket cards add - Add a new card");
367 println!(" pocket cards remove - Remove a card");
368 println!(" pocket cards build - Build a card");
369 println!(" pocket cards create - Create a new card template");
370 println!("");
371 println!(" For more information, run: pocket help cards");
372 }
373 }
374 },
375
376 Commands::Blend { script_file, executable, command } => {
377 match command {
378 Some(BlendCommands::Edit { hook_name }) => {
379 let args = vec![hook_name];
381
382 card_manager.execute_command("blend", "edit", &args)
384 .map_err(|e| PocketError::Card(format!("Failed to edit hook: {}", e)))?;
385 },
386
387 Some(BlendCommands::List) => {
388 card_manager.execute_command("blend", "list", &[])
390 .map_err(|e| PocketError::Card(format!("Failed to list hooks: {}", e)))?;
391 },
392
393 Some(BlendCommands::Run { hook_name, args }) => {
394 let mut run_args = vec![hook_name];
396 run_args.extend(args.iter().cloned());
397
398 card_manager.execute_command("blend", "run", &run_args)
400 .map_err(|e| PocketError::Card(format!("Failed to run hook: {}", e)))?;
401 },
402
403 None => {
404 if let Some(script_path) = script_file {
406 let mut args = vec![script_path];
407
408 if executable {
409 args.push("--executable".to_string());
410 }
411
412 card_manager.execute_command("blend", "add", &args)
414 .map_err(|e| PocketError::Card(format!("Failed to add hook: {}", e)))?;
415 } else {
416 println!("{}", logging::header("Blend Command:"));
418 println!(" Use the following syntax to blend shell scripts:");
419 println!(" pocket blend <script_file> - Add a shell extension (sourced at shell startup)");
420 println!(" pocket blend --executable <script> - Add an executable hook command (run with @name)");
421 println!("");
422 println!(" Other commands:");
423 println!(" pocket blend list - List all installed hooks");
424 println!(" pocket blend edit <hook_name> - Edit an existing hook");
425 println!(" pocket blend run <hook_name> [args] - Run a hook directly");
426 println!("");
427 println!(" For more information, run: pocket help blend");
428 }
429 }
430 }
431 },
432 }
433
434 Ok(())
435}
436
437fn print_custom_help() {
439 println!("{}", logging::header("Pocket CLI Help"));
440 println!("A CLI tool for saving, organizing, and retrieving code snippets");
441 println!("with integrated version control and shell integration");
442 println!("");
443
444 println!("{}", logging::header("Core Commands:"));
445 println!(" {} - Add content to your pocket storage", logging::key("add"));
446 println!(" {} - Display all pocket entries", logging::key("list"));
447 println!(" {} - Remove an entry from storage", logging::key("remove"));
448 println!(" {} - Create a new backpack for organizing entries", logging::key("create"));
449 println!(" {} - Find entries across all backpacks", logging::key("search"));
450 println!(" {} - Insert an entry into a file", logging::key("insert"));
451 println!(" {} - Reload all extensions", logging::key("reload"));
452 println!(" {} - Display help information", logging::key("help"));
453 println!(" {} - Lint code before adding", logging::key("lint"));
454 println!(" {} - Display version information", logging::key("version"));
455 println!(" {} - Edit an existing entry", logging::key("edit"));
456 println!(" {} - Execute a script", logging::key("execute"));
457 println!("");
458
459 println!("{}", logging::header("Extension Commands:"));
460 println!(" {} - Manage extensions/cards", logging::key("cards"));
461 println!(" {} - Blend shell scripts into your environment", logging::key("blend"));
462 println!("");
463
464 println!("For more detailed help on a specific command, run:");
465 println!(" pocket help <command>");
466 println!("");
467
468 println!("To see all extensions and their commands, run:");
469 println!(" pocket help --extensions");
470 println!("");
471}