Skip to content

Releases: codad5/fli

v1.2.0

27 Oct 00:03

Choose a tag to compare

[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");

v1.1.1

26 Oct 20:52
91ea2b4

Choose a tag to compare

[1.1.1] - 2025-10-26

Changed

  • Code formatting improvements in error handling module
    • Reformatted struct field definitions in FliError enum for better readability
    • Removed unnecessary blank lines for cleaner code organization
  • Code formatting improvements in value types module
    • Simplified match expression formatting in replace_with_expected_value method
    • Improved code consistency and readability
  • Test module organization
    • Reordered test module declarations alphabetically in tests/mod.rs

Added

  • Value mutation and parsing methods in Value enum
    • replace_with_expected_value(&mut self, new_value: &str) -> Result<Value> - Updates a value in place by parsing a string according to the value's type
    • from_str_with_type(template: &Value, input: &str) -> Result<Value> - Creates a new value from a string using a template for type inference
  • Enhanced boolean parsing - Accepts multiple formats: true/false, t/f, 1/0, yes/no, y/n (case-insensitive)
  • ValueParseError variant in FliError enum
    • Provides detailed error messages for type parsing failures
    • Includes the failed value, expected type, and reason for failure
  • PartialEq implementation for Value enum
    • Enables value comparison and equality testing
    • Float comparison uses EPSILON for precision handling
  • Comprehensive test suite for value types
    • 44 tests covering all value creation, parsing, and conversion scenarios
    • Tests for success and failure cases across all supported types (Str, Int, Float, Bool)
    • Tests for ValueTypes helper methods (expects_value, as_str, as_strings)

Changed

  • Input parsing improvements
    • Enhanced string value handling in option parser
    • Better default value management for optional single values
    • Improved error propagation using ValueParseError

Internal

  • Removed obsolete tests.rs file in favor of organized tests/ directory
  • Added value_types_test.rs with extensive test coverage

v1.0.0

26 Oct 16:57
75106f9

Choose a tag to compare

[1.0.0] - 2025-10-24

🎉 Major Release - Breaking Changes

This is a complete rewrite of Fli with significant improvements to type safety, error handling, and API design.

Added

Type System

  • Type-safe value parsing with explicit ValueTypes enum
    • ValueTypes::None - Flag options with no values
    • ValueTypes::RequiredSingle(Value) - Single required value
    • ValueTypes::OptionalSingle(Option<Value>) - Single optional value
    • ValueTypes::RequiredMultiple(Vec<Value>, Option<usize>) - Multiple required values with optional count constraint
    • ValueTypes::OptionalMultiple(Option<Vec<Value>>, Option<usize>) - Multiple optional values with optional count constraint
  • Value enum supporting multiple types:
    • Value::Str(String) - String values
    • Value::Int(i64) - Integer values
    • Value::Float(f64) - Floating-point values
    • Value::Bool(bool) - Boolean values

Command System

  • FliCommand struct - Dedicated command structure with:
    • Hierarchical subcommand support
    • Per-command option parsing
    • Command-specific callbacks
    • Expected positional arguments tracking
  • Preserved options - Special options (like --help) that execute immediately
  • Command chaining - Fluent API for building complex command structures
  • Subcommand support via .subcommand() method

Callback System

  • FliCallbackData struct - Rich context passed to callbacks containing:
    • Parsed options via get_option_value()
    • Positional arguments via get_arguments() and get_argument_at()
    • Reference to the executing command
    • Access to the argument parser
  • Convenient value extraction methods:
    • .as_str() - Extract string from single value
    • .as_strings() - Extract strings from multiple values
    • Support for multiple lookup formats (with/without dashes)

Parser

  • InputArgsParser - Sophisticated argument parser with:
    • State machine-based parsing
    • Support for -- separator for positional arguments
    • Proper handling of option-value relationships
    • Validation of required values
  • CommandChain enum - Structured representation of parsed arguments:
    • SubCommand(String) - Subcommand invocations
    • Option(String, ValueTypes) - Options with their values
    • Argument(String) - Positional arguments
    • IsPreservedOption(String) - Preserved options for immediate execution

Error Handling

  • FliError enum with detailed error types:
    • UnknownCommand - Unknown command with suggestions
    • OptionNotFound - Option lookup failures
    • MissingValue - Missing required values
    • UnexpectedToken - Parsing errors with position
    • CommandMismatch - Command name mismatches
    • Internal - Internal errors
  • Result type - Proper error propagation throughout the API

Display System

  • Beautiful help output with:
    • Formatted tables using box-drawing characters
    • Color-coded sections
    • Automatic usage pattern generation
    • Options and subcommands tables
    • Support for both root and subcommand help
  • Debug mode via .with_debug() and .add_debug_option()
  • Error formatting with detailed messages and suggestions
  • "Did you mean?" suggestions for unknown commands using Levenshtein distance

API Improvements

  • Builder pattern with method chaining
  • Separate methods for different concerns:
    • .add_option() - Add options
    • .set_callback() - Set callbacks
    • .command() - Create commands
    • .subcommand() - Create subcommands
  • Expected positional args - .set_expected_positional_args(count)

Changed

Breaking Changes

Option Definition

Before (v0.x):

app.option("-n --name, <>", "Description", callback);

After (v1.0):

app.add_option("name", "Description", "-n", "--name", 
    ValueTypes::RequiredSingle(Value::Str(String::new())));
app.set_callback(callback);
Callback Signature

Before (v0.x):

fn callback(app: &Fli) { }

After (v1.0):

fn callback(data: &FliCallbackData) { }
Value Retrieval

Before (v0.x):

let value = app.get_values("name".to_owned()).unwrap()[0];

After (v1.0):

let value = data.get_option_value("name")
    .and_then(|v| v.as_str())
    .unwrap_or("default");
Command Creation

Before (v0.x):

let cmd = app.command("serve", "Description");

After (v1.0):

let cmd = app.command("serve", "Description")?; // Returns Result
Error Types

Before (v0.x):

Result<(), String>

After (v1.0):

Result<(), FliError>

API Changes

  • .option() renamed to .add_option() with new signature
  • .default() renamed to .set_callback()
  • .run() no longer panics, properly handles errors
  • Removed string-based option template syntax ("-n --name, <>")
  • Commands now return Result<&mut FliCommand> instead of &mut Fli

Improved

  • Help generation - Dramatically improved with tables and sections
  • Error messages - More descriptive with context and suggestions
  • Type safety - Compile-time guarantees for option values
  • Documentation - Comprehensive docs with examples
  • Performance - More efficient parsing with state machine
  • Code organization - Modular architecture with separate concerns

Deprecated

  • init_from_toml() method (use init_fli_from_toml!() macro instead)
  • String-based option syntax ("-n --name, <>")
  • Direct Fli instance manipulation in callbacks

Removed

  • .allow_duplicate_callback() - No longer needed with new architecture
  • .allow_inital_no_param_values() - Replaced by .set_expected_positional_args()
  • .get_values() method on Fli - Use FliCallbackData::get_option_value() instead
  • .is_passed() method on Fli - Check if get_option_value() returns Some
  • .has_a_value() method on Fli - Use get_option_value() and check value type
  • .get_arg_at() method on Fli - Use FliCallbackData::get_argument_at() instead
  • .print_help() on Fli instance - Help is now automatic via --help flag
  • .get_params_callback() - Internal method no longer exposed
  • .get_callable_name() - Internal method no longer exposed

Testing

  • Comprehensive test suite added with 110+ tests covering:
    • Error handling (12 tests)
    • Value types (19 tests)
    • Option parser (15 tests)
    • Display utilities (10 tests)
    • Command system (14 tests)
    • App functionality (13 tests)
    • Library functions (17 tests)
    • Macro functionality (8 tests)

Internal Improvements

  • Modular architecture with separated concerns:
    • app.rs - Application structure
    • command.rs - Command handling
    • display.rs - Output formatting
    • error.rs - Error types
    • option_parser/ - Parsing logic
      • input_parser.rs - Argument parsing
      • option_parser.rs - Option management
      • value_types.rs - Type system
      • parse_state.rs - Parser state machine
  • State machine-based parser for reliable argument parsing
  • HashMap-based lookups for O(1) option access
  • Improved documentation with comprehensive examples

Migration Guide

See detailed migration instructions below for upgrading from v0.x to v1.0.


Version 0.1.0

14 Oct 13:18
4cabf87

Choose a tag to compare

CHANGELOG

0.1.0

  • Added new init_fli_from_toml macro to allow initializing the app from a toml file
    • init_fli_from_toml! macro will read the toml file and initialize the app with the values
  • Deprecated init_from_toml method
    • init_from_toml method is deprecated and will be removed in the next major release

Version 0.0.10

13 Oct 20:33

Choose a tag to compare

CHANGELOG

0.0.10

  • Added auto version option to hrlp print version using --version or -v

v0.0.9

13 Oct 20:15

Choose a tag to compare

CHANGELOG

0.0.9

  • Fix env var issue
    • used env! macro to get the toml details from the Cargo.toml file instead of std::env::var to allow compile time env instead of runtime

Version 0.0.8

13 Oct 18:47

Choose a tag to compare

CHANGELOG

0.0.6

  • Fix issue on removing index out of bounds when getting values

Version 0.0.7

13 Oct 18:38

Choose a tag to compare

CHANGELOG

0.0.5

  • Added support to set app version
    • app.set_version("0.0.5")
    • if using init_from_toml the version will be set from the toml file
  • Properly handle the help message
    • Printing list of similar command if a command is not found
    • Printing the help message if the help command is found