1use crate::core::{InstallScope, MaiConfig};
2use crate::error::Result;
3use crate::storage::{Registry, XdgPaths};
4use clap::Args;
5
6#[derive(Debug, Args)]
7pub struct ListCommand {
8 #[arg(short, long)]
10 pub tool: Option<String>,
11
12 #[arg(short, long)]
14 pub all: bool,
15
16 #[arg(long, conflicts_with = "local")]
18 pub global: bool,
19
20 #[arg(long, conflicts_with = "global")]
22 pub local: bool,
23}
24
25impl ListCommand {
26 pub fn run(&self) -> Result<()> {
27 let scope = if self.global {
28 Some(InstallScope::Global)
29 } else if self.local {
30 Some(InstallScope::Local)
31 } else {
32 None
33 };
34
35 let paths = XdgPaths::new();
36 let registry = Registry::new(&paths);
37
38 if let Some(ref tool) = self.tool {
39 self.list_tool_packs(®istry, tool, scope)?;
40 } else if self.all {
41 self.list_all(®istry, scope)?;
42 } else {
43 self.list_active(&paths, ®istry, scope)?;
44 }
45
46 Ok(())
47 }
48
49 fn list_active(
50 &self,
51 paths: &XdgPaths,
52 registry: &Registry,
53 scope: Option<InstallScope>,
54 ) -> Result<()> {
55 let config_path = paths.config_file();
56 let config = if config_path.exists() {
57 let content = std::fs::read_to_string(&config_path)?;
58 toml::from_str::<MaiConfig>(&content).unwrap_or_default()
59 } else {
60 MaiConfig::new()
61 };
62
63 match config.active_tool() {
64 Some(tool) => {
65 println!("Active tool: {}", tool);
66 self.list_tool_packs(registry, tool, scope)?;
67 }
68 None => {
69 println!("No active tool. Use 'mai use <tool>' to set one.");
70 }
71 }
72 Ok(())
73 }
74
75 fn list_tool_packs(
76 &self,
77 registry: &Registry,
78 tool: &str,
79 scope: Option<InstallScope>,
80 ) -> Result<()> {
81 let packs = registry.list_packs(Some(tool), scope)?;
82 if packs.is_empty() {
83 let scope_msg = match scope {
84 Some(InstallScope::Global) => "global ",
85 Some(InstallScope::Local) => "local ",
86 None => "",
87 };
88 println!("No {}packs installed for tool: {}", scope_msg, tool);
89 } else {
90 println!("Packs for {}:", tool);
91 for pack in packs {
92 let metadata_info = pack
93 .metadata
94 .description
95 .as_ref()
96 .map(|d| format!(" - {}", d))
97 .unwrap_or_default();
98 println!(
99 " [{}] {} {} ({}){}",
100 pack.scope, pack.name, pack.version, pack.pack_type, metadata_info
101 );
102 }
103 }
104 Ok(())
105 }
106
107 fn list_all(&self, registry: &Registry, scope: Option<InstallScope>) -> Result<()> {
108 let packs = registry.list_packs(None, scope)?;
109 if packs.is_empty() {
110 println!("No packs installed.");
111 } else {
112 println!("Installed packs:");
113 for pack in packs {
114 let metadata_info = pack
115 .metadata
116 .description
117 .as_ref()
118 .map(|d| format!(" - {}", d))
119 .unwrap_or_default();
120 println!(
121 " [{}] {} {}{}",
122 pack.scope,
123 pack.id(),
124 pack.pack_type,
125 metadata_info
126 );
127 }
128 }
129 Ok(())
130 }
131}