aboutsummaryrefslogtreecommitdiff
path: root/CHANGELOG.md
diff options
context:
space:
mode:
Diffstat (limited to 'CHANGELOG.md')
-rw-r--r--CHANGELOG.md155
1 files changed, 154 insertions, 1 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ac00643..997eac0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -58,7 +58,13 @@ None
#### Optimizations:
-None
+1. **[`macros`]** Updated `route!` macro to use `Routable` trait instead of `Grouped` trait for error conversion, making the semantics clearer. The `route!` macro now calls `::mingling::Routable::to_chain(e)` on the error branch instead of `::mingling::Grouped::to_chain(e)`.
+
+ Additionally, `ChainProcess<ThisProgram>` now implements `Routable<ThisProgram>`, allowing `route!` to work with `Result<Ok, ChainProcess<ThisProgram>>` patterns — where the error side is already a `ChainProcess` value that should be routed directly:
+
+ When `ChainProcess` implements `Routable`, `to_chain()` re-routes the inner `AnyOutput` to the chain pipeline (preserving the existing `NextProcess::Chain`/`Renderer` flag), while `to_render()` re-routes it to the render pipeline. This enables seamless propagation of already-routed chain process values through the `route!` macro without double-wrapping.
+
+ The `Routable` trait is defined in `mingling_core::asset::routable` and provides unified routing capabilities (`to_chain` / `to_render`) for any type that can be dispatched into the program's pipeline. A blanket implementation is provided for all `T: Grouped<C> + Send`, ensuring backward compatibility — existing types that implement `Grouped` automatically implement `Routable`.
#### Features:
@@ -108,6 +114,109 @@ None
_No migration is required for existing `parser` users — the old API continues to work unchanged._
+4. **[`core`]** Added multiple `From` implementations for `RenderResult`:
+
+ - **From `()`** — Allows constructing an empty `RenderResult` from a unit value, enabling ergonomic returns like `fn my_renderer() -> RenderResult { }` (via `}` → `}` with implicit `()` return).
+ - **From integer types** (`i32`, `i16`, `i8`, `u32`, `u16`, `u8`, `usize`) — Allows constructing a `RenderResult` with a specific exit code and empty text, enabling `fn my_renderer() -> RenderResult { 0 }` or `42.into()`.
+ - **From `String`**, **`&String`**, and **`&str`** — Allows constructing a `RenderResult` with the given text and exit code `0`, enabling `fn my_renderer() -> RenderResult { "Hello".into() }` or passing a `String` directly.
+
+ These implementations make `RenderResult` more flexible as a return type, allowing renderer functions to return simple values without manually constructing a `RenderResult` via `new()` and `write!`/`writeln!`.
+
+5. **[`macros:renderer`]** Removed the restriction that `#[renderer]` functions must return `RenderResult`. The `#[renderer]` macro now accepts any return type (including no return type), and automatically converts the return value to `RenderResult` via `Into::into`.
+
+ - Functions returning `RenderResult` work as before.
+ - Functions returning other types (e.g., `String`, `i32`, `()`) are converted via the `Into<RenderResult>` trait.
+ - Functions with no return type (`-> ()` or omitted) return `()` which is converted to an empty `RenderResult` via `From<()>`.
+
+ This makes `#[renderer]` more flexible and consistent with the ergonomic `From` implementations added in item 4 above.
+
+ ```rust
+ #[renderer]
+ fn render_greeting(prev: ResultGreeting) -> String {
+ format!("Hello, {}!", *prev)
+ }
+
+ #[renderer]
+ fn render_exit_code(prev: ResultExit) -> i32 {
+ 42
+ }
+
+ #[renderer]
+ fn render_void(prev: ResultVoid) {
+ // side effects only, returns empty RenderResult
+ }
+ ```
+
+6. **[`macros:help`]** Removed the restriction that `#[help]` functions must return `::mingling::RenderResult`. The `#[help]` macro now accepts any return type (including no return type), and automatically converts the return value to `RenderResult` via `Into::into`.
+
+ - Functions returning `RenderResult` work as before.
+ - Functions returning other types (e.g., `String`, `i32`, `()`) are converted via `Into<RenderResult>`.
+ - Functions with no return type (`-> ()` or omitted) return `()` which is converted to an empty `RenderResult` via `From<()>`.
+
+ This makes `#[help]` consistent with the `#[renderer]` macro's ergonomic return type handling introduced in item 5 above.
+
+ ```rust
+ #[help]
+ fn help_greeting(prev: EntryGreeting) -> String {
+ format!("Displaying help for greeting: {}", *prev)
+ }
+
+ #[help]
+ fn help_void(prev: EntryVoid) {
+ // side effects only, returns empty RenderResult
+ }
+ ```
+
+7. **[`setups`]** Refactored `BasicProgramSetup`, `HelpFlagSetup`, `QuietFlagSetup`, `ConfirmFlagSetup`, `StructuralRendererSetup`, and `StructuralRendererSimpleSetup` into the `picker` subsystem under `mingling::setups::picker`. These setups now use the `arg_picker` (`picker`) chained argument parsing API internally instead of directly manipulating global arguments.
+
+ - The `BasicProgramSetup`, `HelpFlagSetup`, `QuietFlagSetup`, and `ConfirmFlagSetup` structs now use `PickerArg<Flag>` and chained `.pick()` calls to detect flags from the argument list, replacing the previous `global_argument`-based approach.
+ - The `StructuralRendererSetup` struct now uses `PickerArg<Flag>` constants (e.g., `JSON_FLAG`, `YAML_FLAG`) and chained `.pick()` calls to detect format-specifying flags, replacing the previous `global_argument` approach.
+ - The `StructuralRendererSimpleSetup` struct still uses the legacy `global_argument("--renderer", ...)` approach, preserving backward compatibility with the `--renderer <FORMAT>` syntax.
+ - New `PickerArg<Flag>` constants have been added in `mingling::setups::picker::consts`: `HELP_FLAG`, `QUIET_FLAG`, `CONFIRM_FLAG`, `JSON_FLAG`, `JSON_PRETTY_FLAG`, `YAML_FLAG`, `TOML_FLAG`, `RON_FLAG`, and `RON_PRETTY_FLAG`. The format-specific flags are feature-gated behind their respective `json_serde_fmt`, `yaml_serde_fmt`, `toml_serde_fmt`, and `ron_serde_fmt` features.
+ - The module structure is:
+ - `mingling::setups::picker` — re-exports all picker-based setup types
+ - `mingling::setups::picker::basic` — `BasicProgramSetup`, `HelpFlagSetup`, `QuietFlagSetup`, `ConfirmFlagSetup`
+ - `mingling::setups::picker::consts` — reusable `PickerArg<Flag>` constants
+ - `mingling::setups::picker::structural_renderer` — `StructuralRendererSetup`, `StructuralRendererSimpleSetup`
+ - All setup types remain available from `mingling::setups::*` as before — this is purely an internal refactoring; no public API surface changes.
+
+ The `picker` feature must be enabled for these refactored setups to be available. When the feature is disabled, the original implementations (using `global_argument`) remain in effect.
+
+8. **[`core`]** Added `get_args_mut()`, `take_args()`, and `replace_args()` methods to `Program` for more flexible argument manipulation:
+
+ - **`get_args_mut(&mut self) -> &mut [String]`** — Returns a mutable reference to the program's command-line arguments, allowing in-place modification of individual arguments.
+ - **`take_args(&mut self) -> Vec<String>`** — Takes ownership of the program's command-line arguments, replacing them with an empty `Vec`. Useful for transferring arguments to another context or processing them with ownership.
+ - **`replace_args(&mut self, args: Vec<String>) -> Vec<String>`** — Replaces the program's command-line arguments with a new set and returns the old ones. Enables swapping argument sets during program execution.
+
+ These methods complement the existing read-only `get_args(&self)` method, providing full control over argument mutation and ownership.
+
+9. **[`macros:chain`]** Relaxed the `#[chain]` return type validation. Previously, `#[chain]` functions were restricted to returning `Next`, `ChainProcess<ThisProgram>`, `()`, or omitting the return type. Now, any return type is accepted, and the generated `proc` function performs an explicit `Into<ChainProcess<ThisProgram>>` conversion using a fully-qualified turbofish based on the user-declared return type.
+
+ This means `#[chain]` functions can now return any pack type directly, without needing an explicit `.into()` call in the function body:
+
+ ```rust
+ // Before — required explicit .into()
+ #[chain]
+ fn handle_greet(args: EntryGreet) -> Next {
+ let name = /* ... */;
+ ResultGreeting::new(name).into()
+ }
+
+ // After — return any pack type directly
+ #[chain]
+ fn handle_greet(args: EntryGreet) -> ResultGreeting {
+ let name = /* ... */;
+ ResultGreeting::new(name)
+ }
+ ```
+
+ The generated `proc` function now wraps the body result in `<UserReturnType as Into<ChainProcess<ThisProgram>>>::into(...)`, which:
+ - Works for `Next` / `ChainProcess` via the identity `From<T> for T` implementation.
+ - Works for any pack type (`ResultGreeting`, etc.) via the `.into()` conversion generated by `pack!` / `#[derive(Grouped)]`.
+ - Works for `()` via the `From<()>` implementation on `ChainProcess`.
+
+ The return type validation has been removed entirely — any valid Rust return type is accepted. If the type does not implement `Into<ChainProcess<ThisProgram>>`, a standard Rust compilation error will be produced at the call site.
+
#### **BREAKING CHANGES** (API CHANGES):
1. **[`macros:renderer`]** **[`macros:help`]** Removed `r_println!` and `r_print!` macros. The `#[renderer]` and `#[help]` macros no longer implicitly inject an internal `RenderResult` variable or provide `r_println!` / `r_print!` macros.
@@ -127,6 +236,50 @@ None
All examples, docs, and test cases across the repository have been updated to use the new pattern: creating a `RenderResult` with `RenderResult::new()` or `RenderResult::default()`, writing with `write!`/`writeln!` from `std::io::Write`, and returning the result.
+2. **[`macros:chain`]** The `#[chain]` macro's return type requirement has been relaxed. Previously, chain functions were required to return `Next` or `()` (with `()` auto-converting to `ResultEmpty`). Now, chain functions can also return `ChainProcess<ThisProgram>` directly, or omit the return type entirely (which defaults to `()` → `ResultEmpty`).
+
+ The return value of chain functions is now wrapped in an explicit `.into()` call inside the generated `proc` function, ensuring consistent conversion to `ChainProcess<ProgramType>`. As a result, **all downstream code that previously relied on implicit conversion from packed types to `Next`/`ChainProcess` must now call `.into()` explicitly**.
+
+ ```rust
+ // Before — implicit conversion worked because the generated proc
+ // function was `fn proc(...) -> impl Into<ChainProcess<...>>`
+ #[chain]
+ fn handle_greet(args: EntryGreet) -> Next {
+ let name = /* ... */;
+ ResultGreeting::new(name) // implicitly converted
+ }
+
+ // After — the generated proc function is `fn proc(...) -> ChainProcess<...>`,
+ // so the body must produce ChainProcess explicitly
+ #[chain]
+ fn handle_greet(args: EntryGreet) -> Next {
+ let name = /* ... */;
+ ResultGreeting::new(name).into() // explicit conversion required
+ }
+ ```
+
+ The key advantage of this design is that **the original function body and the expanded `proc` function body are now identical** — the macro only adjusts the function signature and inserts an outermost `.into()` wrapper, without rewriting the internal return expressions. This means the semantics of the original code are perfectly preserved: there is no invisible type coercion happening mid-body, and the behavior you write in the source is exactly what executes at runtime. If a bug arises, the expanded code mirrors the source almost one-to-one, making debugging straightforward.
+
+ This change also applies to:
+ - Chain functions returning `()` (unit), where the body's final expression with `.into()` is replaced by an explicit `ResultEmpty::to_chain()` call.
+ - Chain functions using `&mut` resource injection with non-unit returns: the inner closure now calls `__modify_res_and_return_route` (which returns `ChainProcess<C>` directly) instead of relying on `.into()` conversion.
+ - The `__modify_res_and_return_route` method signature changed from accepting `impl Into<ChainProcess<C>>` to returning `ChainProcess<C>` directly.
+
+ All examples, docs, and test cases across the repository have been updated to use `.into()` where packed types are returned from chain functions.
+
+3. **[`core`]** **[`ExitCodeSetup`]** Updated `ExitCodeSetup` to only override the exit code when `ResExitCode` has been modified (i.e., `exit_code != 0`). Previously, it unconditionally overrode the exit code, which could interfere with exit codes set by other hooks or the program's default exit flow. The `on_finish` hook now returns `ProgramControlUnit::OverrideExitCode(...)` only when the exit code is non-zero, and `ProgramControls::Empty` otherwise. The import of `ProgramControls` has been added accordingly.
+
+4. **[`core`]** **[`macros`]** Renamed `Groupped` (typo) to `Grouped`. All references to the trait, derive macro, module files, and related types have been corrected throughout the codebase:
+
+ - Trait: `Groupped<Group>` → `Grouped<Group>`
+ - Derive macro: `#[derive(Groupped)]` → `#[derive(Grouped)]`
+ - Serialize variant: `GrouppedSerialize` → `GroupedSerialize`
+ - Source files: `groupped.rs` → `grouped.rs`
+ - Pattern matcher: `GrouppedDerivePattern` → `GroupedDerivePattern`
+ - All `use` imports, type annotations, and trait bound references updated accordingly.
+
+ This is a pure rename — no behavioral changes. All functionality remains identical. Downstream code using the old `Groupped` name must migrate to `Grouped`.
+
---
## Release 0.2.2 (2026-07-10)