intelli_shell/process/
import.rs

1use std::time::Duration;
2
3use color_eyre::Result;
4use futures_util::StreamExt;
5use indicatif::{ProgressBar, ProgressStyle};
6
7use super::{Process, ProcessOutput};
8use crate::{
9    cli::ImportItemsProcess,
10    component::{
11        Component,
12        pick::{ImportExportPickerComponent, ImportExportPickerComponentMode},
13    },
14    config::Config,
15    errors::AppError,
16    format_error,
17    process::InteractiveProcess,
18    service::IntelliShellService,
19    widgets::SPINNER_CHARS,
20};
21
22impl Process for ImportItemsProcess {
23    async fn execute(self, config: Config, service: IntelliShellService) -> color_eyre::Result<ProcessOutput> {
24        let dry_run = self.dry_run;
25
26        // If AI is enabled
27        let res = if self.ai {
28            // Setup the progress bar
29            let pb = ProgressBar::new_spinner();
30            pb.set_style(
31                ProgressStyle::with_template("{spinner:.blue} {wide_msg}")
32                    .unwrap()
33                    .tick_strings(&SPINNER_CHARS),
34            );
35            pb.enable_steady_tick(Duration::from_millis(100));
36            pb.set_message("Thinking ...");
37
38            // Retrieve items using AI
39            let res = service.get_items_from_location(self, config.gist).await;
40
41            // Clear the spinner
42            pb.finish_and_clear();
43
44            res
45        } else {
46            // If no AI, it's fast enough to not require a spinner
47            service.get_items_from_location(self, config.gist).await
48        };
49
50        // Check retrieval result
51        let mut items = match res {
52            Ok(s) => s,
53            Err(AppError::UserFacing(err)) => {
54                return Ok(ProcessOutput::fail().stderr(format_error!(config.theme, "{err}")));
55            }
56            Err(AppError::Unexpected(report)) => return Err(report),
57        };
58
59        // Print them out when in dry-run
60        if dry_run {
61            let mut stdout = String::new();
62            while let Some(item) = items.next().await {
63                stdout += &item.map_err(AppError::into_report)?.to_string();
64                stdout += "\n";
65            }
66            if stdout.is_empty() {
67                Ok(ProcessOutput::fail().stderr(format_error!(&config.theme, "No commands or completions were found")))
68            } else {
69                Ok(ProcessOutput::success().stdout(stdout))
70            }
71        } else {
72            // Or import them when not dry-run
73            match service.import_items(items, false).await {
74                Ok(stats) => Ok(stats.into_output(&config.theme)),
75                Err(AppError::UserFacing(err)) => {
76                    Ok(ProcessOutput::fail().stderr(format_error!(config.theme, "{err}")))
77                }
78                Err(AppError::Unexpected(report)) => Err(report),
79            }
80        }
81    }
82}
83
84impl InteractiveProcess for ImportItemsProcess {
85    fn into_component(self, config: Config, service: IntelliShellService, inline: bool) -> Result<Box<dyn Component>> {
86        Ok(Box::new(ImportExportPickerComponent::new(
87            service,
88            config,
89            inline,
90            ImportExportPickerComponentMode::Import { input: self },
91        )))
92    }
93}