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