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}