Skip to main content

intelli_shell/process/
mod.rs

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