summaryrefslogtreecommitdiff
path: root/mingling/src/program
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-03-28 00:47:46 +0800
committer魏曹先生 <1992414357@qq.com>2026-03-28 00:47:46 +0800
commit7ce68cd11516bd7cf037ecea99a92aee7c31b2c3 (patch)
treea3923ad41c91aa21fe169fd6b4b1bf8898a82589 /mingling/src/program
Add initial Mingling framework codebase
Diffstat (limited to 'mingling/src/program')
-rw-r--r--mingling/src/program/config.rs33
-rw-r--r--mingling/src/program/flag.rs115
-rw-r--r--mingling/src/program/setup.rs15
-rw-r--r--mingling/src/program/setup/basic.rs25
4 files changed, 188 insertions, 0 deletions
diff --git a/mingling/src/program/config.rs b/mingling/src/program/config.rs
new file mode 100644
index 0000000..93507e7
--- /dev/null
+++ b/mingling/src/program/config.rs
@@ -0,0 +1,33 @@
+pub struct ProgramStdoutSetting {
+ /// Output error messages
+ pub error_output: bool,
+
+ /// Render results and output
+ pub render_output: bool,
+}
+
+impl Default for ProgramStdoutSetting {
+ fn default() -> Self {
+ ProgramStdoutSetting {
+ error_output: true,
+ render_output: true,
+ }
+ }
+}
+
+pub struct ProgramUserContext {
+ /// View help information instead of running the command
+ pub help: bool,
+
+ /// Skip user confirmation step
+ pub confirm: bool,
+}
+
+impl Default for ProgramUserContext {
+ fn default() -> Self {
+ ProgramUserContext {
+ help: false,
+ confirm: false,
+ }
+ }
+}
diff --git a/mingling/src/program/flag.rs b/mingling/src/program/flag.rs
new file mode 100644
index 0000000..0178ebe
--- /dev/null
+++ b/mingling/src/program/flag.rs
@@ -0,0 +1,115 @@
+use crate::Program;
+
+pub struct Flag {
+ vec: Vec<&'static str>,
+}
+
+impl From<&'static str> for Flag {
+ fn from(s: &'static str) -> Self {
+ Flag { vec: vec![s] }
+ }
+}
+
+impl From<&'static [&'static str]> for Flag {
+ fn from(slice: &'static [&'static str]) -> Self {
+ Flag {
+ vec: slice.to_vec(),
+ }
+ }
+}
+
+impl<const N: usize> From<[&'static str; N]> for Flag {
+ fn from(slice: [&'static str; N]) -> Self {
+ Flag {
+ vec: slice.to_vec(),
+ }
+ }
+}
+
+impl<const N: usize> From<&'static [&'static str; N]> for Flag {
+ fn from(slice: &'static [&'static str; N]) -> Self {
+ Flag {
+ vec: slice.to_vec(),
+ }
+ }
+}
+
+impl AsRef<[&'static str]> for Flag {
+ fn as_ref(&self) -> &[&'static str] {
+ &self.vec
+ }
+}
+
+impl std::ops::Deref for Flag {
+ type Target = [&'static str];
+
+ fn deref(&self) -> &Self::Target {
+ &self.vec
+ }
+}
+
+macro_rules! special_flag {
+ ($args:expr, $flag:expr) => {{
+ let flag = $flag;
+ let found = $args.iter().any(|arg| arg == flag);
+ $args.retain(|arg| arg != flag);
+ found
+ }};
+}
+
+macro_rules! special_argument {
+ ($args:expr, $flag:expr) => {{
+ let flag = $flag;
+ let mut value: Option<String> = None;
+ let mut i = 0;
+ while i < $args.len() {
+ if &$args[i] == flag {
+ if i + 1 < $args.len() {
+ value = Some($args[i + 1].clone());
+ $args.remove(i + 1);
+ $args.remove(i);
+ } else {
+ value = None;
+ $args.remove(i);
+ }
+ break;
+ }
+ i += 1;
+ }
+ value
+ }};
+}
+
+impl Program {
+ /// Registers a global argument (with value) and its handler.
+ pub fn global_argument<F, A>(&mut self, arguments: A, do_fn: F)
+ where
+ F: Fn(&mut Program, String),
+ A: Into<Flag>,
+ {
+ let flag = arguments.into();
+ for argument in flag.iter() {
+ let value = special_argument!(self.args, argument);
+ if let Some(value) = value {
+ do_fn(self, value);
+ return;
+ }
+ }
+ }
+
+ /// Registers a global flag (boolean) and its handler.
+ pub fn global_flag<F, A>(&mut self, flag: A, do_fn: F)
+ where
+ F: Fn(&mut Program),
+ A: Into<Flag>,
+ {
+ let flag = flag.into();
+ for argument in flag.iter() {
+ let enabled = special_flag!(self.args, argument);
+ if enabled {
+ do_fn(self);
+ return;
+ }
+ }
+ }
+}
diff --git a/mingling/src/program/setup.rs b/mingling/src/program/setup.rs
new file mode 100644
index 0000000..fdf7b04
--- /dev/null
+++ b/mingling/src/program/setup.rs
@@ -0,0 +1,15 @@
+use crate::program::Program;
+
+mod basic;
+pub use basic::*;
+
+pub trait ProgramSetup {
+ fn setup(program: &mut Program);
+}
+
+impl Program {
+ /// Load and execute init logic
+ pub fn with_setup<S: ProgramSetup + 'static>(&mut self, _setup: S) {
+ S::setup(self);
+ }
+}
diff --git a/mingling/src/program/setup/basic.rs b/mingling/src/program/setup/basic.rs
new file mode 100644
index 0000000..0ea72a6
--- /dev/null
+++ b/mingling/src/program/setup/basic.rs
@@ -0,0 +1,25 @@
+use crate::program::{Program, setup::ProgramSetup};
+
+/// Performs basic program initialization:
+///
+/// - Collects `--quiet` flag to control message rendering
+/// - Collects `--help` flag to enable help mode
+/// - Collects `--confirm` flag to skip user confirmation
+pub struct BasicProgramSetup;
+
+impl ProgramSetup for BasicProgramSetup {
+ fn setup(program: &mut Program) {
+ program.global_flag(["--quiet", "-q"], |p| {
+ p.stdout_setting.render_output = false;
+ p.stdout_setting.error_output = false;
+ });
+
+ program.global_flag(["--help", "-h"], |p| {
+ p.user_context.help = true;
+ });
+
+ program.global_flag(["--confirm", "-C"], |p| {
+ p.user_context.confirm = true;
+ });
+ }
+}