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