golem_rib_repl/command/
mod.rs

1pub use clap_parser::*;
2use convert_case::{Case, Casing};
3pub use registry::*;
4pub use untyped::*;
5
6mod builtin;
7mod clap_parser;
8mod registry;
9mod untyped;
10
11use crate::rib_context::ReplContext;
12
13/// A Command implementation will do the following:
14///  - Parse user input from a string that follows the command which is of the pattern `:command-name input` and gets a structured Input
15///  - The Input will soon require a Display for documentation purpose
16///  - The Input will be executed to get a structured Output or an ExecutionError
17///  - Print results or errors to the user
18///
19///
20///  To register new commands to the REPL from any client (Ex: golem-cli),
21///  create a struct that implements the `Command` trait and register it using `let mut registry = CommandRegistry::default()`,
22///  and `registry.register(MyCommand);`, and pass it the config when bootstrapping the REPL.
23pub trait Command {
24    /// The structured input type resulting from parsing the raw REPL string.
25    /// If using Clap, this should be a type that derives `clap::Parser`, and the error
26    /// is typically `clap::Error`.
27    type Input;
28
29    /// The output produced after successful execution of the command.
30    type Output;
31
32    /// Error type returned when parsing the user input fails.
33    type InputParseError;
34
35    /// Error type returned when command execution fails.
36    type ExecutionError;
37
38    fn name(&self) -> String {
39        let full = std::any::type_name::<Self>();
40        let last = full.rsplit("::").next().unwrap_or(full);
41        last.to_case(Case::Kebab)
42    }
43
44    /// Parses user input into a structured `Input` type.
45    ///
46    /// Parse implementation can internally make use of Clap or any other parsing library
47    /// If using Clap, using helpers like `parse_with_clap` is recommended to handle shell-style splitting
48    /// and all you need is derived `clap:Parser` trait on the `Input` type.
49    ///
50    /// # Parameters
51    /// - `prompt_input`: The raw string entered by the user after the command name in the REPL.
52    ///   For example, if the user types `:my-command foo bar`, then `prompt_input` will be
53    ///   `"foo bar"`.
54    /// - `repl_context`: An immutable projection of internal ReplState.
55    ///   This gives access to printer, current session of rib script etc
56    //
57    fn parse(
58        &self,
59        input: &str,
60        repl_context: &ReplContext,
61    ) -> Result<Self::Input, Self::InputParseError>;
62
63    /// Executes the command with the parsed input and REPL context.
64    ///
65    /// # Parameters
66    /// - `input`: The structured input previously returned by `parse`.
67    /// - `repl_context`: An immutable projection of internal ReplState
68    fn execute(
69        &self,
70        input: Self::Input,
71        repl_context: &mut ReplContext,
72    ) -> Result<Self::Output, Self::ExecutionError>;
73
74    /// Prints the output produced by the command after successful execution.
75    ///
76    /// # Parameters
77    /// - `output`: The result returned by `execute` if it completed successfully.
78    /// - `repl_context`: An immutable projection of internal ReplState
79    fn print_output(&self, output: Self::Output, repl_context: &ReplContext);
80
81    /// Prints an error that occurred during input parsing.
82    ///
83    /// # Parameters
84    /// - `error`: The error returned by `parse` when the user input is invalid.
85    /// - `repl_context`: An immutable projection of internal ReplState
86    fn print_input_parse_error(&self, error: Self::InputParseError, repl_context: &ReplContext);
87
88    /// Prints an error that occurred during command execution.
89    ///
90    /// # Parameters
91    /// - `error`: The error returned by `execute` when something goes wrong during execution.
92    /// - `repl_context`: An immutable projection of internal ReplState
93    fn print_execution_error(&self, error: Self::ExecutionError, repl_context: &ReplContext);
94}