From 4ac7d7dc9e6abec2f3f84dd5baf8b642727f19c3 Mon Sep 17 00:00:00 2001 From: 魏曹先生 <1992414357@qq.com> Date: Sat, 25 Apr 2026 23:41:36 +0800 Subject: Add help system with `#[help]` macro and `HelpRequest` trait --- mingling_core/src/asset.rs | 3 +++ mingling_core/src/asset/help.rs | 10 +++++++++ mingling_core/src/lib.rs | 1 + mingling_core/src/program.rs | 3 +++ mingling_core/src/program/exec.rs | 35 +++++++++++++++++++++++++++++ mingling_core/src/renderer/render_result.rs | 15 +++++++++++++ 6 files changed, 67 insertions(+) create mode 100644 mingling_core/src/asset/help.rs (limited to 'mingling_core/src') diff --git a/mingling_core/src/asset.rs b/mingling_core/src/asset.rs index a4254ef..234fec1 100644 --- a/mingling_core/src/asset.rs +++ b/mingling_core/src/asset.rs @@ -16,3 +16,6 @@ pub mod node; #[doc(hidden)] pub mod renderer; + +#[doc(hidden)] +pub mod help; diff --git a/mingling_core/src/asset/help.rs b/mingling_core/src/asset/help.rs new file mode 100644 index 0000000..ff2b3d4 --- /dev/null +++ b/mingling_core/src/asset/help.rs @@ -0,0 +1,10 @@ +use crate::RenderResult; + +/// Handles help rendering for command-line arguments +pub trait HelpRequest { + /// The entry type + type Entry; + + /// Process the previous value and write the result into the provided [`RenderResult`](./struct.RenderResult.html) + fn render_help(p: Self::Entry, r: &mut RenderResult); +} diff --git a/mingling_core/src/lib.rs b/mingling_core/src/lib.rs index 87be806..aee0df6 100644 --- a/mingling_core/src/lib.rs +++ b/mingling_core/src/lib.rs @@ -25,6 +25,7 @@ pub use crate::asset::chain::*; pub use crate::asset::comp::*; pub use crate::asset::dispatcher::*; pub use crate::asset::enum_tag::*; +pub use crate::asset::help::*; pub use crate::asset::node::*; pub use crate::asset::renderer::*; diff --git a/mingling_core/src/program.rs b/mingling_core/src/program.rs index c9cffbe..949dd45 100644 --- a/mingling_core/src/program.rs +++ b/mingling_core/src/program.rs @@ -289,6 +289,9 @@ pub trait ProgramCollect { /// Render the input [AnyOutput](./struct.AnyOutput.html) fn render(any: AnyOutput, r: &mut RenderResult); + /// Render help for Entry + fn render_help(any: AnyOutput, r: &mut RenderResult); + /// Find a matching chain to continue execution based on the input [AnyOutput](./struct.AnyOutput.html), returning a new [AnyOutput](./struct.AnyOutput.html) #[cfg(feature = "async")] fn do_chain( diff --git a/mingling_core/src/program/exec.rs b/mingling_core/src/program/exec.rs index c1eada5..469f6d2 100644 --- a/mingling_core/src/program/exec.rs +++ b/mingling_core/src/program/exec.rs @@ -16,6 +16,11 @@ where let mut current = dispatch_args_dynamic(program, program.args.clone())?; let mut stop_next = false; + // If the program has Help enabled, skip actual logic and jump to Help + if program.user_context.help { + return Ok(render_help::(program, current)); + } + loop { let final_exec = stop_next; @@ -56,6 +61,11 @@ where let mut current = dispatch_args_dynamic(program, program.args.clone())?; let mut stop_next = false; + // If the program has Help enabled, skip actual logic and jump to Help + if program.user_context.help { + return Ok(render_help::(program, current)); + } + loop { let final_exec = stop_next; @@ -179,3 +189,28 @@ fn render>(program: &Program, any: AnyOutput) } } } + +#[inline(always)] +#[allow(unused_variables)] +fn render_help>( + program: &Program, + entry: AnyOutput, +) -> RenderResult { + #[cfg(not(feature = "general_renderer"))] + { + let mut render_result = RenderResult::default(); + C::render_help(entry, &mut render_result); + render_result + } + #[cfg(feature = "general_renderer")] + { + match program.general_renderer_name { + super::GeneralRendererSetting::Disable => { + let mut render_result = RenderResult::default(); + C::render_help(entry, &mut render_result); + render_result + } + _ => RenderResult::default(), + } + } +} diff --git a/mingling_core/src/renderer/render_result.rs b/mingling_core/src/renderer/render_result.rs index d9da7b7..3bde1ab 100644 --- a/mingling_core/src/renderer/render_result.rs +++ b/mingling_core/src/renderer/render_result.rs @@ -1,5 +1,6 @@ use std::{ fmt::{Display, Formatter}, + io::Write, ops::Deref, }; @@ -9,6 +10,20 @@ pub struct RenderResult { render_text: String, } +impl Write for RenderResult { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + let s = std::str::from_utf8(buf).map_err(|_| { + std::io::Error::new(std::io::ErrorKind::InvalidInput, "not valid UTF-8") + })?; + self.render_text.push_str(s); + Ok(buf.len()) + } + + fn flush(&mut self) -> std::io::Result<()> { + Ok(()) + } +} + impl Display for RenderResult { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { writeln!(f, "{}", self.render_text.trim()) -- cgit