diff options
| author | 魏曹先生 <1992414357@qq.com> | 2026-08-15 03:28:02 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2026-08-15 03:28:02 +0800 |
| commit | ec6c87d12062576271231b88364a4aa00765ae65 (patch) | |
| tree | c1fcc3583aaffa06c0857403b557231719dde1af /mingling_core/src | |
| parent | 372eb14ab9a9b7fc0e5334ca15a9d8b656140e54 (diff) | |
feat(core): allow pre_dispatch hooks to mutate arguments
Change `HookPreDispatchInfo.arguments` from `&[String]` to `&mut
Vec<String>`
so hooks can rewrite command-line arguments before dispatch.
Diffstat (limited to 'mingling_core/src')
| -rw-r--r-- | mingling_core/src/program/exec.rs | 9 | ||||
| -rw-r--r-- | mingling_core/src/program/hook.rs | 31 | ||||
| -rw-r--r-- | mingling_core/src/program/hook/hook_info.rs | 5 | ||||
| -rw-r--r-- | mingling_core/src/program/once_exec.rs | 14 | ||||
| -rw-r--r-- | mingling_core/src/program/repl_exec.rs | 10 |
5 files changed, 46 insertions, 23 deletions
diff --git a/mingling_core/src/program/exec.rs b/mingling_core/src/program/exec.rs index 923b47b..b0a5b16 100644 --- a/mingling_core/src/program/exec.rs +++ b/mingling_core/src/program/exec.rs @@ -15,13 +15,14 @@ pub fn exec<C>(program: &'static Program<C>) -> Result<RenderResult, ProgramInte where C: ProgramCollect<Enum = C> + Send + Sync, { - might_be_async::invoke!(exec_with_args(program, &program.args)) + let mut args = program.args.clone(); + might_be_async::invoke!(exec_with_args(program, &mut args)) } #[might_be_async::func] pub fn exec_with_args<C>( program: &'static Program<C>, - args: &[String], + args: &mut Vec<String>, ) -> Result<RenderResult, ProgramInternalExecuteError> where C: ProgramCollect<Enum = C> + Send + Sync, @@ -51,7 +52,9 @@ where // Run hooks control!( - program.run_hook_pre_dispatch(&crate::hook::HookPreDispatchInfo { arguments: args }), + program.run_hook_pre_dispatch(&mut crate::hook::HookPreDispatchInfo { + arguments: &mut *args, + }), current ); diff --git a/mingling_core/src/program/hook.rs b/mingling_core/src/program/hook.rs index 8fd2ba1..92106f9 100644 --- a/mingling_core/src/program/hook.rs +++ b/mingling_core/src/program/hook.rs @@ -64,8 +64,9 @@ where pub begin: Option<Box<dyn Fn(&HookBeginInfo) + Send + Sync>>, /// Executes before the program dispatches - pub pre_dispatch: - Option<Box<dyn for<'a> Fn(&HookPreDispatchInfo<'a>) -> ProgramControls<C> + Send + Sync>>, + pub pre_dispatch: Option< + Box<dyn for<'a> Fn(&mut HookPreDispatchInfo<'a>) -> ProgramControls<C> + Send + Sync>, + >, /// Executes after the program dispatches pub post_dispatch: Option< @@ -162,7 +163,10 @@ where } } - pub(crate) fn run_hook_pre_dispatch(&self, info: &HookPreDispatchInfo) -> ProgramControls<C> { + pub(crate) fn run_hook_pre_dispatch( + &self, + info: &mut HookPreDispatchInfo, + ) -> ProgramControls<C> { if !self.user_context.run_hook { return ProgramControls::Empty; } @@ -475,7 +479,7 @@ where #[must_use] pub fn on_pre_dispatch<F, R>(mut self, handler: F) -> Self where - F: for<'a> Fn(&HookPreDispatchInfo<'a>) -> R + 'static + Send + Sync, + F: for<'a> Fn(&mut HookPreDispatchInfo<'a>) -> R + 'static + Send + Sync, R: Into<ProgramControls<C>>, { self.pre_dispatch = Some(Box::new(move |info| handler(info).into())); @@ -801,16 +805,21 @@ mod tests { #[test] fn test_hook_on_pre_dispatch() { static CALLED: AtomicBool = AtomicBool::new(false); - let hook = - ProgramHook::<MockHookEnum>::empty().on_pre_dispatch(|info: &HookPreDispatchInfo| { - assert_eq!(info.arguments, &["a", "b"]); + let mut args = vec!["a".to_string(), "b".to_string()]; + let hook = ProgramHook::<MockHookEnum>::empty().on_pre_dispatch( + |info: &mut HookPreDispatchInfo| { + assert_eq!(info.arguments.as_slice(), &["a", "b"]); + // The hook may rewrite the arguments before dispatch + info.arguments.push("c".to_string()); CALLED.store(true, Ordering::SeqCst); - }); + }, + ); assert!(hook.pre_dispatch.is_some()); - (hook.pre_dispatch.as_ref().unwrap())(&HookPreDispatchInfo { - arguments: &["a".to_string(), "b".to_string()], + (hook.pre_dispatch.as_ref().unwrap())(&mut HookPreDispatchInfo { + arguments: &mut args, }); assert!(CALLED.load(Ordering::SeqCst)); + assert_eq!(args.as_slice(), &["a", "b", "c"]); } #[test] @@ -910,7 +919,7 @@ mod tests { fn test_hook_builder_chaining() { let hook = ProgramHook::<MockHookEnum>::empty() .on_begin::<_, ()>(|_: &HookBeginInfo| ()) - .on_pre_dispatch(|_: &HookPreDispatchInfo| ()) + .on_pre_dispatch(|_: &mut HookPreDispatchInfo| ()) .on_post_dispatch(|_: &HookPostDispatchInfo<MockHookEnum>| ()) .on_pre_chain(|_: &HookPreChainInfo<MockHookEnum>| ()) .on_post_chain(|_: &HookPostChainInfo<MockHookEnum>| ()) diff --git a/mingling_core/src/program/hook/hook_info.rs b/mingling_core/src/program/hook/hook_info.rs index 768f652..25cf272 100644 --- a/mingling_core/src/program/hook/hook_info.rs +++ b/mingling_core/src/program/hook/hook_info.rs @@ -7,7 +7,10 @@ pub struct HookBeginInfo {} /// Represents the data passed to `pre_dispatch` hook. pub struct HookPreDispatchInfo<'a> { /// Arguments entered by the user before dispatching - pub arguments: &'a [String], + /// + /// The reference is mutable so the hook can rewrite the arguments before + /// they are matched against the registered dispatchers. + pub arguments: &'a mut Vec<String>, } /// Represents the data passed to `post_dispatch` hook. diff --git a/mingling_core/src/program/once_exec.rs b/mingling_core/src/program/once_exec.rs index e9927b5..203bbf5 100644 --- a/mingling_core/src/program/once_exec.rs +++ b/mingling_core/src/program/once_exec.rs @@ -25,15 +25,19 @@ where self.run_hook_on_begin(&crate::hook::HookBeginInfo {}); self.args = self.args.iter().skip(1).cloned().collect(); + let mut args = std::mem::take(&mut self.args); #[cfg(not(feature = "async"))] { #[cfg(panic = "abort")] - return self.exec_wrapper(|p| crate::exec::exec(p).map_err(|e| e.into())); + return self + .exec_wrapper(|p| crate::exec::exec_with_args(p, &mut args).map_err(|e| e.into())); #[cfg(not(panic = "abort"))] match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { - self.exec_wrapper(|p| crate::exec::exec(p).map_err(std::convert::Into::into)) + self.exec_wrapper(|p| { + crate::exec::exec_with_args(p, &mut args).map_err(std::convert::Into::into) + }) })) { Ok(result) => result, Err(panic_info) => { @@ -60,7 +64,11 @@ where #[cfg(feature = "async")] { return self - .exec_wrapper(|p| async { crate::exec::exec(p).await.map_err(Into::into) }) + .exec_wrapper(|p| async move { + crate::exec::exec_with_args(p, &mut args) + .await + .map_err(Into::into) + }) .await; } } diff --git a/mingling_core/src/program/repl_exec.rs b/mingling_core/src/program/repl_exec.rs index 9d9be30..b91f7bc 100644 --- a/mingling_core/src/program/repl_exec.rs +++ b/mingling_core/src/program/repl_exec.rs @@ -58,10 +58,10 @@ where line: &mut readline, }); - let args = split_input_string(&readline); + let mut args = split_input_string(&readline); p.run_hook_repl_pre_exec(&crate::hook::HookREPLPreExecInfo { args: &args }); - match might_be_async::invoke!(exec_once(p, &args)) { + match might_be_async::invoke!(exec_once(p, &mut args)) { Ok(r) => { p.run_hook_repl_on_receive_result(&crate::hook::HookREPLOnReceiveResultInfo { result: &r, @@ -91,13 +91,13 @@ where #[cfg(not(feature = "async"))] fn exec_once<C>( p: &'static Program<C>, - args: &[String], + args: &mut Vec<String>, ) -> Result<RenderResult, ProgramInternalExecuteError> where C: ProgramCollect<Enum = C> + Send + Sync + 'static, { #[cfg(panic = "abort")] - let exec_result = super::exec::exec_with_args(p, &args); + let exec_result = super::exec::exec_with_args(p, args); #[cfg(not(panic = "abort"))] let exec_result = { @@ -130,7 +130,7 @@ where #[cfg(feature = "async")] async fn exec_once<C>( p: &'static Program<C>, - args: &[String], + args: &mut Vec<String>, ) -> Result<RenderResult, ProgramInternalExecuteError> where C: ProgramCollect<Enum = C> + Send + Sync + 'static, |
