vx_cli/commands/
mod.rs

1//! CLI command implementations
2
3use crate::cli::{Cli, Commands};
4use crate::ui::UI;
5use vx_plugin::PluginRegistry;
6
7pub mod cleanup;
8pub mod config;
9pub mod execute;
10#[cfg(test)]
11mod execute_tests;
12pub mod fetch;
13pub mod global;
14pub mod init;
15pub mod install;
16pub mod list;
17pub mod plugin;
18pub mod remove;
19pub mod search;
20pub mod self_update;
21pub mod shell;
22pub mod stats;
23pub mod switch;
24pub mod sync;
25
26pub mod update;
27pub mod venv_cmd;
28pub mod version;
29pub mod where_cmd;
30
31// Tests moved to tests/ directory
32
33pub struct CommandHandler;
34
35impl CommandHandler {
36    pub async fn handle(cli: Cli, registry: &PluginRegistry) -> anyhow::Result<()> {
37        // Set verbose mode
38        UI::set_verbose(cli.verbose);
39
40        match cli.command {
41            Some(Commands::Version) => version::handle().await,
42
43            Some(Commands::List {
44                tool,
45                status,
46                installed: _,
47                available: _,
48            }) => list::handle(registry, tool.as_deref(), status).await,
49
50            Some(Commands::Install {
51                tool,
52                version,
53                force,
54            }) => install::handle(registry, &tool, version.as_deref(), force).await,
55
56            Some(Commands::Update { tool, apply: _ }) => {
57                update::handle(registry, tool.as_deref(), false).await
58            }
59
60            Some(Commands::SelfUpdate { check, version }) => {
61                self_update::handle(check, version.as_deref()).await
62            }
63
64            Some(Commands::Uninstall {
65                tool,
66                version,
67                force,
68            }) => remove::handle(registry, &tool, version.as_deref(), force).await,
69
70            Some(Commands::Which { tool, all }) => where_cmd::handle(registry, &tool, all).await,
71
72            Some(Commands::Versions {
73                tool,
74                latest,
75                prerelease,
76                detailed,
77                interactive,
78            }) => fetch::handle(registry, &tool, latest, detailed, interactive, prerelease).await,
79
80            Some(Commands::Switch {
81                tool_version,
82                global,
83            }) => switch::handle(registry, &tool_version, global).await,
84
85            Some(Commands::Config { command }) => match command {
86                Some(crate::cli::ConfigCommand::Show) | None => config::handle().await,
87                Some(crate::cli::ConfigCommand::Set { key, value }) => {
88                    config::handle_set(&key, &value).await
89                }
90                Some(crate::cli::ConfigCommand::Get { key }) => config::handle_get(&key).await,
91                Some(crate::cli::ConfigCommand::Reset { key }) => {
92                    config::handle_reset(key.clone()).await
93                }
94                Some(crate::cli::ConfigCommand::Edit) => config::handle_edit().await,
95            },
96
97            Some(Commands::Search {
98                query,
99                category,
100                installed_only,
101                available_only,
102                format,
103                verbose,
104            }) => {
105                // TODO: Get registry from context
106                // For now, create a minimal registry
107                let registry = PluginRegistry::new();
108                search::handle(
109                    &registry,
110                    query.clone(),
111                    category.clone(),
112                    installed_only,
113                    available_only,
114                    format.clone(),
115                    verbose,
116                )
117                .await
118            }
119
120            Some(Commands::Sync {
121                check,
122                force,
123                dry_run,
124                verbose,
125                no_parallel,
126                no_auto_install,
127            }) => {
128                // TODO: Get registry from context
129                let registry = PluginRegistry::new();
130                sync::handle(
131                    &registry,
132                    check,
133                    force,
134                    dry_run,
135                    verbose,
136                    no_parallel,
137                    no_auto_install,
138                )
139                .await
140            }
141
142            Some(Commands::Init {
143                interactive,
144                template,
145                tools,
146                force,
147                dry_run,
148                list_templates,
149            }) => {
150                init::handle(
151                    interactive,
152                    template.clone(),
153                    tools.clone(),
154                    force,
155                    dry_run,
156                    list_templates,
157                )
158                .await
159            }
160
161            Some(Commands::Clean {
162                dry_run,
163                cache,
164                orphaned,
165                all,
166                force,
167                older_than,
168                verbose,
169            }) => {
170                // Map new clean options to cleanup options
171                let cache_only = cache && !all;
172                let orphaned_only = orphaned && !all;
173                cleanup::handle(
174                    dry_run,
175                    cache_only,
176                    orphaned_only,
177                    force,
178                    older_than,
179                    verbose,
180                )
181                .await
182            }
183
184            Some(Commands::Stats) => stats::handle(registry).await,
185
186            Some(Commands::Plugin { command }) => plugin::handle(registry, command).await,
187
188            Some(Commands::Venv { command }) => venv_cmd::handle(command).await,
189
190            Some(Commands::Global { command }) => global::handle(command).await,
191
192            None => {
193                // Handle tool execution
194                if cli.args.is_empty() {
195                    UI::error("No tool specified");
196                    UI::hint("Usage: vx <tool> [args...]");
197                    UI::hint("Example: vx uv pip install requests");
198                    UI::hint("Run 'vx list --all' to see supported tools");
199                    std::process::exit(1);
200                }
201
202                let tool_name = &cli.args[0];
203                let tool_args = &cli.args[1..];
204
205                // Use the executor to run the tool
206                let exit_code =
207                    execute::execute_tool(registry, tool_name, tool_args, cli.use_system_path)
208                        .await?;
209                if exit_code != 0 {
210                    std::process::exit(exit_code);
211                }
212                Ok(())
213            }
214
215            Some(Commands::Shell { command }) => {
216                use crate::cli::ShellCommand;
217                match command {
218                    ShellCommand::Init { shell } => shell::handle_shell_init(shell.clone()).await,
219                    ShellCommand::Completions { shell } => {
220                        shell::handle_completion(shell.clone()).await
221                    }
222                }
223            }
224        }
225    }
226}