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 return Err(PocketError::Cli("Operation not yet supported in the card system".to_string()));
177 } else {
178 return Err(PocketError::Cli("Missing entry ID for insert".to_string()));
179 }
180 },
181
182 Commands::Reload => {
183 logging::info("Reloading all extensions and cards...");
184
185 card_manager = CardManager::new(card_dir.clone());
187 card_manager.load_cards()
188 .map_err(|e| PocketError::Card(format!("Failed to reload cards: {}", e)))?;
189
190 logging::success("Extensions and cards reloaded successfully");
191 },
192
193 Commands::ShowHelp { command, extensions } => {
194 if extensions {
195 let commands = card_manager.list_commands();
197
198 println!("{}", logging::header("Available extensions:"));
199 for (card_name, card_commands) in commands {
200 println!("\n{}", logging::title(&card_name));
201 for cmd in card_commands {
202 println!(" {} - {}", logging::key(&cmd.name), cmd.description);
203 println!(" Usage: {}", cmd.usage);
204 }
205 }
206 } else if let Some(cmd) = command {
207 logging::warning("Command-specific help not yet implemented in the card system");
210 logging::warning("This will be improved in a future version");
211 } else {
212 print_custom_help();
214 }
215 },
216
217 Commands::Lint { workflow } => {
218 logging::warning("Lint command not yet migrated to the card system");
220 logging::warning("This will be implemented in a future version");
221 },
222
223 Commands::DeleteWorkflow { name } => {
224 logging::warning("DeleteWorkflow command not yet migrated to the card system");
226 logging::warning("This will be implemented in a future version");
227 },
228
229 Commands::Version => {
230 println!("Pocket CLI v{}", env!("CARGO_PKG_VERSION"));
232 println!("A powerful tool for managing code snippets and shell integrations");
233 },
234
235 Commands::Edit { id, force, backpack } => {
236 let mut args = vec![id];
238
239 if force {
240 args.push("--force".to_string());
241 }
242
243 if let Some(b) = backpack {
244 args.push("--backpack".to_string());
245 args.push(b);
246 }
247
248 logging::warning("Edit command not yet fully migrated to the card system");
250 logging::warning("This will be improved in a future version");
251 },
252
253 Commands::Execute { name, args } => {
254 logging::warning("Execute command not yet migrated to the card system");
256 logging::warning("This will be implemented in a future version");
257 },
258
259 Commands::Cards { operation } => {
260 match operation {
261 Some(CardOperation::List { detail }) => {
262 println!("{}", logging::header("Available cards:"));
264 for (name, version, enabled) in card_manager.list_cards() {
265 let status = if enabled {
266 "[Enabled]".green().bold()
267 } else {
268 "[Disabled]".yellow().bold()
269 };
270
271 println!("{} {} v{}", status, logging::title(&name), version);
272
273 if detail {
275 if let Ok(commands) = card_manager.get_card_commands(&name) {
276 for cmd in commands {
277 println!(" - {}: {}", cmd.name, cmd.description);
278 }
279 }
280 }
281
282 println!();
283 }
284 },
285
286 Some(CardOperation::Enable { name }) => {
287 card_manager.enable_card(&name)
289 .map_err(|e| PocketError::Card(format!("Failed to enable card {}: {}", name, e)))?;
290
291 logging::success(&format!("Card {} enabled", name));
292 },
293
294 Some(CardOperation::Disable { name }) => {
295 card_manager.disable_card(&name)
297 .map_err(|e| PocketError::Card(format!("Failed to disable card {}: {}", name, e)))?;
298
299 logging::success(&format!("Card {} disabled", name));
300 },
301
302 Some(CardOperation::Add { name, url }) => {
303 card_manager.register_card_config(&name, &url)
305 .map_err(|e| PocketError::Card(format!("Failed to add card {}: {}", name, e)))?;
306
307 logging::success(&format!("Card {} added from {}", name, url));
308 },
309
310 Some(CardOperation::Remove { name, force }) => {
311 if !force {
313 println!("Are you sure you want to remove card {}? [y/N]", name);
314 let mut input = String::new();
315 std::io::stdin().read_line(&mut input)
316 .map_err(|e| PocketError::Cli(format!("Failed to read input: {}", e)))?;
317
318 if !input.trim().eq_ignore_ascii_case("y") {
319 logging::info("Operation cancelled");
320 return Ok(());
321 }
322 }
323
324 card_manager.remove_card_config(&name)
325 .map_err(|e| PocketError::Card(format!("Failed to remove card {}: {}", name, e)))?;
326
327 logging::success(&format!("Card {} removed", name));
328 },
329
330 Some(CardOperation::Build { name, release }) => {
331 card_manager.build_card(&name, release)
333 .map_err(|e| PocketError::Card(format!("Failed to build card {}: {}", name, e)))?;
334
335 logging::success(&format!("Card {} built successfully", name));
336 },
337
338 Some(CardOperation::Create { name, description }) => {
339 card_manager.create_card(&name, &description)
341 .map_err(|e| PocketError::Card(format!("Failed to create card {}: {}", name, e)))?;
342
343 logging::success(&format!("Card {} created successfully", name));
344 },
345
346 None => {
347 println!("{}", logging::header("Card Management:"));
349 println!(" Use the following commands to manage cards:");
350 println!(" pocket cards list - List all cards");
351 println!(" pocket cards enable - Enable a card");
352 println!(" pocket cards disable - Disable a card");
353 println!(" pocket cards add - Add a new card");
354 println!(" pocket cards remove - Remove a card");
355 println!(" pocket cards build - Build a card");
356 println!(" pocket cards create - Create a new card template");
357 println!("");
358 println!(" For more information, run: pocket help cards");
359 }
360 }
361 },
362
363 Commands::Blend { script_file, executable, command } => {
364 match command {
365 Some(BlendCommands::Edit { hook_name }) => {
366 let args = vec![hook_name];
368
369 card_manager.execute_command("blend", "edit", &args)
371 .map_err(|e| PocketError::Card(format!("Failed to edit hook: {}", e)))?;
372 },
373
374 Some(BlendCommands::List) => {
375 card_manager.execute_command("blend", "list", &[])
377 .map_err(|e| PocketError::Card(format!("Failed to list hooks: {}", e)))?;
378 },
379
380 Some(BlendCommands::Run { hook_name, args }) => {
381 let mut run_args = vec![hook_name];
383 run_args.extend(args.iter().cloned());
384
385 card_manager.execute_command("blend", "run", &run_args)
387 .map_err(|e| PocketError::Card(format!("Failed to run hook: {}", e)))?;
388 },
389
390 None => {
391 if let Some(script_path) = script_file {
393 let mut args = vec![script_path];
394
395 if executable {
396 args.push("--executable".to_string());
397 }
398
399 card_manager.execute_command("blend", "add", &args)
401 .map_err(|e| PocketError::Card(format!("Failed to add hook: {}", e)))?;
402 } else {
403 println!("{}", logging::header("Blend Command:"));
405 println!(" Use the following syntax to blend shell scripts:");
406 println!(" pocket blend <script_file> - Add a shell extension (sourced at shell startup)");
407 println!(" pocket blend --executable <script> - Add an executable hook command (run with @name)");
408 println!("");
409 println!(" Other commands:");
410 println!(" pocket blend list - List all installed hooks");
411 println!(" pocket blend edit <hook_name> - Edit an existing hook");
412 println!(" pocket blend run <hook_name> [args] - Run a hook directly");
413 println!("");
414 println!(" For more information, run: pocket help blend");
415 }
416 }
417 }
418 },
419 }
420
421 Ok(())
422}
423
424fn print_custom_help() {
426 println!("{}", logging::header("Pocket CLI Help"));
427 println!("A CLI tool for saving, organizing, and retrieving code snippets");
428 println!("with integrated version control and shell integration");
429 println!("");
430
431 println!("{}", logging::header("Core Commands:"));
432 println!(" {} - Add content to your pocket storage", logging::key("add"));
433 println!(" {} - Display all pocket entries", logging::key("list"));
434 println!(" {} - Remove an entry from storage", logging::key("remove"));
435 println!(" {} - Create a new backpack for organizing entries", logging::key("create"));
436 println!(" {} - Find entries across all backpacks", logging::key("search"));
437 println!(" {} - Insert an entry into a file", logging::key("insert"));
438 println!(" {} - Reload all extensions", logging::key("reload"));
439 println!(" {} - Display help information", logging::key("help"));
440 println!(" {} - Lint code before adding", logging::key("lint"));
441 println!(" {} - Display version information", logging::key("version"));
442 println!(" {} - Edit an existing entry", logging::key("edit"));
443 println!(" {} - Execute a script", logging::key("execute"));
444 println!("");
445
446 println!("{}", logging::header("Extension Commands:"));
447 println!(" {} - Manage extensions/cards", logging::key("cards"));
448 println!(" {} - Blend shell scripts into your environment", logging::key("blend"));
449 println!("");
450
451 println!("For more detailed help on a specific command, run:");
452 println!(" pocket help <command>");
453 println!("");
454
455 println!("To see all extensions and their commands, run:");
456 println!(" pocket help --extensions");
457 println!("");
458}