Skip to content

Commit 85a3dda

Browse files
authored
feat: enable simpler builtins implemented outside brush (#130)
1 parent 18e7a30 commit 85a3dda

File tree

2 files changed

+60
-2
lines changed

2 files changed

+60
-2
lines changed

brush-core/src/builtins.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ mod unimp;
5656
mod unset;
5757
mod wait;
5858

59-
pub use factory::builtin;
6059
pub(crate) use factory::get_default_builtins;
60+
pub use factory::{builtin, simple_builtin, SimpleCommand};
6161

6262
/// Macro to define a struct that represents a shell built-in flag argument that can be
6363
/// enabled or disabled by specifying an option with a leading '+' or '-' character.
@@ -160,6 +160,14 @@ pub type CommandExecuteFunc = fn(
160160
Vec<commands::CommandArg>,
161161
) -> BoxFuture<'_, Result<BuiltinResult, error::Error>>;
162162

163+
/// Type of a function to retrieve help content for a built-in command.
164+
///
165+
/// # Arguments
166+
///
167+
/// * `name` - The name of the command.
168+
/// * `content_type` - The type of content to retrieve.
169+
pub type CommandContentFunc = fn(&str, ContentType) -> Result<String, error::Error>;
170+
163171
/// Trait implemented by built-in shell commands.
164172
#[async_trait::async_trait]
165173
pub trait Command: Parser {
@@ -256,7 +264,7 @@ pub struct Registration {
256264
pub execute_func: CommandExecuteFunc,
257265

258266
/// Function to retrieve the builtin's content/help text.
259-
pub content_func: fn(&str, ContentType) -> Result<String, error::Error>,
267+
pub content_func: CommandContentFunc,
260268

261269
/// Has this registration been disabled?
262270
pub disabled: bool,

brush-core/src/builtins/factory.rs

+50
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,31 @@ use crate::builtins;
99
use crate::commands::{self, CommandArg};
1010
use crate::error;
1111

12+
/// A simple command that can be registered as a built-in.
13+
pub trait SimpleCommand {
14+
/// Returns the content of the built-in command.
15+
fn get_content(name: &str, content_type: builtins::ContentType)
16+
-> Result<String, error::Error>;
17+
18+
/// Executes the built-in command.
19+
fn execute(
20+
context: commands::ExecutionContext<'_>,
21+
args: &[&str],
22+
) -> Result<builtins::BuiltinResult, error::Error>;
23+
}
24+
25+
/// Returns a built-in command registration, given an implementation of the
26+
/// `SimpleCommand` trait.
27+
pub fn simple_builtin<B: SimpleCommand + Send + Sync>() -> builtins::Registration {
28+
builtins::Registration {
29+
execute_func: exec_simple_builtin::<B>,
30+
content_func: B::get_content,
31+
disabled: false,
32+
special_builtin: false,
33+
declaration_builtin: false,
34+
}
35+
}
36+
1237
/// Returns a built-in command registration, given an implementation of the
1338
/// `Command` trait.
1439
pub fn builtin<B: builtins::Command + Send + Sync>() -> builtins::Registration {
@@ -58,6 +83,31 @@ fn get_builtin_content<T: builtins::Command + Send + Sync>(
5883
T::get_content(name, content_type)
5984
}
6085

86+
fn exec_simple_builtin<T: SimpleCommand + Send + Sync>(
87+
context: commands::ExecutionContext<'_>,
88+
args: Vec<CommandArg>,
89+
) -> BoxFuture<'_, Result<builtins::BuiltinResult, error::Error>> {
90+
Box::pin(async move { exec_simple_builtin_impl::<T>(context, args).await })
91+
}
92+
93+
#[allow(clippy::unused_async)]
94+
async fn exec_simple_builtin_impl<T: SimpleCommand + Send + Sync>(
95+
context: commands::ExecutionContext<'_>,
96+
args: Vec<CommandArg>,
97+
) -> Result<builtins::BuiltinResult, error::Error> {
98+
let plain_args: Vec<_> = args
99+
.into_iter()
100+
.map(|arg| match arg {
101+
CommandArg::String(s) => s,
102+
CommandArg::Assignment(a) => a.to_string(),
103+
})
104+
.collect();
105+
106+
let plain_args: Vec<_> = plain_args.iter().map(AsRef::as_ref).collect();
107+
108+
T::execute(context, plain_args.as_slice())
109+
}
110+
61111
fn exec_builtin<T: builtins::Command + Send + Sync>(
62112
context: commands::ExecutionContext<'_>,
63113
args: Vec<CommandArg>,

0 commit comments

Comments
 (0)