vx_cli/commands/
list.rs

1//! List command implementation
2
3use crate::ui::UI;
4use vx_core::{PluginRegistry, Result, VxEnvironment, VxError};
5
6/// Handle the list command
7pub async fn handle(
8    registry: &PluginRegistry,
9    tool_name: Option<&str>,
10    show_status: bool,
11) -> Result<()> {
12    // If a specific tool is requested, show details for that tool
13    if let Some(tool) = tool_name {
14        return show_tool_details(registry, tool, show_status).await;
15    }
16
17    // Show all tools
18    UI::info("Available tools:");
19
20    let tools = registry.get_all_tools();
21
22    if tools.is_empty() {
23        UI::warn("No tools available");
24        UI::hint("Make sure plugins are properly registered");
25        return Ok(());
26    }
27
28    for tool in tools {
29        let status_icon = if show_status {
30            // Use the tool's own method to check installation status
31            let installed_versions = tool.get_installed_versions().await.unwrap_or_default();
32            if installed_versions.is_empty() {
33                "❌"
34            } else {
35                "✅"
36            }
37        } else {
38            "📦"
39        };
40
41        UI::item(&format!(
42            "{} {} - {}",
43            status_icon,
44            tool.name(),
45            tool.description()
46        ));
47
48        // Show aliases if any
49        let aliases = tool.aliases();
50        if !aliases.is_empty() {
51            UI::detail(&format!("   Aliases: {}", aliases.join(", ")));
52        }
53
54        // Show installation status if requested
55        if show_status {
56            let installed_versions = tool.get_installed_versions().await.unwrap_or_default();
57            if !installed_versions.is_empty() {
58                UI::detail(&format!(
59                    "   Installed versions: {}",
60                    installed_versions.join(", ")
61                ));
62
63                // Show active version if any
64                if let Ok(active_version) = tool.get_active_version().await {
65                    UI::detail(&format!("   Active version: {}", active_version));
66                }
67            }
68        }
69    }
70
71    // Show package managers
72    UI::info("\nAvailable package managers:");
73    let package_managers = registry.get_all_package_managers();
74
75    if package_managers.is_empty() {
76        UI::warn("No package managers available");
77    } else {
78        for pm in package_managers {
79            let available = pm.is_available().await.unwrap_or(false);
80            let status_icon = if available { "✅" } else { "❌" };
81
82            UI::item(&format!(
83                "{} {} ({:?}) - {}",
84                status_icon,
85                pm.name(),
86                pm.ecosystem(),
87                pm.description()
88            ));
89        }
90    }
91
92    Ok(())
93}
94
95/// Show detailed information for a specific tool
96async fn show_tool_details(
97    registry: &PluginRegistry,
98    tool_name: &str,
99    show_status: bool,
100) -> Result<()> {
101    let tool = registry
102        .get_tool(tool_name)
103        .ok_or_else(|| VxError::ToolNotFound {
104            tool_name: tool_name.to_string(),
105        })?;
106
107    UI::header(&format!("Tool: {}", tool.name()));
108    UI::info(&format!("Description: {}", tool.description()));
109
110    // Show aliases if any
111    let aliases = tool.aliases();
112    if !aliases.is_empty() {
113        UI::info(&format!("Aliases: {}", aliases.join(", ")));
114    }
115
116    // Show metadata
117    let metadata = tool.metadata();
118    if !metadata.is_empty() {
119        UI::info("Metadata:");
120        for (key, value) in metadata {
121            UI::detail(&format!("  {}: {}", key, value));
122        }
123    }
124
125    if show_status {
126        // Create environment manager for status checking
127        let env = VxEnvironment::new().map_err(|e| VxError::Other {
128            message: format!("Failed to create VX environment: {}", e),
129        })?;
130
131        // Show installation status
132        let installed_versions = tool.get_installed_versions().await.unwrap_or_default();
133
134        if installed_versions.is_empty() {
135            UI::warn("Not installed");
136            UI::hint(&format!("Use 'vx install {}' to install it", tool.name()));
137        } else {
138            UI::success(&format!(
139                "Installed versions ({}): {}",
140                installed_versions.len(),
141                installed_versions.join(", ")
142            ));
143
144            // Show active version if any
145            if let Ok(active_version) = tool.get_active_version().await {
146                UI::info(&format!("Active version: {}", active_version));
147
148                // Show installation path
149                if let Ok(Some(installation)) =
150                    env.get_installation_info(tool.name(), &active_version)
151                {
152                    UI::detail(&format!(
153                        "Installation path: {}",
154                        installation.install_dir.display()
155                    ));
156                    UI::detail(&format!(
157                        "Executable: {}",
158                        installation.executable_path.display()
159                    ));
160                }
161            } else {
162                UI::warn("No active version set");
163                UI::hint(&format!(
164                    "Use 'vx switch {}@<version>' to set active version",
165                    tool.name()
166                ));
167            }
168        }
169
170        // Show related tools (tools from the same plugin)
171        if let Some(plugin) = registry.find_plugin_for_tool(tool.name()) {
172            let related_tools: Vec<String> = plugin
173                .tools()
174                .into_iter()
175                .filter(|t| t.name() != tool.name())
176                .map(|t| t.name().to_string())
177                .collect();
178
179            if !related_tools.is_empty() {
180                UI::info(&format!("Related tools: {}", related_tools.join(", ")));
181            }
182        }
183    }
184
185    Ok(())
186}