aboutsummaryrefslogtreecommitdiff
path: root/mingling_core/src/program
diff options
context:
space:
mode:
Diffstat (limited to 'mingling_core/src/program')
-rw-r--r--mingling_core/src/program/hook.rs17
-rw-r--r--mingling_core/src/program/once_exec.rs37
-rw-r--r--mingling_core/src/program/repl_exec.rs53
3 files changed, 62 insertions, 45 deletions
diff --git a/mingling_core/src/program/hook.rs b/mingling_core/src/program/hook.rs
index 65f3f0b..8e231f1 100644
--- a/mingling_core/src/program/hook.rs
+++ b/mingling_core/src/program/hook.rs
@@ -2,7 +2,10 @@
use std::any::Any;
-use crate::{AnyOutput, Program, ProgramCollect, RenderResult, error::ProgramPanic};
+use crate::{AnyOutput, Program, ProgramCollect, RenderResult};
+
+#[cfg(not(feature = "async"))]
+use crate::error::ProgramPanic;
#[derive(Default)]
pub struct ProgramHook<C>
@@ -34,6 +37,7 @@ where
pub finish: Option<fn() -> i32>,
/// Executes when the program panics
+ #[cfg(not(feature = "async"))]
pub exec_panic: Option<fn(&ProgramPanic)>,
/// Executes when the REPL starts (only available with `repl` feature)
@@ -53,7 +57,7 @@ where
pub repl_on_receive_result: Option<fn(&RenderResult)>,
/// Executes when the REPL panics (only available with `repl` feature)
- #[cfg(feature = "repl")]
+ #[cfg(all(feature = "repl", not(feature = "async")))]
pub repl_on_panic: Option<fn(&ProgramPanic)>,
}
@@ -152,6 +156,7 @@ where
}
#[allow(dead_code)]
+ #[cfg(not(feature = "async"))]
pub(crate) fn run_hook_exec_panic(&self, panic_info: &ProgramPanic) {
if !self.user_context.run_hook {
return;
@@ -238,7 +243,7 @@ where
}
/// Runs the REPL panic hooks (only available with `repl` feature)
- #[cfg(feature = "repl")]
+ #[cfg(all(feature = "repl", not(feature = "async")))]
pub(crate) fn run_hook_repl_on_panic(&self, panic_info: &ProgramPanic) {
if !self.user_context.run_hook {
return;
@@ -267,6 +272,7 @@ where
pre_render: None,
post_render: None,
finish: None,
+ #[cfg(not(feature = "async"))]
exec_panic: None,
#[cfg(feature = "repl")]
repl_on_begin: None,
@@ -276,7 +282,7 @@ where
repl_post_readline: None,
#[cfg(feature = "repl")]
repl_on_receive_result: None,
- #[cfg(feature = "repl")]
+ #[cfg(all(feature = "repl", not(feature = "async")))]
repl_on_panic: None,
}
}
@@ -330,6 +336,7 @@ where
}
/// Sets the handler for the `exec_panic` event.
+ #[cfg(not(feature = "async"))]
pub fn on_exec_panic(mut self, handler: fn(&ProgramPanic)) -> Self {
let _ = self.exec_panic.insert(handler);
self
@@ -366,7 +373,7 @@ where
}
/// Sets the handler for the REPL panic event (only available with `repl` feature).
- #[cfg(feature = "repl")]
+ #[cfg(all(feature = "repl", not(feature = "async")))]
pub fn on_repl_panic(mut self, handler: fn(panic: &ProgramPanic)) -> Self {
let _ = self.repl_on_panic.insert(handler);
self
diff --git a/mingling_core/src/program/once_exec.rs b/mingling_core/src/program/once_exec.rs
index b68eb01..e1c0956 100644
--- a/mingling_core/src/program/once_exec.rs
+++ b/mingling_core/src/program/once_exec.rs
@@ -1,8 +1,8 @@
use crate::THIS_PROGRAM;
-use crate::{
- Program, ProgramCollect, RenderResult,
- error::{ProgramExecuteError, ProgramPanic},
-};
+use crate::{Program, ProgramCollect, RenderResult, error::ProgramExecuteError};
+
+#[cfg(not(feature = "async"))]
+use crate::error::ProgramPanic;
// Async program
#[cfg(feature = "async")]
@@ -25,11 +25,6 @@ where
.downcast_ref::<Program<C>>()
.unwrap();
- #[cfg(not(panic = "abort"))]
- if program.stdout_setting.silence_panic {
- std::panic::set_hook(Box::new(|_| {}));
- }
-
f(program).await
}
@@ -43,33 +38,9 @@ where
self.args = self.args.iter().skip(1).cloned().collect();
- #[cfg(panic = "abort")]
return self
.exec_wrapper(|p| async { crate::exec::exec(p).await.map_err(|e| e.into()) })
.await;
-
- #[cfg(not(panic = "abort"))]
- match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
- self.exec_wrapper(|p| async { crate::exec::exec(p).await.map_err(|e| e.into()) })
- })) {
- Ok(fut) => fut.await,
- Err(panic_info) => {
- let panic_payload = ProgramPanic {
- payload: panic_info,
- };
-
- let program = THIS_PROGRAM
- .get()
- .unwrap()
- .as_ref()
- .unwrap()
- .downcast_ref::<Program<C>>()
- .unwrap();
-
- program.run_hook_exec_panic(&panic_payload);
- Err(ProgramExecuteError::Panic(panic_payload))
- }
- }
}
/// Run the command line program
diff --git a/mingling_core/src/program/repl_exec.rs b/mingling_core/src/program/repl_exec.rs
index f3dd9f7..5246ece 100644
--- a/mingling_core/src/program/repl_exec.rs
+++ b/mingling_core/src/program/repl_exec.rs
@@ -18,13 +18,6 @@ where
///
/// 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();
@@ -50,6 +43,41 @@ where
}
}
+#[cfg(feature = "async")]
+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.
+ ///
+ /// **Note:** When the `async` feature is enabled, panic unwinding is not supported.
+ /// Any panics during command execution will result in an abort rather than being caught and handled gracefully.
+ pub async fn exec_repl(self) {
+ self.run_hook_repl_on_begin();
+
+ self.exec_wrapper(async |p| -> ! {
+ loop {
+ p.run_hook_repl_pre_readline();
+ let readline = readline_or_empty();
+ p.run_hook_repl_post_readline(&readline);
+
+ let args = split_input_string(readline.clone());
+
+ match exec_once(p, args).await {
+ Ok(r) => {
+ p.run_hook_repl_on_receive_result(&r);
+ }
+ _ => {}
+ }
+ }
+ })
+ .await;
+ }
+}
+
fn readline() -> Result<String, std::io::Error> {
let mut input = String::new();
std::io::stdout().flush()?;
@@ -99,3 +127,14 @@ where
exec_result
}
+
+#[cfg(feature = "async")]
+async fn exec_once<C>(
+ p: &'static Program<C>,
+ args: Vec<String>,
+) -> Result<RenderResult, ProgramInternalExecuteError>
+where
+ C: ProgramCollect<Enum = C> + Send + Sync + 'static,
+{
+ super::exec::exec_with_args(p, args).await
+}