intelli_shell/process/
fix.rs1use std::time::Duration;
2
3use indicatif::{ProgressBar, ProgressStyle};
4use tokio_util::sync::CancellationToken;
5
6use super::{Process, ProcessOutput};
7use crate::{
8 ai::CommandFix,
9 cli::CommandFixProcess,
10 config::Config,
11 errors::AppError,
12 format_error,
13 service::{AiFixProgress, IntelliShellService},
14 widgets::SPINNER_CHARS,
15};
16
17impl Process for CommandFixProcess {
18 async fn execute(
19 self,
20 config: Config,
21 service: IntelliShellService,
22 cancellation_token: CancellationToken,
23 ) -> color_eyre::Result<ProcessOutput> {
24 let pb = ProgressBar::new_spinner();
26 pb.set_style(
27 ProgressStyle::with_template("{spinner:.blue} {wide_msg}")
28 .unwrap()
29 .tick_strings(&SPINNER_CHARS),
30 );
31
32 let on_progress = |progress: AiFixProgress| match progress {
34 AiFixProgress::Thinking => {
36 eprintln!("\n────────────────────────────────────────────────────────────────────────────────\n");
38 pb.enable_steady_tick(Duration::from_millis(100));
40 pb.set_message("Thinking ...");
41 }
42 };
43
44 let res = service
46 .fix_command(&self.command, self.history.as_deref(), on_progress, cancellation_token)
47 .await;
48
49 pb.finish_and_clear();
51
52 match res {
54 Ok(None) => Ok(ProcessOutput::success()),
55 Ok(Some(CommandFix {
56 summary,
57 diagnosis,
58 proposal,
59 fixed_command,
60 })) => {
61 let mut msg = format!(
62 r"🧠 IntelliShell Diagnosis
63
64❌ {summary}
65{}
66
67✨ Fix
68{}
69",
70 config.theme.secondary.apply(diagnosis),
71 config.theme.secondary.apply(proposal)
72 );
73 let mut out = ProcessOutput::success();
74 if !fixed_command.trim().is_empty() {
75 msg += "\nSuggested Command 👉";
76 out = out.stdout(&fixed_command).fileout(fixed_command);
77 }
78 Ok(out.stderr(msg))
79 }
80 Err(AppError::UserFacing(err)) => Ok(ProcessOutput::fail().stderr(format_error!(config.theme, "{err}"))),
81 Err(AppError::Unexpected(report)) => Err(report),
82 }
83 }
84}