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}