Skip to content

v1.2.0

Choose a tag to compare

@codad5 codad5 released this 27 Oct 00:03
· 6 commits to master since this release

[1.2.0] - 2025-10-26

⚠️ BREAKING CHANGES

  1. ValueTypes::None has been REMOVED

    • Reason: Critical design flaw - impossible to distinguish between "flag defined" and "flag passed"
    • Migration: Replace all ValueTypes::None with ValueTypes::OptionalSingle(Some(Value::Bool(false)))
    • How to check if flag was passed:
      • When flag is not passed: value remains Bool(false)
      • When flag is passed: value is updated to Bool(true)
    • See Migration Guide in README for details
  2. add_option_with_callback() signature changed

    • Added parameter: stop_main_callback: bool
    • Existing calls must specify whether the callback should stop main execution
    • Example: .add_option_with_callback("help", "Help", "-h", "--help", ValueTypes::OptionalSingle(Some(Value::Bool(false))), true, callback)

Added

  • Inheritable options feature - Allows parent commands to share options with subcommands
    • CommandOptionsParser::mark_inheritable(&mut self, flag: &str) -> Result<()> - Marks a single option as inheritable
    • CommandOptionsParser::mark_inheritable_many<I, S>(&mut self, flags: I) -> Result<()> - Marks multiple options as inheritable
    • CommandOptionsParser::inheritable_options_builder(&self) -> CommandOptionsParserBuilder - Creates a builder with only inheritable options
    • FliCommand::with_parser(name, description, builder) - Creates commands with pre-configured option parsers
    • Fli::mark_inheritable(&mut self, flag: &str) -> Result<()> - Convenience method to mark root command options as inheritable
    • Fli::mark_inheritable_many<I, S>(&mut self, flags: I) -> Result<()> - Convenience method to mark multiple root options as inheritable
  • Automatic option inheritance in subcommands
    • Subcommands created via subcommand() now automatically inherit options marked as inheritable from parent commands
    • Eliminates code duplication for common options (e.g., verbose, quiet, color flags)
    • Each subcommand receives its own copy of inherited options
  • Preserved options callback control - PreservedOption.stop_main_callback field
    • Controls whether a preserved option's callback should prevent the main command callback from executing
    • When true (e.g., --help, --version): executes the preserved callback and exits immediately
    • When false (e.g., --debug): executes the preserved callback and then continues to the main callback
    • Enables options like --debug that configure state without halting execution
  • Comprehensive test coverage - Added 30 new test cases covering:
    • Single and multiple option inheritance (20 tests)
    • Input parser command chain prediction (25 tests)
    • ValueTypes::None design flaw demonstrations (4 tests)
    • Nested subcommand inheritance
    • Error handling for non-existent options
    • Independent option copies for each subcommand
    • Mixed short/long flag marking

Changed

  • Enhanced subcommand() method - Now automatically propagates inheritable options from parent to child commands
    • Uses inheritable_options_builder() internally to clone marked options
    • Maintains backward compatibility with existing code
  • Simplified Fli::command() method - Now uses subcommand() for automatic inheritance
  • Improved add_debug_option() implementation - Now uses add_option_with_callback with stop_main_callback: false
    • Allows --debug flag to configure debug mode and still run the main command
    • Removes the manual argument checking that ran before the app starts
  • Flag option handling - Flags now use Bool(true/false) to properly track usage state
    • Parser sets flag value to Bool(true) when encountered in arguments
    • Enables checking flag status via option parser, not just command chain
    • Help display shows "flag" instead of "none" for flag-type options

Fixed

  • Critical bug: ValueTypes::None could not distinguish between defined and passed flags
    • Now using Bool(false) (default) vs Bool(true) (passed) provides clear state tracking
    • Applications can now reliably check if a flag was actually used
  • Parser state machine - Fixed unreachable pattern warning in value acceptance logic

Examples

use fli::Fli;
use fli::option_parser::ValueTypes;

// Parent command with common options
let mut app = Fli::new("myapp", "1.0.0", "My application");
app.add_option("verbose", "Enable verbose output", "-v", "--verbose", ValueTypes::OptionalSingle(Some(Value::Bool(false))));
app.add_option("quiet", "Suppress output", "-q", "--quiet", ValueTypes::OptionalSingle(Some(Value::Bool(false))));

// Mark options as inheritable using convenient Fli methods
app.mark_inheritable_many(&["-v", "-q"]).unwrap();

// All subcommands automatically inherit -v and -q
app.command("start", "Start the service").unwrap();
app.command("stop", "Stop the service").unwrap();
// Both subcommands now have -v/--verbose and -q/--quiet options

Alternative using FliCommand directly:

use fli::command::FliCommand;
use fli::option_parser::ValueTypes;

let mut parent = FliCommand::new("parent", "Parent command");
parent.add_option("verbose", "Verbose", "-v", "--verbose", ValueTypes::OptionalSingle(Some(Value::Bool(false))));
parent.get_option_parser().mark_inheritable("-v").unwrap();

// Subcommand automatically inherits -v
let child = parent.subcommand("child", "Child command");