intelli_shell/process/
mod.rs

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