intelli_shell/process/
fix.rs

1use 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        // Setup the progress bar
25        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        // Setup callback for progress updates
33        let on_progress = |progress: AiFixProgress| match progress {
34            // When the command has been executed
35            AiFixProgress::Thinking => {
36                // Print a separator line to indicate the end of the command output
37                eprintln!("\n────────────────────────────────────────────────────────────────────────────────\n");
38                // Display the spinner
39                pb.enable_steady_tick(Duration::from_millis(100));
40                pb.set_message("Thinking ...");
41            }
42        };
43
44        // Call the service to fix the command
45        let res = service
46            .fix_command(&self.command, self.history.as_deref(), on_progress, cancellation_token)
47            .await;
48
49        // Clear the spinner
50        pb.finish_and_clear();
51
52        // Handle the result
53        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}