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 {
61                check,
62                version: _,
63                token,
64                prerelease,
65                force,
66            }) => self_update::handle(token.as_deref(), prerelease, force, check).await,
67
68            Some(Commands::Uninstall {
69                tool,
70                version,
71                force,
72            }) => remove::handle(registry, &tool, version.as_deref(), force).await,
73
74            Some(Commands::Which { tool, all }) => where_cmd::handle(registry, &tool, all).await,
75
76            Some(Commands::Versions {
77                tool,
78                latest,
79                prerelease,
80                detailed,
81                interactive,
82            }) => fetch::handle(registry, &tool, latest, detailed, interactive, prerelease).await,
83
84            Some(Commands::Switch {
85                tool_version,
86                global,
87            }) => switch::handle(registry, &tool_version, global).await,
88
89            Some(Commands::Config { command }) => match command {
90                Some(crate::cli::ConfigCommand::Show) | None => config::handle().await,
91                Some(crate::cli::ConfigCommand::Set { key, value }) => {
92                    config::handle_set(&key, &value).await
93                }
94                Some(crate::cli::ConfigCommand::Get { key }) => config::handle_get(&key).await,
95                Some(crate::cli::ConfigCommand::Reset { key }) => {
96                    config::handle_reset(key.clone()).await
97                }
98                Some(crate::cli::ConfigCommand::Edit) => config::handle_edit().await,
99            },
100
101            Some(Commands::Search {
102                query,
103                category,
104                installed_only,
105                available_only,
106                format,
107                verbose,
108            }) => {
109                // TODO: Get registry from context
110                // For now, create a minimal registry
111                let registry = PluginRegistry::new();
112                search::handle(
113                    &registry,
114                    query.clone(),
115                    category.clone(),
116                    installed_only,
117                    available_only,
118                    format.clone(),
119                    verbose,
120                )
121                .await
122            }
123
124            Some(Commands::Sync {
125                check,
126                force,
127                dry_run,
128                verbose,
129                no_parallel,
130                no_auto_install,
131            }) => {
132                // TODO: Get registry from context
133                let registry = PluginRegistry::new();
134                sync::handle(
135                    &registry,
136                    check,
137                    force,
138                    dry_run,
139                    verbose,
140                    no_parallel,
141                    no_auto_install,
142                )
143                .await
144            }
145
146            Some(Commands::Init {
147                interactive,
148                template,
149                tools,
150                force,
151                dry_run,
152                list_templates,
153            }) => {
154                init::handle(
155                    interactive,
156                    template.clone(),
157                    tools.clone(),
158                    force,
159                    dry_run,
160                    list_templates,
161                )
162                .await
163            }
164
165            Some(Commands::Clean {
166                dry_run,
167                cache,
168                orphaned,
169                all,
170                force,
171                older_than,
172                verbose,
173            }) => {
174                // Map new clean options to cleanup options
175                let cache_only = cache && !all;
176                let orphaned_only = orphaned && !all;
177                cleanup::handle(
178                    dry_run,
179                    cache_only,
180                    orphaned_only,
181                    force,
182                    older_than,
183                    verbose,
184                )
185                .await
186            }
187
188            Some(Commands::Stats) => stats::handle(registry).await,
189
190            Some(Commands::Plugin { command }) => plugin::handle(registry, command).await,
191
192            Some(Commands::Venv { command }) => venv_cmd::handle(command).await,
193
194            Some(Commands::Global { command }) => global::handle(command).await,
195
196            None => {
197                // Handle tool execution
198                if cli.args.is_empty() {
199                    UI::error("No tool specified");
200                    UI::hint("Usage: vx <tool> [args...]");
201                    UI::hint("Example: vx uv pip install requests");
202                    UI::hint("Run 'vx list --all' to see supported tools");
203                    std::process::exit(1);
204                }
205
206                let tool_name = &cli.args[0];
207                let tool_args = &cli.args[1..];
208
209                // Use the executor to run the tool
210                let exit_code =
211                    execute::execute_tool(registry, tool_name, tool_args, cli.use_system_path)
212                        .await?;
213                if exit_code != 0 {
214                    std::process::exit(exit_code);
215                }
216                Ok(())
217            }
218
219            Some(Commands::Shell { command }) => {
220                use crate::cli::ShellCommand;
221                match command {
222                    ShellCommand::Init { shell } => shell::handle_shell_init(shell.clone()).await,
223                    ShellCommand::Completions { shell } => {
224                        shell::handle_completion(shell.clone()).await
225                    }
226                }
227            }
228        }
229    }
230}