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}