From 5d61201e9532cfc92f4b93e34b7c10a97cfb35df Mon Sep 17 00:00:00 2001 From: 魏曹先生 <1992414357@qq.com> Date: Mon, 18 May 2026 22:32:05 +0800 Subject: Add REPL pre/post readline hooks and suppress dead code warnings --- mingling_core/src/program/hook.rs | 58 ++++++++++++++++++++++++++++++++++ mingling_core/src/program/repl_exec.rs | 46 ++++++++++++--------------- 2 files changed, 78 insertions(+), 26 deletions(-) diff --git a/mingling_core/src/program/hook.rs b/mingling_core/src/program/hook.rs index 448949f..65f3f0b 100644 --- a/mingling_core/src/program/hook.rs +++ b/mingling_core/src/program/hook.rs @@ -1,3 +1,5 @@ +#![allow(dead_code)] + use std::any::Any; use crate::{AnyOutput, Program, ProgramCollect, RenderResult, error::ProgramPanic}; @@ -38,6 +40,14 @@ where #[cfg(feature = "repl")] pub repl_on_begin: Option, + /// Executes before reading the next REPL line (only available with `repl` feature) + #[cfg(feature = "repl")] + pub repl_pre_readline: Option, + + /// Executes after reading a REPL line (only available with `repl` feature) + #[cfg(feature = "repl")] + pub repl_post_readline: Option, + /// Executes when the REPL receives a render result (only available with `repl` feature) #[cfg(feature = "repl")] pub repl_on_receive_result: Option, @@ -185,6 +195,34 @@ where } } + /// Runs the REPL pre-readline hooks (only available with `repl` feature) + #[cfg(feature = "repl")] + pub(crate) fn run_hook_repl_pre_readline(&self) { + if !self.user_context.run_hook { + return; + } + + for hook in &self.hooks { + if let Some(repl_pre_readline) = hook.repl_pre_readline { + repl_pre_readline() + } + } + } + + /// Runs the REPL post-readline hooks (only available with `repl` feature) + #[cfg(feature = "repl")] + pub(crate) fn run_hook_repl_post_readline(&self, line: &str) { + if !self.user_context.run_hook { + return; + } + + for hook in &self.hooks { + if let Some(repl_post_readline) = hook.repl_post_readline { + repl_post_readline(line) + } + } + } + /// Runs the REPL receive result hooks (only available with `repl` feature) #[cfg(feature = "repl")] pub(crate) fn run_hook_repl_on_receive_result(&self, result: &RenderResult) { @@ -233,6 +271,10 @@ where #[cfg(feature = "repl")] repl_on_begin: None, #[cfg(feature = "repl")] + repl_pre_readline: None, + #[cfg(feature = "repl")] + repl_post_readline: None, + #[cfg(feature = "repl")] repl_on_receive_result: None, #[cfg(feature = "repl")] repl_on_panic: None, @@ -300,6 +342,22 @@ where self } + /// Sets the handler for the REPL pre-readline event (only available with `repl` feature). + /// This hook runs after `on_repl_begin` but before reading the next input line. + #[cfg(feature = "repl")] + pub fn on_repl_pre_readline(mut self, handler: fn()) -> Self { + let _ = self.repl_pre_readline.insert(handler); + self + } + + /// Sets the handler for the REPL post-readline event (only available with `repl` feature). + /// This hook runs after reading a line of input and receives the line as a `&str`. + #[cfg(feature = "repl")] + pub fn on_repl_post_readline(mut self, handler: fn(line: &str)) -> Self { + let _ = self.repl_post_readline.insert(handler); + self + } + /// Sets the handler for the REPL receive result event (only available with `repl` feature). #[cfg(feature = "repl")] pub fn on_repl_receive_result(mut self, handler: fn(result: &RenderResult)) -> Self { diff --git a/mingling_core/src/program/repl_exec.rs b/mingling_core/src/program/repl_exec.rs index c182f78..f3dd9f7 100644 --- a/mingling_core/src/program/repl_exec.rs +++ b/mingling_core/src/program/repl_exec.rs @@ -1,3 +1,6 @@ +#![allow(unused_imports)] +#![allow(dead_code)] + use std::io::Write; mod splitter; @@ -11,37 +14,28 @@ impl Program where C: ProgramCollect + Send + Sync + 'static, { + /// Executes the REPL interactive CLI mode. + /// + /// This method starts an infinite loop that continuously reads user input, parses commands, executes them, + /// and displays the execution result or error message. It is suitable for scenarios requiring command-line interaction with the user. + /// + /// # Important + /// + /// **REPL mode is currently only available when the `async` feature is disabled; it does not support async.** + /// + /// If the `async` feature is enabled, this method will be unavailable (as it is protected by `#[cfg(not(feature = "async"))]` conditional compilation). + /// Future versions may support asynchronous REPL, but currently only synchronous mode is supported. pub fn exec_repl(self) { self.run_hook_repl_on_begin(); self.exec_wrapper(|p| -> ! { loop { - let args = split_input_string(readline_or_empty()); - match exec_once(p, args) { - Ok(r) => { - p.run_hook_repl_on_receive_result(&r); - } - Err(ProgramInternalExecuteError::REPLPanic(panic)) => { - p.run_hook_repl_on_panic(&panic); - } - _ => {} - } - } - }); - } -} + p.run_hook_repl_pre_readline(); + let readline = readline_or_empty(); + p.run_hook_repl_post_readline(&readline); -#[cfg(feature = "async")] -impl Program -where - C: ProgramCollect + Send + Sync, -{ - pub async fn exec_repl(self) { - self.run_hook_repl_on_begin(); + let args = split_input_string(readline.clone()); - self.exec_wrapper(|p| -> ! { - loop { - let args = split_input_string(readline_or_empty()); match exec_once(p, args) { Ok(r) => { p.run_hook_repl_on_receive_result(&r); @@ -52,8 +46,7 @@ where _ => {} } } - }) - .await; + }); } } @@ -68,6 +61,7 @@ fn readline_or_empty() -> String { readline().unwrap_or("".to_string()) } +#[cfg(not(feature = "async"))] fn exec_once( p: &'static Program, args: Vec, -- cgit