Skip to content

feat: add statically registered filters#972

Draft
reubeno wants to merge 1 commit intomainfrom
static-filter-attempt-minimized
Draft

feat: add statically registered filters#972
reubeno wants to merge 1 commit intomainfrom
static-filter-attempt-minimized

Conversation

@reubeno
Copy link
Owner

@reubeno reubeno commented Feb 1, 2026

No description provided.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a statically-registered filter infrastructure to brush, enabling interception and modification of shell operations through zero-cost abstractions. The implementation uses Rust's trait system with monomorphization to achieve zero runtime overhead when using default no-op filters.

Changes:

  • Adds comprehensive filter infrastructure with CmdExecFilter and SourceFilter traits for intercepting command execution and script sourcing operations
  • Introduces with_filter! macro to reduce boilerplate at hook sites
  • Implements ExternalCommand builder for introspectable external process configuration
  • Integrates filters into shell's command execution and script sourcing paths while maintaining backward compatibility

Reviewed changes

Copilot reviewed 8 out of 9 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
docs/reference/filter-architecture.md Comprehensive documentation of filter architecture, design philosophy, and usage examples
brush-core/src/filter.rs Core filter infrastructure including traits, parameter types, macro, and extensive unit tests (1371 lines)
brush-core/src/extensions.rs Extends ShellExtensions trait to include CmdExecFilter and SourceFilter types with backward-compatible default parameters
brush-core/src/shell.rs Adds filter storage fields and accessor methods to Shell struct
brush-core/src/shell/builder.rs Adds filter configuration to shell builder options
brush-core/src/shell/execution.rs Integrates SourceFilter hooks into script sourcing operations
brush-core/src/commands.rs Integrates CmdExecFilter hooks into command execution pipeline for both simple and external commands
brush-core/src/lib.rs Exports filter module in public API
Cargo.lock Incidental dependency updates (windows-sys 0.60.2 → 0.61.2)

Comment on lines +42 to +51

/// Returns a reference to the command execution filter.
pub const fn cmd_exec_filter(&self) -> &CF {
&self.cmd_exec_filter
}

/// Returns a reference to the source filter.
pub const fn source_filter(&self) -> &SF {
&self.source_filter
}
Copy link

Copilot AI Feb 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These accessor methods on ShellExtensionsImpl return references to the struct's fields, but these fields are never actually populated with meaningful instances - they're just default instances created by the #[derive(Default)]. The actual filter instances are stored and accessed directly on the Shell struct itself via Shell::cmd_exec_filter() and Shell::source_filter(). These accessor methods appear to be unused dead code. Consider removing them unless there's a specific use case for accessing the extension struct's fields directly.

Suggested change
/// Returns a reference to the command execution filter.
pub const fn cmd_exec_filter(&self) -> &CF {
&self.cmd_exec_filter
}
/// Returns a reference to the source filter.
pub const fn source_filter(&self) -> &SF {
&self.source_filter
}

Copilot uses AI. Check for mistakes.
Comment on lines +554 to 604
async fn execute_via_external(self, path: &Path) -> Result<ExecutionSpawnResult, error::Error> {
// Build an ExternalCommand for the filter to inspect/modify.
let mut ext_cmd = ExternalCommand::new(path);
for arg in &self.args[1..] {
if let CommandArg::String(s) = arg {
ext_cmd.arg(s);
}
}

let resolved_path = path.to_string_lossy();
let result = execute_external_command(
cmd_context,
resolved_path.as_ref(),
self.process_group_id,
&self.args[1..],
);
// Extract fields from self before creating params (which borrows shell).
let mut shell = self.shell;
let command_name = self.command_name;
let params = self.params;
let process_group_id = self.process_group_id;
let post_execute = self.post_execute;

if let Some(post_execute) = self.post_execute {
let _ = post_execute(&mut shell);
}
// Create filter params.
let filter_params = ExternalCmdParams::new(&shell, ext_cmd);

result
crate::with_filter!(
shell,
cmd_exec_filter,
pre_external_cmd,
post_external_cmd,
filter_params,
p => {
// Extract the (possibly modified) command info.
let ext_cmd = p.command;
let new_path = PathBuf::from(ext_cmd.program());
let new_args: Vec<CommandArg> = ext_cmd
.args()
.iter()
.map(|a| CommandArg::String(a.to_string_lossy().to_string()))
.collect();

let cmd_context = ExecutionContext {
shell: &mut shell,
command_name,
params,
};

let resolved_path = new_path.to_string_lossy();
execute_external_command(cmd_context, resolved_path.as_ref(), process_group_id, &new_args)
},
finally {
if let Some(post_execute) = post_execute {
let _ = post_execute(&mut shell);
}
}
)
}
Copy link

Copilot AI Feb 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ExternalCommand provides env, clear_env, and set_current_dir methods, but the current integration in execute_via_external only extracts the program() and args() from the command. The environment variables and current directory configured on ExternalCommand are not actually applied to the spawned process. Either these fields should be used when spawning the process, or the Known Limitations section should explicitly document that environment and current directory modification are not yet supported. The into_std_command() method does convert these fields, but it's never called in the current code.

Copilot uses AI. Check for mistakes.
pre_source_script,
post_source_script,
SourceScriptParams::new(&shell, path, &args),
|p| run_script(p.path(), p.args()).await
Copy link

Copilot AI Feb 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The syntax shown here uses closure syntax |p| but the actual with_filter! macro expects arrow syntax p => (without the pipes). This should be changed to match the actual macro implementation.

Suggested change
|p| run_script(p.path(), p.args()).await
p => run_script(p.path(), p.args()).await

Copilot uses AI. Check for mistakes.
@github-actions
Copy link

github-actions bot commented Feb 1, 2026

Test Results

    3 files     32 suites   13m 19s ⏱️
1 903 tests 1 903 ✅ 0 💤 0 ❌
5 681 runs  5 681 ✅ 0 💤 0 ❌

Results for commit 17bdb69.

♻️ This comment has been updated with latest results.

@github-actions
Copy link

github-actions bot commented Feb 1, 2026

Public API changes for crate: brush-core

Removed items

-pub struct brush_core::extensions::DefaultPlaceholder
-impl brush_core::extensions::PlaceholderBehavior for brush_core::extensions::DefaultPlaceholder
-impl brush_core::extensions::PlaceholderBehavior for brush_core::extensions::DefaultPlaceholder
-impl<EF: brush_core::extensions::ErrorFormatter> brush_core::extensions::ShellExtensions for brush_core::extensions::ShellExtensionsImpl<EF>
-impl<EF: brush_core::extensions::ErrorFormatter> brush_core::extensions::ShellExtensions for brush_core::extensions::ShellExtensionsImpl<EF>
-impl<EF: brush_core::extensions::ErrorFormatter> brush_core::extensions::ShellExtensions for brush_core::extensions::ShellExtensionsImpl<EF>
-pub type brush_core::extensions::ShellExtensionsImpl<EF>::ErrorFormatter = EF
-pub type brush_core::extensions::ShellExtensionsImpl<EF>::ErrorFormatter = EF
-pub type brush_core::extensions::ShellExtensionsImpl<EF>::ErrorFormatter = EF
-pub trait brush_core::extensions::PlaceholderBehavior: core::clone::Clone + core::default::Default + core::marker::Send + core::marker::Sync + 'static

Added items

+impl<EF: brush_core::extensions::ErrorFormatter, CF: brush_core::filter::CmdExecFilter, SF: brush_core::filter::SourceFilter> brush_core::extensions::ShellExtensionsImpl<EF, CF, SF>
+pub const fn brush_core::extensions::ShellExtensionsImpl<EF, CF, SF>::cmd_exec_filter(&self) -> &CF
+pub const fn brush_core::extensions::ShellExtensionsImpl<EF, CF, SF>::error_formatter(&self) -> &EF
+pub const fn brush_core::extensions::ShellExtensionsImpl<EF, CF, SF>::source_filter(&self) -> &SF
+impl<EF: brush_core::extensions::ErrorFormatter, CF: brush_core::filter::CmdExecFilter, SF: brush_core::filter::SourceFilter> brush_core::extensions::ShellExtensions for brush_core::extensions::ShellExtensionsImpl<EF, CF, SF>
+impl<EF: brush_core::extensions::ErrorFormatter, CF: brush_core::filter::CmdExecFilter, SF: brush_core::filter::SourceFilter> brush_core::extensions::ShellExtensions for brush_core::extensions::ShellExtensionsImpl<EF, CF, SF>
+impl<EF: brush_core::extensions::ErrorFormatter, CF: brush_core::filter::CmdExecFilter, SF: brush_core::filter::SourceFilter> brush_core::extensions::ShellExtensions for brush_core::extensions::ShellExtensionsImpl<EF, CF, SF>
+pub type brush_core::extensions::ShellExtensionsImpl<EF, CF, SF>::CmdExecFilter = CF
+pub type brush_core::extensions::ShellExtensionsImpl<EF, CF, SF>::CmdExecFilter = CF
+pub type brush_core::extensions::ShellExtensionsImpl<EF, CF, SF>::CmdExecFilter = CF
+pub type brush_core::extensions::ShellExtensionsImpl<EF, CF, SF>::ErrorFormatter = EF
+pub type brush_core::extensions::ShellExtensionsImpl<EF, CF, SF>::ErrorFormatter = EF
+pub type brush_core::extensions::ShellExtensionsImpl<EF, CF, SF>::ErrorFormatter = EF
+pub type brush_core::extensions::ShellExtensionsImpl<EF, CF, SF>::SourceFilter = SF
+pub type brush_core::extensions::ShellExtensionsImpl<EF, CF, SF>::SourceFilter = SF
+pub type brush_core::extensions::ShellExtensionsImpl<EF, CF, SF>::SourceFilter = SF
+pub type brush_core::extensions::ShellExtensions::CmdExecFilter: brush_core::filter::CmdExecFilter
+pub type brush_core::extensions::ShellExtensions::SourceFilter: brush_core::filter::SourceFilter
+pub mod brush_core::filter
+#[non_exhaustive] pub enum brush_core::filter::PostFilterResult<O>
+pub brush_core::filter::PostFilterResult::Return(O)
+#[non_exhaustive] pub enum brush_core::filter::PreFilterResult<I, O>
+pub brush_core::filter::PreFilterResult::Continue(I)
+pub brush_core::filter::PreFilterResult::Return(O)
+#[non_exhaustive] pub struct brush_core::filter::ExternalCmdParams<'a, SE: brush_core::extensions::ShellExtensions>
+pub brush_core::filter::ExternalCmdParams::command: brush_core::filter::ExternalCommand
+pub brush_core::filter::ExternalCmdParams::shell: &'a brush_core::Shell<SE>
+impl<'a, SE: brush_core::extensions::ShellExtensions> brush_core::filter::ExternalCmdParams<'a, SE>
+pub const fn brush_core::filter::ExternalCmdParams<'a, SE>::new(shell: &'a brush_core::Shell<SE>, command: brush_core::filter::ExternalCommand) -> Self
+pub struct brush_core::filter::ExternalCommand
+impl brush_core::filter::ExternalCommand
+pub fn brush_core::filter::ExternalCommand::arg(&mut self, arg: impl core::convert::AsRef<std::ffi::os_str::OsStr>) -> &mut Self
+pub fn brush_core::filter::ExternalCommand::args(&self) -> &[std::ffi::os_str::OsString]
+pub fn brush_core::filter::ExternalCommand::args_extend<I, S>(&mut self, args: I) -> &mut Self where I: core::iter::traits::collect::IntoIterator<Item = S>, S: core::convert::AsRef<std::ffi::os_str::OsStr>
+pub const fn brush_core::filter::ExternalCommand::clear_env(&mut self) -> &mut Self
+pub fn brush_core::filter::ExternalCommand::current_dir(&self) -> core::option::Option<&std::path::Path>
+pub fn brush_core::filter::ExternalCommand::env(&mut self, key: impl core::convert::AsRef<std::ffi::os_str::OsStr>, val: impl core::convert::AsRef<std::ffi::os_str::OsStr>) -> &mut Self
+pub const fn brush_core::filter::ExternalCommand::env_clear(&self) -> bool
+pub fn brush_core::filter::ExternalCommand::envs(&self) -> &[(std::ffi::os_str::OsString, std::ffi::os_str::OsString)]
+pub fn brush_core::filter::ExternalCommand::into_std_command(self) -> std::process::Command
+pub fn brush_core::filter::ExternalCommand::new(program: impl core::convert::AsRef<std::ffi::os_str::OsStr>) -> Self
+pub fn brush_core::filter::ExternalCommand::program(&self) -> &std::ffi::os_str::OsStr
+pub fn brush_core::filter::ExternalCommand::set_current_dir(&mut self, dir: impl core::convert::AsRef<std::path::Path>) -> &mut Self
+pub fn brush_core::filter::ExternalCommand::set_program(&mut self, program: impl core::convert::AsRef<std::ffi::os_str::OsStr>) -> &mut Self
+pub struct brush_core::filter::FilterStack<First, Second>
+pub brush_core::filter::FilterStack::first: First
+pub brush_core::filter::FilterStack::second: Second
+impl<First, Second> brush_core::filter::FilterStack<First, Second>
+pub const fn brush_core::filter::FilterStack<First, Second>::new(first: First, second: Second) -> Self
+impl<First: brush_core::filter::CmdExecFilter, Second: brush_core::filter::CmdExecFilter> brush_core::filter::CmdExecFilter for brush_core::filter::FilterStack<First, Second>
+impl<First: brush_core::filter::CmdExecFilter, Second: brush_core::filter::CmdExecFilter> brush_core::filter::CmdExecFilter for brush_core::filter::FilterStack<First, Second>
+pub async fn brush_core::filter::FilterStack<First, Second>::post_external_cmd(&self, result: brush_core::filter::ExternalCmdOutput) -> brush_core::filter::PostFilterResult<brush_core::filter::ExternalCmdOutput>
+pub async fn brush_core::filter::FilterStack<First, Second>::post_external_cmd(&self, result: brush_core::filter::ExternalCmdOutput) -> brush_core::filter::PostFilterResult<brush_core::filter::ExternalCmdOutput>
+pub async fn brush_core::filter::FilterStack<First, Second>::post_simple_cmd(&self, result: brush_core::filter::SimpleCmdOutput) -> brush_core::filter::PostFilterResult<brush_core::filter::SimpleCmdOutput>
+pub async fn brush_core::filter::FilterStack<First, Second>::post_simple_cmd(&self, result: brush_core::filter::SimpleCmdOutput) -> brush_core::filter::PostFilterResult<brush_core::filter::SimpleCmdOutput>
+pub async fn brush_core::filter::FilterStack<First, Second>::pre_external_cmd<'a, SE: brush_core::extensions::ShellExtensions>(&self, params: brush_core::filter::ExternalCmdParams<'a, SE>) -> brush_core::filter::PreFilterResult<brush_core::filter::ExternalCmdParams<'a, SE>, brush_core::filter::ExternalCmdOutput>
+pub async fn brush_core::filter::FilterStack<First, Second>::pre_external_cmd<'a, SE: brush_core::extensions::ShellExtensions>(&self, params: brush_core::filter::ExternalCmdParams<'a, SE>) -> brush_core::filter::PreFilterResult<brush_core::filter::ExternalCmdParams<'a, SE>, brush_core::filter::ExternalCmdOutput>
+pub async fn brush_core::filter::FilterStack<First, Second>::pre_simple_cmd<'a, SE: brush_core::extensions::ShellExtensions>(&self, params: brush_core::filter::SimpleCmdParams<'a, SE>) -> brush_core::filter::PreFilterResult<brush_core::filter::SimpleCmdParams<'a, SE>, brush_core::filter::SimpleCmdOutput>
+pub async fn brush_core::filter::FilterStack<First, Second>::pre_simple_cmd<'a, SE: brush_core::extensions::ShellExtensions>(&self, params: brush_core::filter::SimpleCmdParams<'a, SE>) -> brush_core::filter::PreFilterResult<brush_core::filter::SimpleCmdParams<'a, SE>, brush_core::filter::SimpleCmdOutput>
+impl<First: brush_core::filter::SourceFilter, Second: brush_core::filter::SourceFilter> brush_core::filter::SourceFilter for brush_core::filter::FilterStack<First, Second>
+impl<First: brush_core::filter::SourceFilter, Second: brush_core::filter::SourceFilter> brush_core::filter::SourceFilter for brush_core::filter::FilterStack<First, Second>
+pub async fn brush_core::filter::FilterStack<First, Second>::post_source_script(&self, result: brush_core::filter::SourceScriptOutput) -> brush_core::filter::PostFilterResult<brush_core::filter::SourceScriptOutput>
+pub async fn brush_core::filter::FilterStack<First, Second>::post_source_script(&self, result: brush_core::filter::SourceScriptOutput) -> brush_core::filter::PostFilterResult<brush_core::filter::SourceScriptOutput>
+pub async fn brush_core::filter::FilterStack<First, Second>::pre_source_script<'a, SE: brush_core::extensions::ShellExtensions>(&self, params: brush_core::filter::SourceScriptParams<'a, SE>) -> brush_core::filter::PreFilterResult<brush_core::filter::SourceScriptParams<'a, SE>, brush_core::filter::SourceScriptOutput>
+pub async fn brush_core::filter::FilterStack<First, Second>::pre_source_script<'a, SE: brush_core::extensions::ShellExtensions>(&self, params: brush_core::filter::SourceScriptParams<'a, SE>) -> brush_core::filter::PreFilterResult<brush_core::filter::SourceScriptParams<'a, SE>, brush_core::filter::SourceScriptOutput>
+impl<First: core::clone::Clone, Second: core::clone::Clone> core::clone::Clone for brush_core::filter::FilterStack<First, Second>
+pub fn brush_core::filter::FilterStack<First, Second>::clone(&self) -> Self
+impl<First: core::default::Default, Second: core::default::Default> core::default::Default for brush_core::filter::FilterStack<First, Second>
+pub fn brush_core::filter::FilterStack<First, Second>::default() -> Self
+pub struct brush_core::filter::NoOpCmdExecFilter
+impl brush_core::filter::CmdExecFilter for brush_core::filter::NoOpCmdExecFilter
+impl brush_core::filter::CmdExecFilter for brush_core::filter::NoOpCmdExecFilter
+pub struct brush_core::filter::NoOpSourceFilter
+impl brush_core::filter::SourceFilter for brush_core::filter::NoOpSourceFilter
+impl brush_core::filter::SourceFilter for brush_core::filter::NoOpSourceFilter
+#[non_exhaustive] pub struct brush_core::filter::SimpleCmdParams<'a, SE: brush_core::extensions::ShellExtensions>
+pub brush_core::filter::SimpleCmdParams::args: alloc::borrow::Cow<'a, [alloc::string::String]>
+pub brush_core::filter::SimpleCmdParams::command_name: alloc::borrow::Cow<'a, str>
+pub brush_core::filter::SimpleCmdParams::shell: &'a brush_core::Shell<SE>
+impl<'a, SE: brush_core::extensions::ShellExtensions> brush_core::filter::SimpleCmdParams<'a, SE>
+pub fn brush_core::filter::SimpleCmdParams<'a, SE>::args(&self) -> &[alloc::string::String]
+pub fn brush_core::filter::SimpleCmdParams<'a, SE>::args_to_strings(&self) -> alloc::borrow::Cow<'_, [alloc::string::String]>
+pub fn brush_core::filter::SimpleCmdParams<'a, SE>::command_name(&self) -> &str
+pub fn brush_core::filter::SimpleCmdParams<'a, SE>::from_command_args(shell: &'a brush_core::Shell<SE>, command_name: impl core::convert::Into<alloc::borrow::Cow<'a, str>>, args: &'a [brush_core::commands::CommandArg]) -> Self
+pub fn brush_core::filter::SimpleCmdParams<'a, SE>::new(shell: &'a brush_core::Shell<SE>, command_name: impl core::convert::Into<alloc::borrow::Cow<'a, str>>, args: impl core::convert::Into<alloc::borrow::Cow<'a, [alloc::string::String]>>) -> Self
+#[non_exhaustive] pub struct brush_core::filter::SourceScriptParams<'a, SE: brush_core::extensions::ShellExtensions>
+pub brush_core::filter::SourceScriptParams::args: alloc::borrow::Cow<'a, [alloc::string::String]>
+pub brush_core::filter::SourceScriptParams::path: alloc::borrow::Cow<'a, std::path::Path>
+pub brush_core::filter::SourceScriptParams::shell: &'a brush_core::Shell<SE>
+impl<'a, SE: brush_core::extensions::ShellExtensions> brush_core::filter::SourceScriptParams<'a, SE>
+pub fn brush_core::filter::SourceScriptParams<'a, SE>::args(&self) -> &[alloc::string::String]
+pub fn brush_core::filter::SourceScriptParams<'a, SE>::new(shell: &'a brush_core::Shell<SE>, path: impl core::convert::Into<alloc::borrow::Cow<'a, std::path::Path>>, args: impl core::convert::Into<alloc::borrow::Cow<'a, [alloc::string::String]>>) -> Self
+pub fn brush_core::filter::SourceScriptParams<'a, SE>::path(&self) -> &std::path::Path
+pub trait brush_core::filter::CmdExecFilter: core::clone::Clone + core::default::Default + core::marker::Send + core::marker::Sync + 'static
+pub fn brush_core::filter::CmdExecFilter::post_external_cmd(&self, result: brush_core::filter::ExternalCmdOutput) -> impl core::future::future::Future<Output = brush_core::filter::PostFilterResult<brush_core::filter::ExternalCmdOutput>> + core::marker::Send
+pub fn brush_core::filter::CmdExecFilter::post_simple_cmd(&self, result: brush_core::filter::SimpleCmdOutput) -> impl core::future::future::Future<Output = brush_core::filter::PostFilterResult<brush_core::filter::SimpleCmdOutput>> + core::marker::Send
+pub fn brush_core::filter::CmdExecFilter::pre_external_cmd<'a, SE: brush_core::extensions::ShellExtensions>(&self, params: brush_core::filter::ExternalCmdParams<'a, SE>) -> impl core::future::future::Future<Output = brush_core::filter::PreFilterResult<brush_core::filter::ExternalCmdParams<'a, SE>, brush_core::filter::ExternalCmdOutput>> + core::marker::Send
+pub fn brush_core::filter::CmdExecFilter::pre_simple_cmd<'a, SE: brush_core::extensions::ShellExtensions>(&self, params: brush_core::filter::SimpleCmdParams<'a, SE>) -> impl core::future::future::Future<Output = brush_core::filter::PreFilterResult<brush_core::filter::SimpleCmdParams<'a, SE>, brush_core::filter::SimpleCmdOutput>> + core::marker::Send
+pub trait brush_core::filter::CmdExecFilterExt: brush_core::filter::CmdExecFilter + core::marker::Sized
+pub fn brush_core::filter::CmdExecFilterExt::and_then<F: brush_core::filter::CmdExecFilter>(self, next: F) -> brush_core::filter::FilterStack<Self, F>
+impl<T: brush_core::filter::CmdExecFilter> brush_core::filter::CmdExecFilterExt for T
+pub trait brush_core::filter::SourceFilter: core::clone::Clone + core::default::Default + core::marker::Send + core::marker::Sync + 'static
+pub fn brush_core::filter::SourceFilter::post_source_script(&self, result: brush_core::filter::SourceScriptOutput) -> impl core::future::future::Future<Output = brush_core::filter::PostFilterResult<brush_core::filter::SourceScriptOutput>> + core::marker::Send
+pub fn brush_core::filter::SourceFilter::pre_source_script<'a, SE: brush_core::extensions::ShellExtensions>(&self, params: brush_core::filter::SourceScriptParams<'a, SE>) -> impl core::future::future::Future<Output = brush_core::filter::PreFilterResult<brush_core::filter::SourceScriptParams<'a, SE>, brush_core::filter::SourceScriptOutput>> + core::marker::Send
+pub trait brush_core::filter::SourceFilterExt: brush_core::filter::SourceFilter + core::marker::Sized
+pub fn brush_core::filter::SourceFilterExt::and_then<F: brush_core::filter::SourceFilter>(self, next: F) -> brush_core::filter::FilterStack<Self, F>
+impl<T: brush_core::filter::SourceFilter> brush_core::filter::SourceFilterExt for T
+pub type brush_core::filter::ExternalCmdOutput = core::result::Result<brush_core::results::ExecutionSpawnResult, brush_core::error::Error>
+pub type brush_core::filter::SimpleCmdOutput = core::result::Result<brush_core::results::ExecutionSpawnResult, brush_core::error::Error>
+pub type brush_core::filter::SourceScriptOutput = core::result::Result<brush_core::results::ExecutionResult, brush_core::error::Error>
+pub macro brush_core::with_filter!
+pub brush_core::CreateOptions::cmd_exec_filter: <SE as brush_core::extensions::ShellExtensions>::CmdExecFilter
+pub brush_core::CreateOptions::source_filter: <SE as brush_core::extensions::ShellExtensions>::SourceFilter
+pub const fn brush_core::Shell<SE>::cmd_exec_filter(&self) -> &<SE as brush_core::extensions::ShellExtensions>::CmdExecFilter
+pub const fn brush_core::Shell<SE>::source_filter(&self) -> &<SE as brush_core::extensions::ShellExtensions>::SourceFilter
+pub type brush_core::ShellBuilderState::CmdExecFilter
+pub type brush_core::ShellBuilderState::SourceFilter
+pub type brush_core::ShellExtensions::CmdExecFilter: brush_core::filter::CmdExecFilter
+pub type brush_core::ShellExtensions::SourceFilter: brush_core::filter::SourceFilter

Changed items

-pub struct brush_core::extensions::ShellExtensionsImpl<EF: brush_core::extensions::ErrorFormatter>
+pub struct brush_core::extensions::ShellExtensionsImpl<EF: brush_core::extensions::ErrorFormatter, CF: brush_core::filter::CmdExecFilter, SF: brush_core::filter::SourceFilter>

Performance Benchmark Report

Benchmark name Baseline (μs) Test/PR (μs) Delta (μs) Delta %
clone_shell_object 16.78 μs 16.75 μs -0.03 μs ⚪ Unchanged
eval_arithmetic 0.15 μs 0.15 μs 0.00 μs ⚪ Unchanged
expand_one_string 1.56 μs 1.52 μs -0.04 μs ⚪ Unchanged
for_loop 22.44 μs 23.25 μs 0.82 μs 🟠 +3.65%
function_call 2.38 μs 2.13 μs -0.25 μs ⚪ Unchanged
instantiate_shell 52.21 μs 52.16 μs -0.05 μs ⚪ Unchanged
instantiate_shell_with_init_scripts 24345.46 μs 24146.96 μs -198.50 μs 🟢 -0.82%
parse_bash_completion 2026.55 μs 2047.02 μs 20.48 μs ⚪ Unchanged
parse_sample_script 1.93 μs 1.95 μs 0.02 μs 🟠 +1.04%
run_echo_builtin_command 15.02 μs 15.24 μs 0.22 μs ⚪ Unchanged
tokenize_sample_script 3.37 μs 3.36 μs -0.02 μs ⚪ Unchanged

Code Coverage Report: Only Changed Files listed

Package Base Coverage New Coverage Difference
brush-core/src/commands.rs 🟢 91.74% 🟢 92.16% 🟢 0.42%
brush-core/src/error.rs 🟢 90.91% 🟢 94.81% 🟢 3.9%
brush-core/src/filter.rs 🔴 0% 🟢 76.58% 🟢 76.58%
brush-core/src/shell.rs 🟢 93.4% 🟢 91.23% 🔴 -2.17%
brush-core/src/shell/builder.rs 🟢 79.59% 🟢 80% 🟢 0.41%
Overall Coverage 🟢 74.44% 🟢 74.5% 🟢 0.06%

Minimum allowed coverage is 70%, this run produced 74.5%

Test Summary: bash-completion test suite

Outcome Count Percentage
✅ Pass 1560 73.97
❗️ Error 17 0.81
❌ Fail 178 8.44
⏩ Skip 339 16.07
❎ Expected Fail 13 0.62
✔️ Unexpected Pass 2 0.09
📊 Total 2109 100.00

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants