1use anyhow::Result;
4use clap::Parser;
5use vx_core::{PluginRegistry, VxError};
6
7pub mod cli;
8pub mod commands;
9pub mod tracing_setup;
10pub mod ui;
11
12pub use cli::Cli;
14pub use tracing_setup::setup_tracing;
15
16pub struct VxCli {
18 registry: PluginRegistry,
19}
20
21impl VxCli {
22 pub fn new(registry: PluginRegistry) -> Self {
24 Self { registry }
25 }
26
27 pub async fn run(self) -> Result<()> {
29 let cli = Cli::parse();
30
31 if cli.verbose {
33 }
35
36 match &cli.command {
38 Some(command) => self.handle_command(command.clone(), &cli).await,
39 None => {
40 if cli.args.is_empty() {
42 Cli::parse_from(["vx", "--help"]);
44 Ok(())
45 } else {
46 self.execute_tool(&cli.args, cli.use_system_path).await
48 }
49 }
50 }
51 }
52
53 async fn handle_command(&self, command: cli::Commands, _cli: &Cli) -> Result<()> {
55 use cli::Commands;
56
57 match command {
58 Commands::Version => commands::version::handle().await.map_err(Into::into),
59 Commands::List { tool, status } => {
60 commands::list::handle(&self.registry, tool.as_deref(), status)
61 .await
62 .map_err(Into::into)
63 }
64 Commands::Install {
65 tool,
66 version,
67 force,
68 } => commands::install::handle(&self.registry, &tool, version.as_deref(), force)
69 .await
70 .map_err(Into::into),
71 Commands::Update { tool, apply } => {
72 commands::update::handle(&self.registry, tool.as_deref(), apply)
73 .await
74 .map_err(Into::into)
75 }
76 Commands::Remove {
77 tool,
78 version,
79 force,
80 } => commands::remove::handle(&self.registry, &tool, version.as_deref(), force)
81 .await
82 .map_err(Into::into),
83 Commands::Where { tool, all } => {
84 commands::where_cmd::handle(&self.registry, &tool, all)
85 .await
86 .map_err(Into::into)
87 }
88 Commands::Fetch {
89 tool,
90 latest,
91 prerelease,
92 detailed,
93 interactive,
94 } => commands::fetch::handle(
95 &self.registry,
96 &tool,
97 latest,
98 detailed,
99 interactive,
100 prerelease,
101 )
102 .await
103 .map_err(Into::into),
104 Commands::Use { tool_version } => {
105 commands::use_cmd::handle(&self.registry, &tool_version)
106 .await
107 .map_err(Into::into)
108 }
109 Commands::Switch {
110 tool_version,
111 global,
112 } => commands::switch::handle(&self.registry, &tool_version, global)
113 .await
114 .map_err(Into::into),
115 Commands::Config => commands::config::handle().await.map_err(Into::into),
116 Commands::Init => {
117 println!("Init command not yet implemented");
119 Ok(())
120 }
121 Commands::Cleanup => {
122 println!("Cleanup command not yet implemented");
124 Ok(())
125 }
126 Commands::Stats => commands::stats::handle(&self.registry)
127 .await
128 .map_err(Into::into),
129 Commands::Plugin { command } => commands::plugin::handle(&self.registry, command)
130 .await
131 .map_err(Into::into),
132 Commands::Venv { command } => commands::venv_cmd::handle(command)
133 .await
134 .map_err(Into::into),
135 }
136 }
137
138 async fn execute_tool(&self, args: &[String], use_system_path: bool) -> Result<()> {
140 if args.is_empty() {
141 return Err(VxError::Other {
142 message: "No tool specified".to_string(),
143 }
144 .into());
145 }
146
147 let tool_name = &args[0];
148 let tool_args = &args[1..];
149
150 commands::execute::handle(&self.registry, tool_name, tool_args, use_system_path)
151 .await
152 .map_err(Into::into)
153 }
154}