Releases: codad5/fli
Releases · codad5/fli
v1.2.0
[1.2.0] - 2025-10-26
⚠️ BREAKING CHANGES
-
ValueTypes::Nonehas been REMOVED- Reason: Critical design flaw - impossible to distinguish between "flag defined" and "flag passed"
- Migration: Replace all
ValueTypes::NonewithValueTypes::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)
- When flag is not passed: value remains
- See Migration Guide in README for details
-
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 parameter:
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 inheritableCommandOptionsParser::mark_inheritable_many<I, S>(&mut self, flags: I) -> Result<()>- Marks multiple options as inheritableCommandOptionsParser::inheritable_options_builder(&self) -> CommandOptionsParserBuilder- Creates a builder with only inheritable optionsFliCommand::with_parser(name, description, builder)- Creates commands with pre-configured option parsersFli::mark_inheritable(&mut self, flag: &str) -> Result<()>- Convenience method to mark root command options as inheritableFli::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
- Subcommands created via
- Preserved options callback control -
PreservedOption.stop_main_callbackfield- 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
--debugthat 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
- Uses
- Simplified
Fli::command()method - Now usessubcommand()for automatic inheritance - Improved
add_debug_option()implementation - Now usesadd_option_with_callbackwithstop_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
- Parser sets flag value to
Fixed
- Critical bug:
ValueTypes::Nonecould not distinguish between defined and passed flags- Now using
Bool(false)(default) vsBool(true)(passed) provides clear state tracking - Applications can now reliably check if a flag was actually used
- Now using
- 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 optionsAlternative 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
[1.1.1] - 2025-10-26
Changed
- Code formatting improvements in error handling module
- Reformatted struct field definitions in
FliErrorenum for better readability - Removed unnecessary blank lines for cleaner code organization
- Reformatted struct field definitions in
- Code formatting improvements in value types module
- Simplified match expression formatting in
replace_with_expected_valuemethod - Improved code consistency and readability
- Simplified match expression formatting in
- Test module organization
- Reordered test module declarations alphabetically in
tests/mod.rs
- Reordered test module declarations alphabetically in
Added
- Value mutation and parsing methods in
Valueenumreplace_with_expected_value(&mut self, new_value: &str) -> Result<Value>- Updates a value in place by parsing a string according to the value's typefrom_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
FliErrorenum- Provides detailed error messages for type parsing failures
- Includes the failed value, expected type, and reason for failure
- PartialEq implementation for
Valueenum- 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
ValueTypeshelper 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.rsfile in favor of organizedtests/directory - Added
value_types_test.rswith extensive test coverage
v1.0.0
[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
ValueTypesenumValueTypes::None- Flag options with no valuesValueTypes::RequiredSingle(Value)- Single required valueValueTypes::OptionalSingle(Option<Value>)- Single optional valueValueTypes::RequiredMultiple(Vec<Value>, Option<usize>)- Multiple required values with optional count constraintValueTypes::OptionalMultiple(Option<Vec<Value>>, Option<usize>)- Multiple optional values with optional count constraint
- Value enum supporting multiple types:
Value::Str(String)- String valuesValue::Int(i64)- Integer valuesValue::Float(f64)- Floating-point valuesValue::Bool(bool)- Boolean values
Command System
FliCommandstruct - 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
FliCallbackDatastruct - Rich context passed to callbacks containing:- Parsed options via
get_option_value() - Positional arguments via
get_arguments()andget_argument_at() - Reference to the executing command
- Access to the argument parser
- Parsed options via
- 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
CommandChainenum - Structured representation of parsed arguments:SubCommand(String)- Subcommand invocationsOption(String, ValueTypes)- Options with their valuesArgument(String)- Positional argumentsIsPreservedOption(String)- Preserved options for immediate execution
Error Handling
FliErrorenum with detailed error types:UnknownCommand- Unknown command with suggestionsOptionNotFound- Option lookup failuresMissingValue- Missing required valuesUnexpectedToken- Parsing errors with positionCommandMismatch- Command name mismatchesInternal- 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 ResultError 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 (useinit_fli_from_toml!()macro instead)- String-based option syntax (
"-n --name, <>") - Direct
Fliinstance 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 onFli- UseFliCallbackData::get_option_value()instead.is_passed()method onFli- Check ifget_option_value()returnsSome.has_a_value()method onFli- Useget_option_value()and check value type.get_arg_at()method onFli- UseFliCallbackData::get_argument_at()instead.print_help()onFliinstance - Help is now automatic via--helpflag.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 structurecommand.rs- Command handlingdisplay.rs- Output formattingerror.rs- Error typesoption_parser/- Parsing logicinput_parser.rs- Argument parsingoption_parser.rs- Option managementvalue_types.rs- Type systemparse_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
CHANGELOG
0.1.0
- Added new
init_fli_from_tomlmacro to allow initializing the app from a toml fileinit_fli_from_toml!macro will read the toml file and initialize the app with the values
- Deprecated
init_from_tomlmethodinit_from_tomlmethod is deprecated and will be removed in the next major release
Version 0.0.10
CHANGELOG
0.0.10
- Added auto version option to hrlp print version using
--versionor-v
v0.0.9
Version 0.0.8
CHANGELOG
0.0.6
- Fix issue on removing index out of bounds when getting values
Version 0.0.7
CHANGELOG
0.0.5
- Added support to set app version
app.set_version("0.0.5")- if using
init_from_tomlthe 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