intelli_shell/process/
new.rs1use std::time::Duration;
2
3use indicatif::{ProgressBar, ProgressStyle};
4use tracing::instrument;
5
6use super::{InteractiveProcess, Process, ProcessOutput};
7use crate::{
8 cli::BookmarkCommandProcess,
9 component::{
10 Component,
11 edit::{EditCommandComponent, EditCommandComponentMode},
12 },
13 config::Config,
14 errors::{AppError, UserFacingError},
15 format_error, format_msg,
16 model::{CATEGORY_USER, Command, SOURCE_USER},
17 service::IntelliShellService,
18 widgets::SPINNER_CHARS,
19};
20
21impl Process for BookmarkCommandProcess {
22 #[instrument(skip_all)]
23 async fn execute(self, config: Config, service: IntelliShellService) -> color_eyre::Result<ProcessOutput> {
24 let BookmarkCommandProcess {
25 mut command,
26 alias,
27 mut description,
28 ai,
29 } = self;
30
31 if ai {
33 let cmd = command.clone().unwrap_or_default();
34 let desc = description.clone().unwrap_or_default();
35
36 if cmd.trim().is_empty() && desc.trim().is_empty() {
37 return Ok(ProcessOutput::fail().stderr(format_error!(
38 config.theme,
39 "{}",
40 UserFacingError::AiEmptyCommand
41 )));
42 }
43
44 let pb = ProgressBar::new_spinner();
46 pb.set_style(
47 ProgressStyle::with_template("{spinner:.blue} {wide_msg}")
48 .unwrap()
49 .tick_strings(&SPINNER_CHARS),
50 );
51 pb.enable_steady_tick(Duration::from_millis(100));
52 pb.set_message("Thinking ...");
53
54 let res = service.suggest_command(cmd, desc).await;
56
57 pb.finish_and_clear();
59
60 match res {
62 Ok(Some(suggestion)) => {
63 command = Some(suggestion.cmd);
64 description = suggestion.description;
65 }
66 Ok(None) => {
67 return Ok(
68 ProcessOutput::fail().stderr(format_error!(config.theme, "AI didn't generate any command"))
69 );
70 }
71 Err(AppError::UserFacing(err)) => {
72 return Ok(ProcessOutput::fail().stderr(format_error!(config.theme, "{err}")));
73 }
74 Err(AppError::Unexpected(report)) => return Err(report),
75 }
76 }
77
78 let command = Command::new(CATEGORY_USER, SOURCE_USER, command.unwrap_or_default())
79 .with_alias(alias)
80 .with_description(description);
81
82 match service.insert_command(command).await {
83 Ok(command) => Ok(ProcessOutput::success()
84 .stderr(format_msg!(
85 config.theme,
86 "Command stored: {}",
87 config.theme.secondary.apply(&command.cmd)
88 ))
89 .fileout(command.cmd)),
90 Err(AppError::UserFacing(err)) => Ok(ProcessOutput::fail().stderr(format_error!(config.theme, "{err}"))),
91 Err(AppError::Unexpected(report)) => Err(report),
92 }
93 }
94}
95
96impl InteractiveProcess for BookmarkCommandProcess {
97 #[instrument(skip_all)]
98 fn into_component(
99 self,
100 config: Config,
101 service: IntelliShellService,
102 inline: bool,
103 ) -> color_eyre::Result<Box<dyn Component>> {
104 let BookmarkCommandProcess {
105 command,
106 alias,
107 description,
108 ai,
109 } = self;
110
111 let command = Command::new(CATEGORY_USER, SOURCE_USER, command.unwrap_or_default())
112 .with_alias(alias)
113 .with_description(description);
114
115 Ok(Box::new(EditCommandComponent::new(
116 service,
117 config.theme,
118 inline,
119 command,
120 EditCommandComponentMode::New { ai },
121 )))
122 }
123}