aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/example-argument-parse/src/main.rs15
-rw-r--r--examples/example-async-support/src/main.rs7
-rw-r--r--examples/example-basic/src/main.rs7
-rw-r--r--examples/example-clap-binding/src/main.rs22
-rw-r--r--examples/example-combine-pathf-dispatch-tree/src/sub/mod.rs9
-rw-r--r--examples/example-completion/src/main.rs7
-rw-r--r--examples/example-custom-pickable/src/main.rs13
-rw-r--r--examples/example-dispatch-tree/src/main.rs7
-rw-r--r--examples/example-enum-tag/src/main.rs8
-rw-r--r--examples/example-error-handling/src/main.rs40
-rw-r--r--examples/example-exitcode/src/main.rs20
-rw-r--r--examples/example-help/src/main.rs7
-rw-r--r--examples/example-hook/src/main.rs8
-rw-r--r--examples/example-lazy-resources/src/main.rs14
-rw-r--r--examples/example-outside-type/src/main.rs19
-rw-r--r--examples/example-pack-err/src/main.rs31
-rw-r--r--examples/example-panic-unwind/src/main.rs8
-rw-r--r--examples/example-pathfinder/src/sub/mod.rs11
-rw-r--r--examples/example-repl-basic/src/main.rs24
-rw-r--r--examples/example-resources/src/main.rs15
-rw-r--r--examples/example-structural-renderer/src/main.rs9
-rw-r--r--examples/example-unit-test/src/main.rs44
-rw-r--r--examples/full-todolist/src/help.rs99
-rw-r--r--examples/full-todolist/src/main.rs40
-rw-r--r--examples/full-todolist/src/todolist.rs22
25 files changed, 330 insertions, 176 deletions
diff --git a/examples/example-argument-parse/src/main.rs b/examples/example-argument-parse/src/main.rs
index 4929b7c..59499a2 100644
--- a/examples/example-argument-parse/src/main.rs
+++ b/examples/example-argument-parse/src/main.rs
@@ -19,6 +19,7 @@
//! ```
use mingling::{macros::route, prelude::*};
+use std::io::Write;
dispatcher!("transfer", CMDTransfer => EntryTransfer);
dispatcher!("strict-transfer", CMDStrictTransfer => EntryStrictTransfer);
@@ -71,20 +72,26 @@ fn handle_strict_transfer_parse(args: EntryStrictTransfer) -> Next {
/// Renders the parsed transfer result (file/dir, size, name).
#[renderer]
-fn render_result_file(result: ResultFile) {
+fn render_result_file(result: ResultFile) -> RenderResult {
let (is_dir, size, name) = result.into();
- r_println!(
+ let mut result = RenderResult::new();
+ writeln!(
+ result,
"{}: {} ({})",
if is_dir { "dir" } else { "file" },
name,
size
)
+ .ok();
+ result
}
/// Renders the error when no name is provided.
#[renderer]
-fn render_error_no_name_provided(_: ErrorNoNameProvided) {
- r_println!("Error: name is not provided")
+fn render_error_no_name_provided(_: ErrorNoNameProvided) -> RenderResult {
+ let mut result = RenderResult::new();
+ writeln!(result, "Error: name is not provided").ok();
+ result
}
gen_program!();
diff --git a/examples/example-async-support/src/main.rs b/examples/example-async-support/src/main.rs
index 847bfea..ac85aaf 100644
--- a/examples/example-async-support/src/main.rs
+++ b/examples/example-async-support/src/main.rs
@@ -24,6 +24,7 @@
//! ```
use mingling::{hook::ProgramHook, prelude::*};
+use std::io::Write;
#[tokio::main]
async fn main() {
@@ -55,8 +56,10 @@ pub async fn handle_download(args: EntryDownload) -> Next {
/// Renders the downloaded file name.
#[renderer]
// But renderers cannot use the `async` keyword
-pub fn render_downloaded(result: ResultDownloaded) {
- r_println!("\"{}\" downloaded.", *result);
+pub fn render_downloaded(result: ResultDownloaded) -> RenderResult {
+ let mut render_result = RenderResult::new();
+ writeln!(render_result, "\"{}\" downloaded.", *result).ok();
+ render_result
}
// --------- IMPORTANT ---------
diff --git a/examples/example-basic/src/main.rs b/examples/example-basic/src/main.rs
index 3d94a4b..7fc0bce 100644
--- a/examples/example-basic/src/main.rs
+++ b/examples/example-basic/src/main.rs
@@ -14,6 +14,7 @@
// Import commonly used Mingling modules
use mingling::prelude::*;
+use std::io::Write;
// Define the `greet` subcommand
// _____________________________ subcmd name, can be nested (e.g. "remote.add" "remote.rm")
@@ -60,8 +61,10 @@ fn handle_greet(args: EntryGreet) -> Next {
// Define renderer `render_name`, used to render `ResultName`
/// Renders the greeting message with the provided name.
#[renderer]
-fn render_name(name: ResultName) {
- r_println!("Hello, {}!", *name);
+fn render_name(name: ResultName) -> RenderResult {
+ let mut render_result = RenderResult::new();
+ writeln!(render_result, "Hello, {}!", *name).ok();
+ render_result
}
// Note: This macro generates the program entry point.
diff --git a/examples/example-clap-binding/src/main.rs b/examples/example-clap-binding/src/main.rs
index 19d794b..d99f8d1 100644
--- a/examples/example-clap-binding/src/main.rs
+++ b/examples/example-clap-binding/src/main.rs
@@ -38,7 +38,8 @@
//! For more information, try '--help'.
//! ```
-use mingling::{macros::dispatcher_clap, prelude::*, setup::BasicProgramSetup, Groupped};
+use mingling::{Groupped, macros::dispatcher_clap, prelude::*, setup::BasicProgramSetup};
+use std::io::Write;
fn main() {
let mut program = ThisProgram::new();
@@ -89,24 +90,29 @@ pub struct EntryGreet {
/// Renders the greet output with optional repetition.
#[renderer]
-fn render_greet(greet: EntryGreet) {
+fn render_greet(greet: EntryGreet) -> RenderResult {
let name = greet.name;
let count = greet.repeat.max(0) as usize;
- r_print!("Hello, ");
+ let mut render_result = RenderResult::default();
+ write!(render_result, "Hello, ").ok();
for i in 0..count {
- r_print!("{name}");
+ write!(render_result, "{name}").ok();
if i < count - 1 {
- r_print!(", ");
+ write!(render_result, ", ").ok();
}
}
- r_println!("!");
+ writeln!(render_result, "!").ok();
+ render_result
}
/// Renders the error message when greet argument parsing fails.
#[renderer]
-fn render_greet_parse_failed(err: ErrorGreetParsed) {
- r_println!("{}", *err);
+// renderers can return a RenderResult instead of using r_println!
+pub fn render_greet_parse_failed(err: ErrorGreetParsed) -> RenderResult {
+ let mut render_result = RenderResult::default();
+ writeln!(render_result, "{}", *err).ok();
+ render_result
}
gen_program!();
diff --git a/examples/example-combine-pathf-dispatch-tree/src/sub/mod.rs b/examples/example-combine-pathf-dispatch-tree/src/sub/mod.rs
index e0b7743..5ab0ece 100644
--- a/examples/example-combine-pathf-dispatch-tree/src/sub/mod.rs
+++ b/examples/example-combine-pathf-dispatch-tree/src/sub/mod.rs
@@ -1,5 +1,6 @@
use crate::Next;
-use mingling::{macros::r_println, prelude::*};
+use mingling::prelude::*;
+use std::io::Write;
dispatcher!("hello");
@@ -17,6 +18,8 @@ pub fn handle_my(args: EntryHello) -> Next {
}
#[renderer]
-pub fn render_my(msg: ResultMessage) {
- r_println!("Hello, {}!", *msg);
+pub fn render_my(msg: ResultMessage) -> RenderResult {
+ let mut render_result = RenderResult::new();
+ writeln!(render_result, "Hello, {}!", *msg).ok();
+ render_result
}
diff --git a/examples/example-completion/src/main.rs b/examples/example-completion/src/main.rs
index 0c64d03..0159807 100644
--- a/examples/example-completion/src/main.rs
+++ b/examples/example-completion/src/main.rs
@@ -45,6 +45,7 @@
//! ```
use mingling::{macros::suggest, prelude::*, ShellContext, Suggest};
+use std::io::Write;
fn main() {
let mut program = ThisProgram::new();
@@ -118,13 +119,15 @@ fn handle_greet(args: EntryGreet) -> Next {
/// Renders the greeting with the result name and repeat count.
#[renderer]
-fn render_name(result: ResultName) {
+fn render_name(result: ResultName) -> RenderResult {
let (repeat, name) = result.inner;
+ let mut render_result = RenderResult::new();
let mut parts = Vec::with_capacity(repeat as usize);
for _ in 0..repeat {
parts.push(name.clone());
}
- r_println!("Hello, {}!", parts.join(", "));
+ writeln!(render_result, "Hello, {}!", parts.join(", ")).ok();
+ render_result
}
gen_program!();
diff --git a/examples/example-custom-pickable/src/main.rs b/examples/example-custom-pickable/src/main.rs
index 015cc62..d203815 100644
--- a/examples/example-custom-pickable/src/main.rs
+++ b/examples/example-custom-pickable/src/main.rs
@@ -15,6 +15,7 @@
//! ```
use mingling::{macros::route, parser::Pickable, prelude::*, Groupped};
+use std::io::Write;
// Define types that can be recognized by Mingling
// ________________________ `Pickable` trait needs to implement Default
@@ -52,14 +53,18 @@ fn handle_connect(prev: EntryConnect) -> Next {
/// Renders the connected address.
#[renderer]
-fn render_address(addr: Address) {
- r_println!("Connected to \"{}\"", addr.to_string());
+pub fn render_address(addr: Address) -> RenderResult {
+ let mut render_result = RenderResult::new();
+ write!(render_result, "Connected to \"{}\"", addr).ok();
+ render_result
}
/// Renders the error message when address parsing fails.
#[renderer]
-fn render_error_parse_address_failed(_: ErrorParseAddressFailed) {
- r_println!("Failed to parse address");
+pub fn render_error_parse_address_failed(_: ErrorParseAddressFailed) -> RenderResult {
+ let mut render_result = RenderResult::new();
+ write!(render_result, "Failed to parse address").ok();
+ render_result
}
gen_program!();
diff --git a/examples/example-dispatch-tree/src/main.rs b/examples/example-dispatch-tree/src/main.rs
index e087b1e..9f76f15 100644
--- a/examples/example-dispatch-tree/src/main.rs
+++ b/examples/example-dispatch-tree/src/main.rs
@@ -21,6 +21,7 @@
//!
use mingling::prelude::*;
+use std::io::Write;
// --------- IMPORTANT ---------
// You have a large number of subcommands
@@ -53,8 +54,10 @@ fn main() {
/// Renders the confirmation message for the `cmd5` command.
#[renderer]
-fn render_cmd5(_: Entry5) {
- r_println!("It's works!");
+fn render_cmd5(_: Entry5) -> RenderResult {
+ let mut render_result = RenderResult::new();
+ writeln!(render_result, "It's works!").ok();
+ render_result
}
gen_program!();
diff --git a/examples/example-enum-tag/src/main.rs b/examples/example-enum-tag/src/main.rs
index ad9db82..01c7767 100644
--- a/examples/example-enum-tag/src/main.rs
+++ b/examples/example-enum-tag/src/main.rs
@@ -19,6 +19,7 @@ use mingling::{
macros::suggest_enum, parser::PickableEnum, prelude::*, EnumTag, Groupped, ShellContext,
Suggest,
};
+use std::io::Write;
// Define the enum and derive the EnumTag trait
// ________ adds metadata to the enum, enabling it to:
@@ -83,10 +84,11 @@ fn handle_language_selection(args: EntryLanguageSelection) -> Next {
/// Renders the selected programming language with its name and description.
#[renderer]
-fn render_programming_language(lang: ProgrammingLanguages) {
- // You can use `enum_info()` to get the name and description of the current enum
+pub fn render_programming_language(lang: ProgrammingLanguages) -> RenderResult {
+ let mut render_result = RenderResult::new();
let (name, desc) = lang.enum_info();
- r_println!("Selected: {} ({})", name, desc)
+ writeln!(render_result, "Selected: {} ({})", name, desc).ok();
+ render_result
}
#[completion(EntryLanguageSelection)]
diff --git a/examples/example-error-handling/src/main.rs b/examples/example-error-handling/src/main.rs
index ae79b97..de9792d 100644
--- a/examples/example-error-handling/src/main.rs
+++ b/examples/example-error-handling/src/main.rs
@@ -21,6 +21,7 @@
//! ```
use mingling::prelude::*;
+use std::io::Write;
// In Mingling, instead of using ? to propagate errors upward,
// errors are treated as branches that continue execution.
@@ -61,36 +62,47 @@ fn handle_hello(args: EntryHello) -> Next {
/// Renders a successful greeting with the given name.
#[renderer]
-fn render_result_name(name: ResultName) {
- r_println!("Hello, {}", *name);
+fn render_result_name(name: ResultName) -> RenderResult {
+ let mut render_result = RenderResult::new();
+ writeln!(render_result, "Hello, {}", *name).ok();
+ render_result
}
/// Renders the error when no name is provided.
#[renderer]
-fn render_error_no_name_provided(_: ErrorNoNameProvided) {
- // Prompt when no name is provided
- r_println!("No name provided");
+fn render_error_no_name_provided(_: ErrorNoNameProvided) -> RenderResult {
+ let mut render_result = RenderResult::new();
+ writeln!(render_result, "No name provided").ok();
+ render_result
}
/// Renders the error when the name is already taken.
#[renderer]
-fn render_error_name_not_available(_: ErrorNameNotAvailable) {
- // Prompt when name is already taken
- r_println!("Name not available");
+fn render_error_name_not_available(_: ErrorNameNotAvailable) -> RenderResult {
+ let mut render_result = RenderResult::new();
+ writeln!(render_result, "Name not available").ok();
+ render_result
}
/// Renders the error when the name exceeds the maximum length.
#[renderer]
-fn render_error_name_too_long(len: ErrorNameTooLong) {
- // Prompt when name is too long, showing actual length
- r_println!("Name too long: {} > 10", *len);
+fn render_error_name_too_long(len: ErrorNameTooLong) -> RenderResult {
+ let mut render_result = RenderResult::new();
+ writeln!(render_result, "Name too long: {} > 10", *len).ok();
+ render_result
}
/// Renders the error when the dispatcher (subcommand) is not found.
#[renderer]
-fn render_dispatcher_not_found(err: ErrorDispatcherNotFound) {
- // Prompt when command is not found, showing the input command
- r_println!("Command not found: \"{}\"", err.inner.join(" "));
+fn render_dispatcher_not_found(err: ErrorDispatcherNotFound) -> RenderResult {
+ let mut render_result = RenderResult::new();
+ writeln!(
+ render_result,
+ "Command not found: \"{}\"",
+ err.inner.join(" ")
+ )
+ .ok();
+ render_result
}
gen_program!();
diff --git a/examples/example-exitcode/src/main.rs b/examples/example-exitcode/src/main.rs
index b0b7467..6b22eae 100644
--- a/examples/example-exitcode/src/main.rs
+++ b/examples/example-exitcode/src/main.rs
@@ -20,6 +20,7 @@ use mingling::{
res::ResExitCode,
setup::{BasicProgramSetup, ExitCodeSetup},
};
+use std::io::Write;
fn main() {
let mut program = ThisProgram::new();
@@ -52,25 +53,32 @@ fn handle_hello(args: EntryHello) -> Next {
/// Renders a successful greeting with the given name.
#[renderer]
-fn render_result_name(name: ResultName) {
- r_println!("Hello, {}", *name);
+fn render_result_name(name: ResultName) -> RenderResult {
+ let mut result = RenderResult::new();
+ writeln!(result, "Hello, {}", *name).ok();
+ result
}
#[help]
-fn help_hello(_p: EntryHello, ec: &mut ResExitCode) {
- r_println!("Usage: hello <NAME>");
+fn help_hello(_p: EntryHello, ec: &mut ResExitCode) -> RenderResult {
+ let mut result = RenderResult::new();
+ writeln!(result, "Usage: hello <NAME>").ok();
ec.exit_code = 2;
+ result
}
// Define renderer, render error message _______________ Inject exit code resource
// /
/// Renders the error when no name is provided |
#[renderer] // vvvvvvvvvvvvvvvv
-fn render_error_no_name_provided(_: ErrorNoNameProvided, ec: &mut ResExitCode) {
+fn render_error_no_name_provided(_: ErrorNoNameProvided, ec: &mut ResExitCode) -> RenderResult {
ec.exit_code = 1;
+ let mut result = RenderResult::new();
+
// Prompt when no name is provided
- r_println!("No name provided (with exit code 1)");
+ writeln!(result, "No name provided (with exit code 1)").ok();
+ result
}
gen_program!();
diff --git a/examples/example-help/src/main.rs b/examples/example-help/src/main.rs
index 9567c49..3282683 100644
--- a/examples/example-help/src/main.rs
+++ b/examples/example-help/src/main.rs
@@ -14,14 +14,17 @@
//! ```
use mingling::{macros::help, prelude::*, setup::BasicProgramSetup};
+use std::io::Write;
dispatcher!("greet", CMDGreet => EntryGreet);
// Define help _________ When `program.user_context.help` is `true`
// / the command will not enter `#[chain]` / `#[renderer]`
#[help] // vvvvvvvvvv but instead enter this `#[help]` function
-fn help_greet(_prev: EntryGreet) {
- r_println!("Usage: greet <NAME>");
+fn help_greet(_prev: EntryGreet) -> RenderResult {
+ let mut render_result = RenderResult::new();
+ writeln!(render_result, "Usage: greet <NAME>").ok();
+ render_result
}
fn main() {
diff --git a/examples/example-hook/src/main.rs b/examples/example-hook/src/main.rs
index d9a8fd1..41928ca 100644
--- a/examples/example-hook/src/main.rs
+++ b/examples/example-hook/src/main.rs
@@ -24,6 +24,7 @@ use mingling::{
hook::{ProgramControlUnit, ProgramHook},
prelude::*,
};
+use std::io::Write;
dispatcher!("greet", CMDGreet => EntryGreet);
@@ -67,9 +68,12 @@ fn handle_greet(args: EntryGreet) -> Next {
}
/// Renders the greeting message with the provided name.
+/// Renders the greeting message with the provided name.
#[renderer]
-fn render_name(name: ResultName) {
- r_println!("Hello, {}!", *name);
+fn render_name(name: ResultName) -> RenderResult {
+ let mut render_result = RenderResult::new();
+ writeln!(render_result, "Hello, {}!", *name).ok();
+ render_result
}
gen_program!();
diff --git a/examples/example-lazy-resources/src/main.rs b/examples/example-lazy-resources/src/main.rs
index 3533ae2..aaafb98 100644
--- a/examples/example-lazy-resources/src/main.rs
+++ b/examples/example-lazy-resources/src/main.rs
@@ -22,6 +22,7 @@
//! ```
use std::collections::BTreeMap;
+use std::io::Write;
use mingling::{LazyInit, LazyRes, prelude::*};
@@ -73,20 +74,25 @@ fn main() {
// | _____________________ Use LazyRes<ResLargeData>
// | / instead of ResLargeData
#[renderer] // vvvv vvvvvvvvvvvvvvvvvvvvv
-fn render_entry_show(_args: EntryShow, res: &mut LazyRes<ResLargeData>) {
+fn render_entry_show(_args: EntryShow, res: &mut LazyRes<ResLargeData>) -> RenderResult {
+ let mut render_result = RenderResult::new();
+
// _______ Initialization happens here
// /
// vvvvvvv
let res = res.get_ref();
for (key, value) in &res.data {
- r_println!("{}: {}", key, value);
+ writeln!(render_result, "{}: {}", key, value).ok();
}
+ render_result
}
// When not using LazyRes<ResLargeData>, it will not be initialized
#[renderer]
-fn render_entry_none(_args: EntryNone) {
- r_println!("None");
+fn render_entry_none(_args: EntryNone) -> RenderResult {
+ let mut render_result = RenderResult::new();
+ writeln!(render_result, "None").ok();
+ render_result
}
gen_program!();
diff --git a/examples/example-outside-type/src/main.rs b/examples/example-outside-type/src/main.rs
index 7cf4d40..925878a 100644
--- a/examples/example-outside-type/src/main.rs
+++ b/examples/example-outside-type/src/main.rs
@@ -19,6 +19,7 @@
//! ```
use mingling::{macros::group, prelude::*};
+use std::io::Write;
use std::{io::ErrorKind::Other, num::ParseIntError};
dispatcher!("parse");
@@ -61,8 +62,10 @@ fn parse_number(args: EntryParse) -> Next {
// _____________ Using std::num::ParseIntError as a chain input
// /
#[renderer] // vvvvvvvvvvvv
-fn render_number(num: ParsedNumber) {
- r_println!("Parsed number: {}", *num);
+fn render_number(num: ParsedNumber) -> RenderResult {
+ let mut render_result = RenderResult::new();
+ write!(render_result, "Parsed number: {}", *num).ok();
+ render_result
}
/// Renderer for parse errors — using the outside `ParseIntError` type.
@@ -70,16 +73,20 @@ fn render_number(num: ParsedNumber) {
/// The `ParseIntError` type is registered via `group!` above, so it implements
/// `Groupped<ThisProgram>` and can be used directly in a `#[renderer]` function.
#[renderer]
-fn render_parse_error(err: ParseIntError) {
- r_println!("Parse error: {}", err);
+fn render_parse_error(err: ParseIntError) -> RenderResult {
+ let mut render_result = RenderResult::new();
+ write!(render_result, "Parse error: {}", err).ok();
+ render_result
}
/// Renderer for IO errors — using `std::io::Error` registered as `ErrorIo`.
// ________ Must use alias `ErrorIo` here, not bare `std::io::Error`
// /
#[renderer] // vvvvvvv
-fn render_error_io(err: ErrorIo) {
- r_println!("IO_ERROR: {}", err.to_string());
+fn render_error_io(err: ErrorIo) -> RenderResult {
+ let mut render_result = RenderResult::new();
+ write!(render_result, "IO_ERROR: {}", err).ok();
+ render_result
}
fn main() {
diff --git a/examples/example-pack-err/src/main.rs b/examples/example-pack-err/src/main.rs
index 8716333..5bf5066 100644
--- a/examples/example-pack-err/src/main.rs
+++ b/examples/example-pack-err/src/main.rs
@@ -28,6 +28,7 @@
use mingling::prelude::*;
use mingling::setup::StructuralRendererSetup;
+use std::io::Write;
use std::path::PathBuf;
dispatcher!("find", CMDFind => EntryFind);
@@ -100,32 +101,42 @@ fn handle_find_structural(args: EntryFindStructural) -> Next {
/// Renders the successful result with the found directory path.
#[renderer]
-fn render_result_path(path: ResultPath) {
- r_println!("Found directory: {}", path.display());
+fn render_result_path(path: ResultPath) -> RenderResult {
+ let mut render_result = RenderResult::new();
+ writeln!(render_result, "Found directory: {}", path.display()).ok();
+ render_result
}
/// Renders the error when no search path is provided.
#[renderer]
-fn render_error_not_found(_: ErrorNotFound) {
- r_println!("Search path not provided");
+fn render_error_not_found(_: ErrorNotFound) -> RenderResult {
+ let mut render_result = RenderResult::new();
+ writeln!(render_result, "Search path not provided").ok();
+ render_result
}
/// Renders the error when the given path is not a directory.
#[renderer]
-fn render_error_not_dir(err: ErrorNotDir) {
- r_println!("Not a directory: {}", err.info.display());
+fn render_error_not_dir(err: ErrorNotDir) -> RenderResult {
+ let mut render_result = RenderResult::new();
+ writeln!(render_result, "Not a directory: {}", err.info.display()).ok();
+ render_result
}
/// Renders the structural error when no search path is provided.
#[renderer]
-fn render_error_not_found_structural(_: ErrorNotFoundStructural) {
- r_println!("Search path not provided");
+fn render_error_not_found_structural(_: ErrorNotFoundStructural) -> RenderResult {
+ let mut render_result = RenderResult::new();
+ writeln!(render_result, "Search path not provided").ok();
+ render_result
}
/// Renders the structural error when the given path is not a directory.
#[renderer]
-fn render_error_not_dir_structural(err: ErrorNotDirStructural) {
- r_println!("Not a directory: {}", err.info.display());
+fn render_error_not_dir_structural(err: ErrorNotDirStructural) -> RenderResult {
+ let mut render_result = RenderResult::new();
+ writeln!(render_result, "Not a directory: {}", err.info.display()).ok();
+ render_result
}
gen_program!();
diff --git a/examples/example-panic-unwind/src/main.rs b/examples/example-panic-unwind/src/main.rs
index ed032c5..a829158 100644
--- a/examples/example-panic-unwind/src/main.rs
+++ b/examples/example-panic-unwind/src/main.rs
@@ -16,6 +16,7 @@
//! ```
use mingling::{hook::ProgramHook, prelude::*};
+use std::io::Write;
dispatcher!("panic", CMDPanic => EntryPanic);
pack!(NotPanic = ());
@@ -51,9 +52,12 @@ fn handle_panic(prev: EntryPanic) -> Next {
}
/// Renders the message when no panic occurs.
+/// Renders the message when no panic occurs.
#[renderer]
-fn render(_: NotPanic) {
- r_println!("Program not panic");
+pub fn render(_: NotPanic) -> RenderResult {
+ let mut render_result = RenderResult::new();
+ writeln!(render_result, "Program not panic").ok();
+ render_result
}
gen_program!();
diff --git a/examples/example-pathfinder/src/sub/mod.rs b/examples/example-pathfinder/src/sub/mod.rs
index ef10a75..6d15930 100644
--- a/examples/example-pathfinder/src/sub/mod.rs
+++ b/examples/example-pathfinder/src/sub/mod.rs
@@ -1,5 +1,6 @@
-use mingling::prelude::*;
use crate::Next;
+use mingling::prelude::*;
+use std::io::Write;
dispatcher!("greet", CMDGreet => EntryGreet);
pack!(ResultName = String);
@@ -15,7 +16,11 @@ pub fn handle_greet(args: EntryGreet) -> Next {
name
}
+/// Renders the name.
#[renderer]
-pub fn render_name(name: ResultName) {
- r_println!("Hello, {}!", *name);
+// But renderers cannot use the `async` keyword
+pub fn render_name(name: ResultName) -> RenderResult {
+ let mut render_result = RenderResult::new();
+ writeln!(render_result, "Hello, {}!", *name).ok();
+ render_result
}
diff --git a/examples/example-repl-basic/src/main.rs b/examples/example-repl-basic/src/main.rs
index 8df8c22..d15319e 100644
--- a/examples/example-repl-basic/src/main.rs
+++ b/examples/example-repl-basic/src/main.rs
@@ -14,6 +14,7 @@ use mingling::{
setup::{BasicREPLOutputSetup, BasicREPLPromptSetup, BasicREPLReadlineSetup},
this,
};
+use std::io::Write;
use std::{env::current_dir, path::PathBuf};
// Resource to store the current directory
@@ -136,10 +137,12 @@ fn handle_ls(_prev: EntryLs, current_dir: &ResCurrentDir) -> Next {
/// Render ResultList data
#[renderer]
-fn render_list(list: ResultList) {
+fn render_list(list: ResultList) -> RenderResult {
+ let mut render_result = RenderResult::new();
for item in list.inner {
- r_println!("{}", item);
+ writeln!(render_result, "{}", item).ok();
}
+ render_result
}
// Handle exit command event
@@ -161,15 +164,24 @@ fn handle_clear(_prev: EntryClear) {
/// Handle path not found event
#[renderer]
-fn render_error_directory_not_exist(err: ErrorDirectoryNotExist) {
- r_println!("Directory not found: {}", err.inner.display())
+fn render_error_directory_not_exist(err: ErrorDirectoryNotExist) -> RenderResult {
+ let mut render_result = RenderResult::new();
+ writeln!(
+ render_result,
+ "Directory not found: {}",
+ err.inner.display()
+ )
+ .ok();
+ render_result
}
/// Handle dispatcher not found event
/// Renders the error when a command is not found.
#[renderer]
-fn dispatcher_not_found(prev: ErrorDispatcherNotFound) {
- r_println!("Command not found: \"{}\"", prev.join(", "))
+fn dispatcher_not_found(prev: ErrorDispatcherNotFound) -> RenderResult {
+ let mut render_result = RenderResult::new();
+ writeln!(render_result, "Command not found: \"{}\"", prev.join(", ")).ok();
+ render_result
}
gen_program!();
diff --git a/examples/example-resources/src/main.rs b/examples/example-resources/src/main.rs
index 6c5bf84..b08ee26 100644
--- a/examples/example-resources/src/main.rs
+++ b/examples/example-resources/src/main.rs
@@ -14,9 +14,9 @@
//! Current directory: /home/alice/mingling/src
//! ```
-use std::path::PathBuf;
-
use mingling::prelude::*;
+use std::io::Write;
+use std::path::PathBuf;
// Create resource
// ______________ Resource needs to
@@ -58,8 +58,15 @@ fn render_modify_current(args: EntryModifyCurrent, current_dir: &mut ResCurrentD
// /
/// Renders the current directory path. |
#[renderer] // vvvvvvvvvvvvvv
-fn render_current(_: EntryCurrent, current_dir: &ResCurrentDir) {
- r_println!("Current directory: {}", current_dir.current_dir.display());
+fn render_current(_: EntryCurrent, current_dir: &ResCurrentDir) -> RenderResult {
+ let mut render_result = RenderResult::new();
+ write!(
+ render_result,
+ "Current directory: {}",
+ current_dir.current_dir.display()
+ )
+ .ok();
+ render_result
}
gen_program!();
diff --git a/examples/example-structural-renderer/src/main.rs b/examples/example-structural-renderer/src/main.rs
index 21077e7..13c4c84 100644
--- a/examples/example-structural-renderer/src/main.rs
+++ b/examples/example-structural-renderer/src/main.rs
@@ -18,8 +18,9 @@
//! ```
use mingling::prelude::*;
-use mingling::{parser::Picker, setup::StructuralRendererSetup, StructuralData, Groupped};
+use mingling::{Groupped, StructuralData, parser::Picker, setup::StructuralRendererSetup};
use serde::Serialize;
+use std::io::Write;
dispatcher!("render", CMDRender => EntryRender);
@@ -64,8 +65,10 @@ fn parse_render(prev: EntryRender) -> Next {
/// Implement default renderer for when structural_renderer is not specified
#[renderer]
-fn render_info(prev: Info) {
- r_println!("{} is {} years old", prev.name, prev.age);
+fn render_info(prev: Info) -> RenderResult {
+ let mut render_result = RenderResult::new();
+ writeln!(render_result, "{} is {} years old", prev.name, prev.age).ok();
+ render_result
}
gen_program!();
diff --git a/examples/example-unit-test/src/main.rs b/examples/example-unit-test/src/main.rs
index b89c629..b85ff01 100644
--- a/examples/example-unit-test/src/main.rs
+++ b/examples/example-unit-test/src/main.rs
@@ -7,6 +7,7 @@
//! ```
use mingling::prelude::*;
+use std::io::Write;
#[cfg(test)]
mod tests {
@@ -41,25 +42,25 @@ mod tests {
#[test]
fn test_render_result_name() {
let r = render_result_name(ResultName::new("Peter".into()));
- assert_eq!(r, "Hello, Peter!\n")
+ assert_eq!(r.to_string().as_str(), "Hello, Peter!\n")
}
#[test]
fn test_render_error_no_name_provided() {
let r = render_error_no_name_provided(ErrorNoNameProvided::default());
- assert_eq!(r, "No name provided\n")
+ assert_eq!(r.to_string().as_str(), "No name provided\n")
}
#[test]
fn test_render_error_name_not_available() {
let r = render_error_name_not_available(ErrorNameNotAvailable::default());
- assert_eq!(r, "Name not available\n")
+ assert_eq!(r.to_string().as_str(), "Name not available\n")
}
#[test]
fn test_render_error_name_too_long() {
let r = render_error_name_too_long(ErrorNameTooLong::new(17));
- assert_eq!(r, "Name too long: 17 > 10\n")
+ assert_eq!(r.to_string().as_str(), "Name too long: 17 > 10\n")
}
// --------- IMPORTANT ---------
}
@@ -93,32 +94,47 @@ fn handle_hello(args: EntryHello) -> Next {
/// Renders a successful greeting with the given name.
#[renderer]
-fn render_result_name(name: ResultName) -> String {
- r_println!("Hello, {}!", *name);
+fn render_result_name(name: ResultName) -> RenderResult {
+ let mut render_result = RenderResult::new();
+ writeln!(render_result, "Hello, {}!", *name).ok();
+ render_result
}
/// Renders the error when no name is provided.
#[renderer]
-fn render_error_no_name_provided(_: ErrorNoNameProvided) -> String {
- r_println!("No name provided");
+fn render_error_no_name_provided(_: ErrorNoNameProvided) -> RenderResult {
+ let mut render_result = RenderResult::new();
+ writeln!(render_result, "No name provided").ok();
+ render_result
}
/// Renders the error when the name is already taken.
#[renderer]
-fn render_error_name_not_available(_: ErrorNameNotAvailable) -> String {
- r_println!("Name not available");
+fn render_error_name_not_available(_: ErrorNameNotAvailable) -> RenderResult {
+ let mut render_result = RenderResult::new();
+ writeln!(render_result, "Name not available").ok();
+ render_result
}
/// Renders the error when the name exceeds the maximum length.
#[renderer]
-fn render_error_name_too_long(len: ErrorNameTooLong) -> String {
- r_println!("Name too long: {} > 10", *len);
+fn render_error_name_too_long(len: ErrorNameTooLong) -> RenderResult {
+ let mut render_result = RenderResult::new();
+ writeln!(render_result, "Name too long: {} > 10", *len).ok();
+ render_result
}
/// Renders the error when the dispatcher (subcommand) is not found.
#[renderer]
-fn render_dispatcher_not_found(err: ErrorDispatcherNotFound) {
- r_println!("Command not found: \"{}\"", err.inner.join(" "));
+fn render_dispatcher_not_found(err: ErrorDispatcherNotFound) -> RenderResult {
+ let mut render_result = RenderResult::new();
+ writeln!(
+ render_result,
+ "Command not found: \"{}\"",
+ err.inner.join(" ")
+ )
+ .ok();
+ render_result
}
gen_program!();
diff --git a/examples/full-todolist/src/help.rs b/examples/full-todolist/src/help.rs
index ab33176..2f8228a 100644
--- a/examples/full-todolist/src/help.rs
+++ b/examples/full-todolist/src/help.rs
@@ -1,15 +1,16 @@
//! This module provides help information for the `todolist` command line program
-use mingling::macros::{help, r_println};
-
use crate::{EntryAdd, EntryClean, EntryComplete, EntryList, ErrorDispatcherNotFound};
+use mingling::{RenderResult, macros::help};
+use std::io::Write;
+/// Shows the global help message.
#[help]
-pub fn help_global(_p: ErrorDispatcherNotFound) {
- r_println!(
- "{}",
- r"
-Usage: todolist [command] [args]
+pub fn help_global(_p: ErrorDispatcherNotFound) -> RenderResult {
+ let mut render_result = RenderResult::new();
+ writeln!(
+ render_result,
+ r"Usage: todolist [command] [args]
Commands:
add -- Add a new task
@@ -20,74 +21,78 @@ Commands:
Args:
-h, --help -- Show this help message
-V, --version -- Show the version
- -A, --all -- All tasks (Clean all / List all)
- "
- .trim()
- );
+ -A, --all -- All tasks (Clean all / List all)"
+ )
+ .ok();
+ render_result
}
+/// Shows help for the `add` command.
#[help]
-pub fn help_add(_p: EntryAdd) {
- r_println!(
- "{}",
- r"
-Usage: todolist add [task description]
+pub fn help_add(_p: EntryAdd) -> RenderResult {
+ let mut render_result = RenderResult::new();
+ writeln!(
+ render_result,
+ r"Usage: todolist add [task description]
Add a new task to the todo list.
Example:
todolist add 'Buy groceries'
- todolist add 'Finish Rust project'
- "
- .trim()
- );
+ todolist add 'Finish Rust project'"
+ )
+ .ok();
+ render_result
}
+/// Shows help for the `list` command.
#[help]
-pub fn help_list(_p: EntryList) {
- r_println!(
- "{}",
- r"
-Usage: todolist list
+pub fn help_list(_p: EntryList) -> RenderResult {
+ let mut render_result = RenderResult::new();
+ writeln!(
+ render_result,
+ r"Usage: todolist list
List all tasks.
Example:
- todolist list
- "
- .trim()
- );
+ todolist list"
+ )
+ .ok();
+ render_result
}
+/// Shows help for the `complete` command.
#[help]
-pub fn help_complete(_p: EntryComplete) {
- r_println!(
- "{}",
- r"
-Usage: todolist complete [task_id]
+pub fn help_complete(_p: EntryComplete) -> RenderResult {
+ let mut render_result = RenderResult::new();
+ writeln!(
+ render_result,
+ r"Usage: todolist complete [task_id]
Mark a task as complete by its ID.
Example:
todolist complete 1
- todolist complete 3
- "
- .trim()
- );
+ todolist complete 3"
+ )
+ .ok();
+ render_result
}
+/// Shows help for the `clean` command.
#[help]
-pub fn help_clean(_p: EntryClean) {
- r_println!(
- "{}",
- r"
-Usage: todolist clean
+pub fn help_clean(_p: EntryClean) -> RenderResult {
+ let mut render_result = RenderResult::new();
+ writeln!(
+ render_result,
+ r"Usage: todolist clean
Remove all completed tasks from the list.
Example:
- todolist clean
- "
- .trim()
- );
+ todolist clean"
+ )
+ .ok();
+ render_result
}
diff --git a/examples/full-todolist/src/main.rs b/examples/full-todolist/src/main.rs
index e4c5aa6..0748832 100644
--- a/examples/full-todolist/src/main.rs
+++ b/examples/full-todolist/src/main.rs
@@ -7,12 +7,13 @@
//! > This is truly a cliché example, as common as `Hello World`!
use mingling::{
+ LazyInit, LazyRes,
macros::route,
prelude::*,
res::ResExitCode,
- setup::{ExitCodeSetup, StructuralRendererSetup, HelpFlagSetup},
- LazyInit, LazyRes,
+ setup::{ExitCodeSetup, HelpFlagSetup, StructuralRendererSetup},
};
+use std::io::Write;
mod help;
pub use help::*;
@@ -160,38 +161,47 @@ fn handle_clean(
}
}
+/// Renders error when no task description is provided.
#[renderer]
-fn render_error_no_task_description_provided(
+pub fn render_error_no_task_description_provided(
_err: ErrorNoTaskDescriptionProvided,
// ExitCode
ec: &mut ResExitCode,
-) {
- r_println!("No task description provided!");
- r_println!("");
- r_println!("Use `todolist add <desc>` to add a task");
+) -> RenderResult {
+ let mut render_result = RenderResult::new();
+ writeln!(render_result, "No task description provided!").ok();
+ writeln!(render_result).ok();
+ writeln!(render_result, "Use `todolist add <desc>` to add a task").ok();
ec.exit_code = 1;
+ render_result
}
+/// Renders error when no index is provided.
#[renderer]
-fn render_error_no_index_provided(
+pub fn render_error_no_index_provided(
_err: ErrorNoIndexProvided,
// ExitCode
ec: &mut ResExitCode,
-) {
- r_println!("No index provided!");
- r_println!("");
- r_println!("Use `todolist list` to query indexes");
+) -> RenderResult {
+ let mut render_result = RenderResult::new();
+ writeln!(render_result, "No index provided!").ok();
+ writeln!(render_result).ok();
+ writeln!(render_result, "Use `todolist list` to query indexes").ok();
ec.exit_code = 2;
+ render_result
}
+/// Renders error when index is out of bounds.
#[renderer]
-fn render_error_index_out_of_bounds(
+pub fn render_error_index_out_of_bounds(
_err: ErrorIndexOutOfBounds,
// ExitCode
ec: &mut ResExitCode,
-) {
- r_println!("Index out of bounds!");
+) -> RenderResult {
+ let mut render_result = RenderResult::new();
+ writeln!(render_result, "Index out of bounds!").ok();
ec.exit_code = 3;
+ render_result
}
gen_program!();
diff --git a/examples/full-todolist/src/todolist.rs b/examples/full-todolist/src/todolist.rs
index e447f5d..71338c3 100644
--- a/examples/full-todolist/src/todolist.rs
+++ b/examples/full-todolist/src/todolist.rs
@@ -1,10 +1,8 @@
//! Data structures, read and write logic for the todo list
-use mingling::{
- macros::{r_println, renderer},
- Groupped,
-};
+use mingling::{Groupped, RenderResult, macros::renderer};
use serde::{Deserialize, Serialize};
+use std::io::Write;
use std::{env::current_dir, path::PathBuf};
use crate::ResProgramFlags;
@@ -37,22 +35,30 @@ pub fn read_todo_list() -> ResTodoList {
serde_json::from_reader(reader).unwrap_or_default()
}
+/// Renders the todo list.
#[renderer]
-pub fn render_res_todo_list(todo_list: ResTodoList, program_flags: &ResProgramFlags) {
+pub fn render_res_todo_list(
+ todo_list: ResTodoList,
+ program_flags: &ResProgramFlags,
+) -> RenderResult {
+ let mut render_result = RenderResult::new();
let mut idx = 0;
- r_println!("TODO: ");
+ writeln!(render_result, "TODO: ").ok();
for item in &todo_list.items {
if item.completed && !program_flags.all {
idx += 1;
continue;
}
- r_println!(
+ writeln!(
+ render_result,
" {idx}. [{}] - \"{}\"",
if item.completed { "x" } else { " " },
item.item
- );
+ )
+ .ok();
idx += 1;
}
+ render_result
}
pub fn write_todo_list(todo_list: ResTodoList) {