Module :: unilang
A universal command framework that lets you define command-line interfaces once and deploy them across multiple interaction paradigms — CLI, TUI, GUI, Web APIs, and more.
Why unilang?
When building command-line tools, you often face these challenges:
- Repetitive Code: Defining argument parsing, validation, and help generation for each command
- Inconsistent APIs: Different interaction modes (CLI vs Web API) require separate implementations
- Limited Extensibility: Hard to add new commands or change existing ones without major refactoring
- Poor User Experience: Inconsistent help messages, error handling, and command organization
unilang solves these problems by providing:
- 📝 Single Definition: Define commands once, use everywhere
- 🔧 Multiple Modalities: Same commands work as CLI, Web API, or programmatic API
- 🏗️ Modular Architecture: Easy to add, modify, or remove commands
- 🎯 Type Safety: Strong typing with comprehensive validation
- 📚 Auto Documentation: Help text and command discovery built-in
- 🔍 Rich Validation: Built-in validators for common patterns
Quick Start
Installation
Basic Example
Here's a simple "Hello World" command:
use *;
Run this example:
Core Concepts
1. Command Registry
The central hub that stores and manages all command definitions and their execution routines.
use *;
let mut registry = new;
// registry is now ready to use
2. Command Definition
Describes a command's metadata, arguments, and behavior.
use *;
let command = CommandDefinition
;
// command definition is complete
assert_eq!;
3. Argument Types
unilang supports rich argument types with automatic parsing and validation:
- Basic Types:
String,Integer,Float,Boolean - Path Types:
Path,File,Directory - Complex Types:
Url,DateTime,Pattern(regex) - Collections:
List<T>,Map<K,V> - Special Types:
Enum(choices),JsonString,Object
4. Validation Rules
Built-in validators ensure arguments meet requirements:
use *;
use ValidationRule;
let validation_rules : = vec!
;
assert_eq!;
5. Command Execution Pipeline
The execution flow: Parse → Validate → Execute
use *;
let registry = new;
let pipeline = new;
let result = pipeline.process_command_simple;
// result contains the execution outcome
6. Verbosity Control
Control debug output levels for cleaner CLI experiences:
use *;
use UnilangParserOptions;
// Create registry and set verbosity programmatically
let registry = new;
let mut parser_options = default;
parser_options.verbosity = 0; // 0 = quiet, 1 = normal, 2 = debug
let pipeline = with_parser_options;
Or use environment variable:
# Quiet mode - suppress all debug output
UNILANG_VERBOSITY=0
# Normal mode (default) - standard output only
UNILANG_VERBOSITY=1
# Debug mode - include parser traces
UNILANG_VERBOSITY=2
Examples
Working with Different Argument Types
use *;
use ValidationRule;
// See examples/02_argument_types.rs for the full example
let command = CommandDefinition
;
assert_eq!;
Run the argument types demo:
Using Collections
use *;
// See examples/03_collection_types.rs for the full example
// List of strings with custom delimiter
let _tags_arg = ArgumentDefinition
;
// Map with custom delimiters
let _options_arg = ArgumentDefinition
;
assert_eq!;
Run the collections demo:
Namespaces and Command Organization
use *;
// See examples/05_namespaces_and_aliases.rs for the full example
// Commands can be organized hierarchically
let commands = vec!
;
assert_eq!;
Loading Commands from YAML/JSON
// See examples/07_yaml_json_loading.rs for the full example
use ;
use *;
// Load from YAML file
let mut registry = new;
let commands = load_from_yaml_file?;
for cmd in commands
// Or from JSON string
let json = r#"[
{
"name" : "test",
"description" : "Test command",
"arguments" : []
}]"#;
let commands = load_from_json_str?;
Command-Line Usage Patterns
unilang supports flexible command-line syntax:
# Named arguments (recommended)
# Positional arguments
# Mixed (positional first, then named)
# With namespaces
# Using aliases
# List all commands (just dot)
# Get help for any command
Advanced Features
Custom Validation
use *;
use ValidationRule;
// Create complex validation rules
let password_arg = ArgumentDefinition
;
assert!;
Batch Processing
use *;
let registry = new;
let pipeline = new;
// Process multiple commands efficiently
let commands = vec!
;
let batch_result = pipeline.process_batch;
// Success rate will be 0% since no commands are registered
assert_eq!;
Help System
unilang provides a comprehensive help system with two ways to access help:
use *;
let registry = new;
// Automatic help generation
let help_gen = new;
// List all commands (will be empty for new registry)
let commands_list = help_gen.list_commands;
assert!; // Always contains header
// Get help for specific command (returns None if not found)
let help = help_gen.command;
assert!; // No commands registered yet
The help operator (?) provides instant help without argument validation:
# Shows help even if required arguments are missing
This ensures users can always get help, even when they don't know the required arguments.
Full CLI Example
For a complete example showing all features, check out:
# Run the full CLI example with dot-prefixed command
# See available commands (just dot shows all commands with help)
# Get help for a specific command
API Modes
unilang can be used in different ways:
1. Pipeline API (Recommended)
High-level API that handles the full command execution pipeline:
use *;
let registry = new;
let pipeline = new;
let result = pipeline.process_command_simple;
// Result will indicate command not found since no commands are registered
assert!;
2. Component API
Lower-level access to individual components:
use *;
# let registry = new;
# let input = ".example";
# let mut context = default;
// Parse
let parser = new;
let instruction = parser.parse_single_instruction?;
// Analyze
let analyzer = new;
let commands = analyzer.analyze?;
// Execute
let interpreter = new;
interpreter.run?;
3. Direct Integration
For maximum control:
use *;
# let registry = new;
# let verified_command = todo!;
# let context = default;
// Direct command execution
let routine = registry.routines.get.unwrap;
let result = routine?;
REPL (Read-Eval-Print Loop) Support
unilang provides comprehensive support for building interactive REPL applications. The framework's stateless architecture makes it ideal for REPL implementations.
Basic REPL Implementation
use ;
use ;
Interactive Arguments with Secure Input
unilang supports interactive arguments for secure input like passwords:
// In your command definition
use ;
ArgumentDefinition ;
// In your REPL loop
use ;
match result.error
Advanced REPL Features
For production REPL applications, consider these patterns:
Command History & Auto-completion:
use HashMap;
let mut command_history = Vecnew;
let mut session_stats = new;
// In your REPL loop
if input.ends_with
command_history.push;
Error Recovery:
match result.error
Session Management:
// Track session statistics for debugging and UX
let mut session = ReplSession ;
session.command_count += 1;
if result.success else
REPL Performance Considerations
- Component Reuse: Pipeline components are stateless and reusable - this provides 20-50% performance improvement over creating new instances
- Memory Management: Bound command history to prevent memory leaks in long-running sessions
- Static Commands: Use static command registry with PHF for zero-cost lookups even with millions of commands
Complete REPL Examples
The examples/ directory contains comprehensive REPL implementations:
12_repl_loop.rs- Basic REPL with stateless operation15_interactive_repl_mode.rs- Interactive arguments and secure input17_advanced_repl_features.rs- Full-featured REPL with history, auto-completion, and error recovery
Key REPL Insights:
- ✅ Stateless Design: Each command execution is independent - no state accumulation
- ✅ Interactive Security: Proper handling of passwords and API keys
- ✅ Error Isolation: Command failures don't affect subsequent commands
- ✅ Memory Efficiency: Constant memory usage regardless of session length
- ✅ Professional UX: History, auto-completion, and intelligent error recovery
Error Handling
unilang provides comprehensive error handling:
use *;
let registry = new;
let pipeline = new;
let input = ".example";
match pipeline.process_command_simple
More Examples
Explore the examples/ directory for more detailed examples:
01_basic_command_registration.rs- Getting started02_argument_types.rs- All supported argument types03_collection_types.rs- Lists and maps04_validation_rules.rs- Input validation05_namespaces_and_aliases.rs- Command organization06_help_system.rs- Automatic help generation07_yaml_json_loading.rs- Loading commands from files08_semantic_analysis_simple.rs- Understanding the analysis phase09_command_execution.rs- Execution patterns10_full_pipeline.rs- Complete pipeline example11_pipeline_api.rs- Pipeline API featuresfull_cli_example.rs- Full-featured CLI application
Contributing
See CONTRIBUTING.md for details.
License
Licensed under MIT license (LICENSE or https://opensource.org/licenses/MIT)