Skip to content

Commit

Permalink
feat: enable simpler builtins implemented outside brush (#130)
Browse files Browse the repository at this point in the history
  • Loading branch information
reubeno authored Jul 18, 2024
1 parent 18e7a30 commit 85a3dda
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 2 deletions.
12 changes: 10 additions & 2 deletions brush-core/src/builtins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ mod unimp;
mod unset;
mod wait;

pub use factory::builtin;
pub(crate) use factory::get_default_builtins;
pub use factory::{builtin, simple_builtin, SimpleCommand};

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

/// Type of a function to retrieve help content for a built-in command.
///
/// # Arguments
///
/// * `name` - The name of the command.
/// * `content_type` - The type of content to retrieve.
pub type CommandContentFunc = fn(&str, ContentType) -> Result<String, error::Error>;

/// Trait implemented by built-in shell commands.
#[async_trait::async_trait]
pub trait Command: Parser {
Expand Down Expand Up @@ -256,7 +264,7 @@ pub struct Registration {
pub execute_func: CommandExecuteFunc,

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

/// Has this registration been disabled?
pub disabled: bool,
Expand Down
50 changes: 50 additions & 0 deletions brush-core/src/builtins/factory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,31 @@ use crate::builtins;
use crate::commands::{self, CommandArg};
use crate::error;

/// A simple command that can be registered as a built-in.
pub trait SimpleCommand {
/// Returns the content of the built-in command.
fn get_content(name: &str, content_type: builtins::ContentType)
-> Result<String, error::Error>;

/// Executes the built-in command.
fn execute(
context: commands::ExecutionContext<'_>,
args: &[&str],
) -> Result<builtins::BuiltinResult, error::Error>;
}

/// Returns a built-in command registration, given an implementation of the
/// `SimpleCommand` trait.
pub fn simple_builtin<B: SimpleCommand + Send + Sync>() -> builtins::Registration {
builtins::Registration {
execute_func: exec_simple_builtin::<B>,
content_func: B::get_content,
disabled: false,
special_builtin: false,
declaration_builtin: false,
}
}

/// Returns a built-in command registration, given an implementation of the
/// `Command` trait.
pub fn builtin<B: builtins::Command + Send + Sync>() -> builtins::Registration {
Expand Down Expand Up @@ -58,6 +83,31 @@ fn get_builtin_content<T: builtins::Command + Send + Sync>(
T::get_content(name, content_type)
}

fn exec_simple_builtin<T: SimpleCommand + Send + Sync>(
context: commands::ExecutionContext<'_>,
args: Vec<CommandArg>,
) -> BoxFuture<'_, Result<builtins::BuiltinResult, error::Error>> {
Box::pin(async move { exec_simple_builtin_impl::<T>(context, args).await })
}

#[allow(clippy::unused_async)]
async fn exec_simple_builtin_impl<T: SimpleCommand + Send + Sync>(
context: commands::ExecutionContext<'_>,
args: Vec<CommandArg>,
) -> Result<builtins::BuiltinResult, error::Error> {
let plain_args: Vec<_> = args
.into_iter()
.map(|arg| match arg {
CommandArg::String(s) => s,
CommandArg::Assignment(a) => a.to_string(),
})
.collect();

let plain_args: Vec<_> = plain_args.iter().map(AsRef::as_ref).collect();

T::execute(context, plain_args.as_slice())
}

fn exec_builtin<T: builtins::Command + Send + Sync>(
context: commands::ExecutionContext<'_>,
args: Vec<CommandArg>,
Expand Down

0 comments on commit 85a3dda

Please sign in to comment.