intelli_shell/process/
mod.rs

1use clap::{Args, FromArgMatches};
2
3use crate::{component::Component, config::Config, service::IntelliShellService};
4
5pub mod completion_delete;
6pub mod completion_list;
7pub mod completion_new;
8pub mod export;
9pub mod fix;
10pub mod import;
11pub mod new;
12pub mod replace;
13pub mod search;
14pub mod tldr_clear;
15pub mod tldr_fetch;
16
17#[cfg(debug_assertions)]
18pub mod query;
19
20/// Represents the final outcome of a [`Process`] execution.
21///
22/// This enum determines the action the shell should take after a command has been processed.
23/// It can either lead to the execution of a new shell command or result in exiting the process with specific output
24/// information.
25#[derive(PartialEq, Eq)]
26pub enum ProcessOutput {
27    /// Instructs the shell to execute the specified command
28    Execute { cmd: String },
29    /// Instructs the shell to terminate and output the provided information
30    Output(OutputInfo),
31}
32
33/// Holds the information to be written to output streams upon process termination.
34///
35/// This structure defines what should be sent to standard output (stdout), standard error (stderr), and/or a dedicated
36/// file, along with a status indicating if the operation itself succeeded or failed.
37#[derive(Clone, PartialEq, Eq, Default)]
38#[cfg_attr(debug_assertions, derive(Debug))]
39pub struct OutputInfo {
40    /// Indicates whether the operation that generated this output bundle was considered a failure
41    pub failed: bool,
42
43    /// Content to be written to a specified output file.
44    ///
45    /// When this is `Some`, it typically takes precedence over `stdout`. This is useful for redirecting the main
46    /// output of a command to a file, for instance, via an `--output` flag.
47    pub fileout: Option<String>,
48
49    /// Content to be written to the standard output (stdout) stream.
50    ///
51    /// This is generally used when no file output is specified.
52    pub stdout: Option<String>,
53
54    /// Content to be written to the standard error (stderr) stream.
55    ///
56    /// Used for error messages or diagnostic information.
57    pub stderr: Option<String>,
58}
59
60impl ProcessOutput {
61    /// Creates a [`ProcessOutput::Execute`] variant to run a shell command
62    pub fn execute(cmd: impl Into<String>) -> Self {
63        Self::Execute { cmd: cmd.into() }
64    }
65
66    /// Creates a successful [`ProcessOutput::Output`] with no content and succesful exit code
67    pub fn success() -> Self {
68        Self::Output(OutputInfo {
69            failed: false,
70            ..Default::default()
71        })
72    }
73
74    /// Creates a failed [`ProcessOutput::Output`] with no content and failure exit code
75    pub fn fail() -> Self {
76        Self::Output(OutputInfo {
77            failed: true,
78            ..Default::default()
79        })
80    }
81
82    /// Sets the file output content for the [`ProcessOutput::Output`] variant.
83    ///
84    /// Note: This has no effect if the instance is a `ProcessOutput::Execute` variant.
85    pub fn fileout(self, fileout: impl Into<String>) -> Self {
86        match self {
87            e @ ProcessOutput::Execute { .. } => e,
88            ProcessOutput::Output(data) => ProcessOutput::Output(OutputInfo {
89                fileout: Some(fileout.into()),
90                ..data
91            }),
92        }
93    }
94
95    /// Sets the standard output content for the [`ProcessOutput::Output`] variant.
96    ///
97    /// Note: This has no effect if the instance is a `ProcessOutput::Execute` variant.
98    pub fn stdout(self, stdout: impl Into<String>) -> Self {
99        match self {
100            e @ ProcessOutput::Execute { .. } => e,
101            ProcessOutput::Output(data) => ProcessOutput::Output(OutputInfo {
102                stdout: Some(stdout.into()),
103                ..data
104            }),
105        }
106    }
107
108    /// Sets the standard error content for the [`ProcessOutput::Output`] variant.
109    ///
110    /// Note: This has no effect if the instance is a `ProcessOutput::Execute` variant.
111    pub fn stderr(self, stderr: impl Into<String>) -> Self {
112        match self {
113            e @ ProcessOutput::Execute { .. } => e,
114            ProcessOutput::Output(data) => ProcessOutput::Output(OutputInfo {
115                stderr: Some(stderr.into()),
116                ..data
117            }),
118        }
119    }
120}
121
122/// Trait for non-interactive processes
123#[trait_variant::make(Send)]
124pub trait Process {
125    /// Executes the process non-interactively and returns the output
126    async fn execute(self, config: Config, service: IntelliShellService) -> color_eyre::Result<ProcessOutput>;
127}
128
129/// Trait for interactive processes
130pub trait InteractiveProcess: Process + FromArgMatches + Args {
131    /// Converts the process into a renderable component
132    fn into_component(
133        self,
134        config: Config,
135        service: IntelliShellService,
136        inline: bool,
137    ) -> color_eyre::Result<Box<dyn Component>>;
138}