aboutsummaryrefslogtreecommitdiff
path: root/mingling_core/src/program
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-05-18 22:32:05 +0800
committer魏曹先生 <1992414357@qq.com>2026-05-18 22:32:05 +0800
commit5d61201e9532cfc92f4b93e34b7c10a97cfb35df (patch)
treee2692856b95dd0196af521abc1be10a7415801e2 /mingling_core/src/program
parentda5a750965dbec5a2c003faa8fb9f1dd110ccce8 (diff)
Add REPL pre/post readline hooks and suppress dead code warnings
Diffstat (limited to 'mingling_core/src/program')
-rw-r--r--mingling_core/src/program/hook.rs58
-rw-r--r--mingling_core/src/program/repl_exec.rs46
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<fn()>,
+ /// Executes before reading the next REPL line (only available with `repl` feature)
+ #[cfg(feature = "repl")]
+ pub repl_pre_readline: Option<fn()>,
+
+ /// Executes after reading a REPL line (only available with `repl` feature)
+ #[cfg(feature = "repl")]
+ pub repl_post_readline: Option<fn(line: &str)>,
+
/// Executes when the REPL receives a render result (only available with `repl` feature)
#[cfg(feature = "repl")]
pub repl_on_receive_result: Option<fn(&RenderResult)>,
@@ -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<C> Program<C>
where
C: ProgramCollect<Enum = C> + 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<C> Program<C>
-where
- C: ProgramCollect<Enum = C> + 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<C>(
p: &'static Program<C>,
args: Vec<String>,