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