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