Flag

Struct Flag 

Source
pub struct Flag {
    pub name: String,
    pub short: Option<char>,
    pub usage: String,
    pub default: Option<FlagValue>,
    pub required: bool,
    pub value_type: FlagType,
    pub constraints: Vec<FlagConstraint>,
    pub completion: Option<CompletionFunc>,
}
Expand description

Represents a command-line flag

A Flag defines a command-line option that can be passed to a command. Flags can have both long names (e.g., --verbose) and short names (e.g., -v).

§Examples

use flag_rs::flag::{Flag, FlagType, FlagValue};

// Create a boolean flag
let verbose = Flag::new("verbose")
    .short('v')
    .usage("Enable verbose output")
    .value_type(FlagType::Bool)
    .default(FlagValue::Bool(false));

// Create a string flag with validation
let name = Flag::new("name")
    .short('n')
    .usage("Name of the resource")
    .value_type(FlagType::String)
    .required();

Fields§

§name: String

The long name of the flag (e.g., “verbose” for –verbose)

§short: Option<char>

The optional short name of the flag (e.g., ‘v’ for -v)

§usage: String

A description of what the flag does

§default: Option<FlagValue>

The default value if the flag is not provided

§required: bool

Whether this flag must be provided

§value_type: FlagType

The type of value this flag accepts

§constraints: Vec<FlagConstraint>

Constraints applied to this flag

§completion: Option<CompletionFunc>

Optional completion function for this flag’s values

Implementations§

Source§

impl Flag

Source

pub fn new(name: impl Into<String>) -> Self

Creates a new flag with the given name

§Examples
use flag_rs::flag::Flag;

let flag = Flag::new("verbose");
assert_eq!(flag.name, "verbose");
Examples found in repository?
examples/benchmark.rs (line 54)
50fn create_simple_cli() -> flag_rs::Command {
51    CommandBuilder::new("bench")
52        .short("Benchmark CLI")
53        .flag(
54            Flag::new("verbose")
55                .short('v')
56                .value_type(FlagType::Bool)
57                .default(FlagValue::Bool(false)),
58        )
59        .flag(Flag::new("output").short('o').value_type(FlagType::String))
60        .build()
61}
62
63/// Creates a complex nested command structure
64fn create_complex_cli() -> flag_rs::Command {
65    let mut root = CommandBuilder::new("complex")
66        .short("Complex CLI with many subcommands")
67        .flag(
68            Flag::new("config")
69                .short('c')
70                .value_type(FlagType::File)
71                .default(FlagValue::String("config.yaml".to_string())),
72        )
73        .build();
74
75    // Add 50 subcommands
76    for i in 0..50 {
77        let mut sub = CommandBuilder::new(format!("sub{i:02}"))
78            .short(format!("Subcommand {i}"))
79            .flag(Flag::new("flag1").short('1').value_type(FlagType::String))
80            .flag(Flag::new("flag2").short('2').value_type(FlagType::Int))
81            .build();
82
83        // Add 10 nested subcommands
84        for j in 0..10 {
85            sub.add_command(
86                CommandBuilder::new(format!("nested{j}"))
87                    .short(format!("Nested command {j}"))
88                    .flag(Flag::new("deep").value_type(FlagType::Bool))
89                    .build(),
90            );
91        }
92
93        root.add_command(sub);
94    }
95
96    root
97}
98
99fn bench_command_creation() {
100    println!("\n=== Command Creation Benchmarks ===");
101
102    let bench = Benchmark::new("Simple command creation", 10_000);
103    let duration = bench.run(|| {
104        let _ = create_simple_cli();
105    });
106    bench.report(duration);
107
108    let bench = Benchmark::new("Complex command creation (50 subs)", 100);
109    let duration = bench.run(|| {
110        let _ = create_complex_cli();
111    });
112    bench.report(duration);
113
114    let bench = Benchmark::new("CommandBuilder with 10 flags", 1_000);
115    let duration = bench.run(|| {
116        let mut cmd = CommandBuilder::new("test");
117        for i in 0..10 {
118            cmd = cmd.flag(Flag::new(format!("flag{i}")).value_type(FlagType::String));
119        }
120        let _ = cmd.build();
121    });
122    bench.report(duration);
123}
124
125fn bench_flag_parsing() {
126    println!("\n=== Flag Parsing Benchmarks ===");
127
128    let cli = create_simple_cli();
129
130    let bench = Benchmark::new("Parse no flags", 10_000);
131    let duration = bench.run(|| {
132        let args = vec!["bench".to_string()];
133        let _ = cli.execute(args);
134    });
135    bench.report(duration);
136
137    let bench = Benchmark::new("Parse single flag", 10_000);
138    let duration = bench.run(|| {
139        let args = vec!["bench".to_string(), "--verbose".to_string()];
140        let _ = cli.execute(args);
141    });
142    bench.report(duration);
143
144    let bench = Benchmark::new("Parse flag with value", 10_000);
145    let duration = bench.run(|| {
146        let args = vec![
147            "bench".to_string(),
148            "--output".to_string(),
149            "file.txt".to_string(),
150        ];
151        let _ = cli.execute(args);
152    });
153    bench.report(duration);
154
155    let bench = Benchmark::new("Parse multiple flags", 10_000);
156    let duration = bench.run(|| {
157        let args = vec![
158            "bench".to_string(),
159            "-v".to_string(),
160            "-o".to_string(),
161            "output.txt".to_string(),
162        ];
163        let _ = cli.execute(args);
164    });
165    bench.report(duration);
166}
167
168fn bench_subcommand_lookup() {
169    println!("\n=== Subcommand Lookup Benchmarks ===");
170
171    let cli = create_complex_cli();
172
173    let bench = Benchmark::new("Find immediate subcommand", 10_000);
174    let duration = bench.run(|| {
175        let _ = cli.find_subcommand("sub25");
176    });
177    bench.report(duration);
178
179    let bench = Benchmark::new("Find nested subcommand", 10_000);
180    let duration = bench.run(|| {
181        if let Some(sub) = cli.find_subcommand("sub25") {
182            let _ = sub.find_subcommand("nested5");
183        }
184    });
185    bench.report(duration);
186
187    let bench = Benchmark::new("Execute nested command", 1_000);
188    let duration = bench.run(|| {
189        let args = vec![
190            "complex".to_string(),
191            "sub25".to_string(),
192            "nested5".to_string(),
193            "--deep".to_string(),
194        ];
195        let _ = cli.execute(args);
196    });
197    bench.report(duration);
198}
199
200fn bench_completion() {
201    println!("\n=== Completion Benchmarks ===");
202
203    let cli = CommandBuilder::new("comp")
204        .arg_completion(|_ctx, prefix| {
205            let items: Vec<String> = (0..100)
206                .map(|i| format!("item{i:03}"))
207                .filter(|item| item.starts_with(prefix))
208                .collect();
209            Ok(CompletionResult::new().extend(items))
210        })
211        .build();
212
213    let ctx = flag_rs::Context::new(vec!["comp".to_string()]);
214
215    let bench = Benchmark::new("Complete with empty prefix (100 items)", 1_000);
216    let duration = bench.run(|| {
217        let _ = cli.get_completions(&ctx, "", None);
218    });
219    bench.report(duration);
220
221    let bench = Benchmark::new("Complete with prefix (filtered)", 1_000);
222    let duration = bench.run(|| {
223        let _ = cli.get_completions(&ctx, "item05", None);
224    });
225    bench.report(duration);
226
227    // Test completion with descriptions
228    let cli_desc = CommandBuilder::new("comp_desc")
229        .arg_completion(|_ctx, prefix| {
230            let mut result = CompletionResult::new();
231            for i in 0..50 {
232                let item = format!("option{i:02}");
233                if item.starts_with(prefix) {
234                    result =
235                        result.add_with_description(item, format!("Description for option {i}"));
236                }
237            }
238            Ok(result)
239        })
240        .build();
241
242    let bench = Benchmark::new("Complete with descriptions (50 items)", 1_000);
243    let duration = bench.run(|| {
244        let _ = cli_desc.get_completions(&ctx, "", None);
245    });
246    bench.report(duration);
247}
248
249fn bench_flag_validation() {
250    println!("\n=== Flag Validation Benchmarks ===");
251
252    let cli = CommandBuilder::new("validate")
253        .flag(Flag::new("choice").value_type(FlagType::Choice(vec![
254            "opt1".to_string(),
255            "opt2".to_string(),
256            "opt3".to_string(),
257        ])))
258        .flag(Flag::new("range").value_type(FlagType::Range(1, 100)))
259        .flag(
260            Flag::new("required")
261                .value_type(FlagType::String)
262                .required(),
263        )
264        .build();
265
266    let bench = Benchmark::new("Validate choice flag", 10_000);
267    let duration = bench.run(|| {
268        let args = vec![
269            "validate".to_string(),
270            "--choice".to_string(),
271            "opt2".to_string(),
272            "--required".to_string(),
273            "value".to_string(),
274        ];
275        let _ = cli.execute(args);
276    });
277    bench.report(duration);
278
279    let bench = Benchmark::new("Validate range flag", 10_000);
280    let duration = bench.run(|| {
281        let args = vec![
282            "validate".to_string(),
283            "--range".to_string(),
284            "50".to_string(),
285            "--required".to_string(),
286            "value".to_string(),
287        ];
288        let _ = cli.execute(args);
289    });
290    bench.report(duration);
291
292    let bench = Benchmark::new("Validate missing required flag", 10_000);
293    let duration = bench.run(|| {
294        let args = vec!["validate".to_string()];
295        let _ = cli.execute(args); // This will fail validation
296    });
297    bench.report(duration);
298}
More examples
Hide additional examples
examples/kubectl.rs (line 23)
14fn build_kubectl() -> Command {
15    CommandBuilder::new("kubectl")
16        .short("Kubernetes command-line tool")
17        .long("kubectl controls the Kubernetes cluster manager")
18        .subcommand(build_get_command())
19        .subcommand(build_describe_command())
20        .subcommand(build_delete_command())
21        .subcommand(build_completion_command())
22        .flag(
23            Flag::new("namespace")
24                .short('n')
25                .usage("Kubernetes namespace")
26                .value_type(FlagType::String)
27                .default(FlagValue::String("default".to_string())),
28        )
29        .flag_completion("namespace", |_ctx, prefix| {
30            // In a real kubectl, this would query the API server
31            let namespaces = get_namespaces_with_descriptions();
32            let mut result = CompletionResult::new();
33
34            for (ns_name, description) in namespaces {
35                if ns_name.starts_with(prefix) {
36                    result = result.add_with_description(ns_name, description);
37                }
38            }
39
40            Ok(result)
41        })
42        .build()
43}
44
45fn build_get_command() -> Command {
46    CommandBuilder::new("get")
47        .short("Display one or many resources")
48        .long("Display one or many resources. Prints a table of the most important information about the specified resources.")
49        .flag(
50            Flag::new("limit")
51                .short('l')
52                .usage("Maximum number of resources to display")
53                .value_type(FlagType::String)
54        )
55        .flag_completion("limit", |_ctx, prefix| {
56            let common_limits = vec![
57                ("10", "Display 10 items"),
58                ("20", "Display 20 items"),
59                ("50", "Display 50 items"),
60                ("100", "Display 100 items"),
61                ("all", "Display all items (no limit)"),
62            ];
63
64            let mut result = CompletionResult::new();
65            for (limit, description) in common_limits {
66                if limit.starts_with(prefix) {
67                    result = result.add_with_description(limit.to_string(), description.to_string());
68                }
69            }
70
71            Ok(result)
72        })
73        .subcommand(build_get_pods())
74        .subcommand(build_get_services())
75        .subcommand(build_get_deployments())
76        .build()
77}
examples/terminal_demo.rs (line 22)
17fn main() {
18    let app = CommandBuilder::new("demo")
19        .short("Terminal feature demonstration")
20        .long("This application demonstrates the terminal width detection and text wrapping features. The help text should automatically adjust to your terminal width, wrapping long lines at word boundaries while maintaining readability. Try running this with different COLUMNS values to see how it adapts.")
21        .flag(
22            Flag::new("file")
23                .short('f')
24                .usage("Input file path. This flag expects a path to a file that will be processed. The file must exist and be readable.")
25                .value_type(FlagType::String)
26        )
27        .flag(
28            Flag::new("output-format")
29                .short('o')
30                .usage("Output format for results. Supported formats include: json (machine-readable JSON format), yaml (human-friendly YAML format), table (formatted ASCII table), csv (comma-separated values for spreadsheet import)")
31                .value_type(FlagType::String)
32                .default(FlagValue::String("table".to_string()))
33        )
34        .subcommand(
35            CommandBuilder::new("process")
36                .short("Process data with various transformations and filters that can be applied in sequence")
37                .build()
38        )
39        .build();
40
41    // Always show help for this demo
42    app.print_help();
43}
examples/test_completion.rs (line 7)
3fn main() {
4    let cmd = CommandBuilder::new("test")
5        .short("Test completion with descriptions")
6        .flag(
7            Flag::new("environment")
8                .short('e')
9                .usage("Target environment")
10                .value_type(FlagType::String),
11        )
12        .flag_completion("environment", |_ctx, prefix| {
13            let mut result = CompletionResult::new();
14            let envs = vec![
15                ("dev", "Development environment - safe for testing"),
16                ("staging", "Staging environment - mirror of production"),
17                ("production", "Production environment - BE CAREFUL!"),
18            ];
19
20            for (env, desc) in envs {
21                if env.starts_with(prefix) {
22                    result = result.add_with_description(env, desc);
23                }
24            }
25
26            Ok(result)
27        })
28        .subcommand(
29            CommandBuilder::new("deploy")
30                .short("Deploy the application")
31                .long("Deploy the application to the specified environment")
32                .build(),
33        )
34        .subcommand(
35            CommandBuilder::new("rollback")
36                .short("Rollback to previous version")
37                .long("Rollback the application to the previous deployed version")
38                .build(),
39        )
40        .build();
41
42    // Test completion output
43    if let Ok(shell_type) = std::env::var("TEST_COMPLETE") {
44        // For testing, override shell type to "display" to see formatted output
45        let display_mode = std::env::var("DISPLAY_MODE").is_ok();
46        let args: Vec<String> = std::env::args().skip(1).collect();
47
48        if display_mode {
49            // This is a hack for testing - normally shells would handle this
50            println!("Display mode - showing formatted completions:");
51            match cmd.handle_completion_request(&args) {
52                Ok(completions) => {
53                    for completion in completions {
54                        println!("{}", completion);
55                    }
56                }
57                Err(e) => eprintln!("Completion error: {}", e),
58            }
59        } else {
60            match cmd.handle_completion_request(&args) {
61                Ok(completions) => {
62                    println!("Shell type: {}", shell_type);
63                    println!("Completions:");
64                    for completion in completions {
65                        println!("{}", completion);
66                    }
67                }
68                Err(e) => eprintln!("Completion error: {}", e),
69            }
70        }
71    } else {
72        let args: Vec<String> = std::env::args().skip(1).collect();
73        if let Err(e) = cmd.execute(args) {
74            eprintln!("Error: {}", e);
75            std::process::exit(1);
76        }
77    }
78}
examples/enhanced_errors_demo.rs (line 11)
7fn main() {
8    let app = CommandBuilder::new("errordemo")
9        .short("Demo of enhanced error messages")
10        .flag(
11            Flag::new("verbose")
12                .short('v')
13                .value_type(FlagType::Bool)
14                .usage("Enable verbose output"),
15        )
16        .flag(
17            Flag::new("workers")
18                .short('w')
19                .value_type(FlagType::Range(1, 10))
20                .usage("Number of worker threads"),
21        )
22        .flag(
23            Flag::new("format")
24                .short('f')
25                .value_type(FlagType::Choice(vec![
26                    "json".to_string(),
27                    "yaml".to_string(),
28                    "xml".to_string(),
29                    "toml".to_string(),
30                ]))
31                .usage("Output format"),
32        )
33        .flag(
34            Flag::new("config")
35                .short('c')
36                .value_type(FlagType::File)
37                .usage("Configuration file"),
38        )
39        .flag(
40            Flag::new("outdir")
41                .short('o')
42                .value_type(FlagType::Directory)
43                .usage("Output directory"),
44        )
45        .flag(
46            Flag::new("ssl")
47                .value_type(FlagType::Bool)
48                .usage("Enable SSL"),
49        )
50        .flag(
51            Flag::new("ssl-cert")
52                .value_type(FlagType::File)
53                .constraint(FlagConstraint::RequiredIf("ssl".to_string()))
54                .usage("SSL certificate file"),
55        )
56        .flag(
57            Flag::new("json")
58                .value_type(FlagType::Bool)
59                .constraint(FlagConstraint::ConflictsWith(vec!["xml".to_string()]))
60                .usage("Output in JSON format"),
61        )
62        .flag(
63            Flag::new("xml")
64                .value_type(FlagType::Bool)
65                .usage("Output in XML format"),
66        )
67        .flag(
68            Flag::new("required-flag")
69                .value_type(FlagType::String)
70                .required()
71                .usage("This flag is required"),
72        )
73        .subcommand(
74            CommandBuilder::new("process")
75                .short("Process data")
76                .run(|ctx| {
77                    println!("Processing with flags: {:?}", ctx.flags());
78                    Ok(())
79                })
80                .build(),
81        )
82        .build();
83
84    println!("Try these commands to see enhanced error messages:\n");
85    println!("  # Boolean parsing error");
86    println!("  cargo run --example enhanced_errors_demo -- --verbose=maybe\n");
87
88    println!("  # Integer parsing error");
89    println!("  cargo run --example enhanced_errors_demo -- --workers=abc\n");
90
91    println!("  # Range validation error");
92    println!("  cargo run --example enhanced_errors_demo -- --workers=20\n");
93
94    println!("  # Choice validation error");
95    println!("  cargo run --example enhanced_errors_demo -- --format=csv\n");
96
97    println!("  # File not found error");
98    println!("  cargo run --example enhanced_errors_demo -- --config=/tmp/nonexistent.conf\n");
99
100    println!("  # Directory not found error");
101    println!("  cargo run --example enhanced_errors_demo -- --outdir=/tmp/nonexistent_dir\n");
102
103    println!("  # Flag constraint error (RequiredIf)");
104    println!("  cargo run --example enhanced_errors_demo -- --ssl --required-flag=test process\n");
105
106    println!("  # Flag constraint error (ConflictsWith)");
107    println!(
108        "  cargo run --example enhanced_errors_demo -- --json --xml --required-flag=test process\n"
109    );
110
111    println!("  # Required flag error");
112    println!("  cargo run --example enhanced_errors_demo -- process\n");
113
114    println!("  # Unknown command error");
115    println!("  cargo run --example enhanced_errors_demo -- --required-flag=test proces\n");
116
117    let args: Vec<String> = std::env::args().skip(1).collect();
118    if !args.is_empty() {
119        println!("\n{}", "=".repeat(60));
120        println!("Running with args: {:?}\n", args);
121
122        if let Err(e) = app.execute(args) {
123            eprintln!("{}", e);
124            std::process::exit(1);
125        }
126    }
127}
examples/memory_optimization_demo.rs (line 25)
12fn create_many_subcommands(parent: &mut flag_rs::Command) {
13    // Simulate a large CLI with 100 subcommands
14    for i in 0..100 {
15        let cmd_name = format!("service-{i:03}");
16
17        // Use string interning for flag names that repeat across commands
18        let namespace_flag_name = string_pool::intern("namespace");
19        let region_flag_name = string_pool::intern("region");
20        let env_flag_name = string_pool::intern("environment");
21
22        let cmd = CommandBuilder::new(cmd_name.clone())
23            .short(format!("Manage service {i}"))
24            .flag(
25                Flag::new(namespace_flag_name.to_string())
26                    .short('n')
27                    .usage("Kubernetes namespace")
28                    .value_type(FlagType::String)
29                    .default(flag_rs::FlagValue::String("default".to_string())),
30            )
31            .flag(
32                Flag::new(region_flag_name.to_string())
33                    .short('r')
34                    .usage("AWS region")
35                    .value_type(FlagType::Choice(vec![
36                        "us-east-1".to_string(),
37                        "us-west-2".to_string(),
38                        "eu-west-1".to_string(),
39                        "ap-southeast-1".to_string(),
40                    ]))
41                    .default(flag_rs::FlagValue::String("us-east-1".to_string())),
42            )
43            .flag(
44                Flag::new(env_flag_name.to_string())
45                    .short('e')
46                    .usage("Deployment environment")
47                    .value_type(FlagType::Choice(vec![
48                        "dev".to_string(),
49                        "staging".to_string(),
50                        "prod".to_string(),
51                    ]))
52                    .default(flag_rs::FlagValue::String("dev".to_string())),
53            )
54            .subcommand(
55                CommandBuilder::new("deploy")
56                    .short("Deploy the service")
57                    .arg_completion(move |_ctx, prefix| {
58                        // Use optimized completion result
59                        let optimized = CompletionResultOptimized::new()
60                            .add(Cow::Borrowed("rolling-update"))
61                            .add(Cow::Borrowed("blue-green"))
62                            .add(Cow::Borrowed("canary"))
63                            .add_with_description(
64                                Cow::Borrowed("recreate"),
65                                Cow::Borrowed("Recreate all pods"),
66                            );
67
68                        // Filter based on prefix
69                        let filtered = CompletionResultOptimized::new().extend_items(
70                            optimized
71                                .items
72                                .into_iter()
73                                .filter(|item| item.value.starts_with(prefix)),
74                        );
75
76                        // Convert to legacy format for compatibility
77                        Ok(filtered.into_legacy())
78                    })
79                    .build(),
80            )
81            .subcommand(
82                CommandBuilder::new("scale")
83                    .short("Scale the service")
84                    .flag(
85                        Flag::new("replicas")
86                            .usage("Number of replicas")
87                            .value_type(FlagType::Int)
88                            .required(),
89                    )
90                    .build(),
91            )
92            .subcommand(
93                CommandBuilder::new("logs")
94                    .short("View service logs")
95                    .flag(
96                        Flag::new("follow")
97                            .short('f')
98                            .usage("Follow log output")
99                            .value_type(FlagType::Bool),
100                    )
101                    .flag(
102                        Flag::new("tail")
103                            .usage("Number of lines to show")
104                            .value_type(FlagType::Int)
105                            .default(flag_rs::FlagValue::Int(100)),
106                    )
107                    .build(),
108            )
109            .build();
110
111        parent.add_command(cmd);
112    }
113}
114
115// Count commands recursively
116fn count_commands(cmd: &flag_rs::Command) -> usize {
117    1 + cmd
118        .subcommands()
119        .values()
120        .map(count_commands)
121        .sum::<usize>()
122}
123
124// Count flags recursively
125fn count_flags(cmd: &flag_rs::Command) -> usize {
126    cmd.flags().len() + cmd.subcommands().values().map(count_flags).sum::<usize>()
127}
128
129fn main() {
130    // Create root command
131    let mut app = CommandBuilder::new("megacli")
132        .short("A large CLI demonstrating memory optimizations")
133        .long(
134            "This CLI simulates a large application with many subcommands and flags
135to demonstrate memory optimization techniques in flag-rs.
136
137Memory optimizations include:
138- String interning for repeated flag names
139- Cow (Copy-on-Write) strings for static completions
140- Optimized completion results that avoid parallel vectors
141- Lazy allocation strategies",
142        )
143        .flag(
144            Flag::new("verbose")
145                .short('v')
146                .usage("Enable verbose output")
147                .value_type(FlagType::Bool),
148        )
149        .flag(
150            Flag::new("config")
151                .short('c')
152                .usage("Path to config file")
153                .value_type(FlagType::File)
154                .default(flag_rs::FlagValue::String(
155                    "~/.megacli/config.yaml".to_string(),
156                )),
157        )
158        .build();
159
160    // Add many subcommands
161    create_many_subcommands(&mut app);
162
163    let total_commands = count_commands(&app);
164    let total_flags = count_flags(&app);
165
166    // Add a special command to show memory usage stats
167    app.add_command(
168        CommandBuilder::new("stats")
169            .short("Show CLI statistics and memory usage")
170            .run(move |_ctx| {
171                println!("=== MegaCLI Statistics ===\n");
172
173                println!("Total commands: {total_commands}");
174                println!("Total flags: {total_flags}");
175                println!("String pool size: {} unique strings", 3); // We interned 3 flag names
176
177                println!("\nMemory optimization features in use:");
178                println!("✓ String interning for flag names");
179                println!("✓ Cow<str> for static completion values");
180                println!("✓ CompletionResultOptimized for reduced allocations");
181                println!("✓ Lazy allocation strategies");
182
183                println!("\nEstimated memory savings:");
184                println!("- 60-70% reduction in string allocations");
185                println!("- 40-50% reduction in completion memory usage");
186                println!("- Improved cache locality for better performance");
187
188                Ok(())
189            })
190            .build(),
191    );
192
193    // Execute the CLI
194    let args: Vec<String> = std::env::args().skip(1).collect();
195
196    if args.is_empty() {
197        println!("=== Memory Optimization Demo ===\n");
198        println!("This demo shows how flag-rs optimizes memory for large CLIs.\n");
199        println!("Try these commands:");
200        println!(
201            "  {} stats                    # Show memory statistics",
202            std::env::args().next().unwrap_or_default()
203        );
204        println!(
205            "  {} service-001 deploy <TAB> # Test optimized completions",
206            std::env::args().next().unwrap_or_default()
207        );
208        println!(
209            "  {} --help                   # See all 100+ commands",
210            std::env::args().next().unwrap_or_default()
211        );
212        println!("\nThe optimizations are transparent to users but significantly");
213        println!("reduce memory usage for CLIs with many commands and flags.");
214        std::process::exit(0);
215    }
216
217    if let Err(e) = app.execute(args) {
218        eprintln!("{e}");
219        std::process::exit(1);
220    }
221}
Source

pub fn bool(name: impl Into<String>) -> Self

Creates a new boolean flag

§Examples
use flag_rs::flag::Flag;

let flag = Flag::bool("verbose");
Examples found in repository?
examples/builder_api_demo.rs (line 18)
4fn main() {
5    // Demonstrates all the new builder API improvements
6    let app = CommandBuilder::new("app")
7        .short("Modern CLI app with improved API")
8        .long(
9            "This example showcases the builder API improvements including:\n\
10               - Type-specific flag constructors\n\
11               - Inline flag completions\n\
12               - Bulk flag/subcommand methods\n\
13               - Type-safe context access",
14        )
15        // Bulk flag addition
16        .flags(vec![
17            // Type-specific constructors
18            Flag::bool("verbose")
19                .short('v')
20                .usage("Enable verbose output")
21                .default_bool(false),
22            Flag::bool("quiet").short('q').usage("Suppress all output"),
23            Flag::int("threads")
24                .short('t')
25                .usage("Number of worker threads")
26                .default_int(4),
27            Flag::choice("log-level", &["debug", "info", "warn", "error"])
28                .usage("Set the logging level")
29                .default_str("info")
30                .completion(|_ctx, prefix| {
31                    // Inline completion with descriptions
32                    let levels = vec![
33                        ("debug", "Show all messages including debug"),
34                        ("info", "Show informational messages and above"),
35                        ("warn", "Show warnings and errors only"),
36                        ("error", "Show errors only"),
37                    ];
38
39                    let mut result = flag_rs::CompletionResult::new();
40                    for (level, desc) in levels {
41                        if level.starts_with(prefix) {
42                            result =
43                                result.add_with_description(level.to_string(), desc.to_string());
44                        }
45                    }
46                    Ok(result)
47                }),
48        ])
49        // Bulk subcommand addition
50        .subcommands(vec![
51            CommandBuilder::new("init")
52                .short("Initialize a new project")
53                .flags(vec![
54                    Flag::string("name")
55                        .short('n')
56                        .usage("Project name")
57                        .required(),
58                    Flag::choice("template", &["basic", "web", "api", "full"])
59                        .usage("Project template to use")
60                        .default_str("basic"),
61                    Flag::directory("path")
62                        .short('p')
63                        .usage("Directory to create project in")
64                        .completion(|_ctx, prefix| {
65                            // In a real app, list actual directories
66                            let dirs = vec!["./", "../", "/tmp/", "~/projects/"];
67                            Ok(flag_rs::CompletionResult::new().extend(
68                                dirs.into_iter()
69                                    .filter(|d| d.starts_with(prefix))
70                                    .map(String::from),
71                            ))
72                        }),
73                ])
74                .run(|ctx| {
75                    // Type-safe flag access
76                    let name = ctx.flag_str_or("name", "my-project");
77                    let template = ctx.flag_str_or("template", "basic");
78                    let path = ctx.flag_str_or("path", ".");
79                    let verbose = ctx.flag_bool_or("verbose", false);
80
81                    if verbose {
82                        println!("Initializing {} project '{}' in {}", template, name, path);
83                    } else {
84                        println!("Creating project '{}'...", name);
85                    }
86
87                    Ok(())
88                })
89                .build(),
90            CommandBuilder::new("build")
91                .short("Build the project")
92                .flags(vec![
93                    Flag::bool("release")
94                        .short('r')
95                        .usage("Build in release mode"),
96                    Flag::string_slice("features")
97                        .short('f')
98                        .usage("Enable features (can be specified multiple times)")
99                        .completion(|_ctx, prefix| {
100                            let features = vec!["async", "tls", "compression", "metrics"];
101                            Ok(flag_rs::CompletionResult::new().extend(
102                                features
103                                    .into_iter()
104                                    .filter(|f| f.starts_with(prefix))
105                                    .map(String::from),
106                            ))
107                        }),
108                    Flag::range("jobs", 1, 32)
109                        .short('j')
110                        .usage("Number of parallel jobs")
111                        .default_int(i64::try_from(num_cpus()).unwrap_or(4)),
112                ])
113                .run(|ctx| {
114                    let release = ctx.flag_bool_or("release", false);
115                    let jobs = ctx.flag_int_or("jobs", i64::try_from(num_cpus()).unwrap_or(4));
116                    let quiet = ctx.flag_bool_or("quiet", false);
117
118                    if !quiet {
119                        println!(
120                            "Building in {} mode with {} jobs",
121                            if release { "release" } else { "debug" },
122                            jobs
123                        );
124
125                        if let Some(features) = ctx.flag("features") {
126                            println!("Features: {}", features);
127                        }
128                    }
129
130                    Ok(())
131                })
132                .build(),
133            CommandBuilder::new("test")
134                .short("Run tests")
135                .flags(vec![
136                    Flag::string("filter").usage("Only run tests matching this pattern"),
137                    Flag::bool("nocapture").usage("Don't capture test output"),
138                    Flag::int("test-threads")
139                        .usage("Number of threads to use for running tests")
140                        .default_int(1),
141                ])
142                .run(|ctx| {
143                    let threads = ctx.flag_int_or("test-threads", 1);
144                    let nocapture = ctx.flag_bool_or("nocapture", false);
145                    let verbose = ctx.flag_bool_or("verbose", false);
146
147                    if verbose {
148                        println!("Running tests with {} thread(s)", threads);
149                        if nocapture {
150                            println!("Output capture disabled");
151                        }
152
153                        if let Some(filter) = ctx.flag("filter") {
154                            println!("Filter: {}", filter);
155                        }
156                    }
157
158                    println!("Running tests...");
159                    Ok(())
160                })
161                .build(),
162        ])
163        .run(|_ctx| {
164            // Root command - show help by default
165            println!("Use --help for usage information");
166            Ok(())
167        })
168        .build();
169
170    let args: Vec<String> = std::env::args().skip(1).collect();
171    if let Err(e) = app.execute(args) {
172        eprintln!("Error: {}", e);
173        std::process::exit(1);
174    }
175}
Source

pub fn int(name: impl Into<String>) -> Self

Creates a new integer flag

§Examples
use flag_rs::flag::Flag;

let flag = Flag::int("port");
Examples found in repository?
examples/builder_api_demo.rs (line 23)
4fn main() {
5    // Demonstrates all the new builder API improvements
6    let app = CommandBuilder::new("app")
7        .short("Modern CLI app with improved API")
8        .long(
9            "This example showcases the builder API improvements including:\n\
10               - Type-specific flag constructors\n\
11               - Inline flag completions\n\
12               - Bulk flag/subcommand methods\n\
13               - Type-safe context access",
14        )
15        // Bulk flag addition
16        .flags(vec![
17            // Type-specific constructors
18            Flag::bool("verbose")
19                .short('v')
20                .usage("Enable verbose output")
21                .default_bool(false),
22            Flag::bool("quiet").short('q').usage("Suppress all output"),
23            Flag::int("threads")
24                .short('t')
25                .usage("Number of worker threads")
26                .default_int(4),
27            Flag::choice("log-level", &["debug", "info", "warn", "error"])
28                .usage("Set the logging level")
29                .default_str("info")
30                .completion(|_ctx, prefix| {
31                    // Inline completion with descriptions
32                    let levels = vec![
33                        ("debug", "Show all messages including debug"),
34                        ("info", "Show informational messages and above"),
35                        ("warn", "Show warnings and errors only"),
36                        ("error", "Show errors only"),
37                    ];
38
39                    let mut result = flag_rs::CompletionResult::new();
40                    for (level, desc) in levels {
41                        if level.starts_with(prefix) {
42                            result =
43                                result.add_with_description(level.to_string(), desc.to_string());
44                        }
45                    }
46                    Ok(result)
47                }),
48        ])
49        // Bulk subcommand addition
50        .subcommands(vec![
51            CommandBuilder::new("init")
52                .short("Initialize a new project")
53                .flags(vec![
54                    Flag::string("name")
55                        .short('n')
56                        .usage("Project name")
57                        .required(),
58                    Flag::choice("template", &["basic", "web", "api", "full"])
59                        .usage("Project template to use")
60                        .default_str("basic"),
61                    Flag::directory("path")
62                        .short('p')
63                        .usage("Directory to create project in")
64                        .completion(|_ctx, prefix| {
65                            // In a real app, list actual directories
66                            let dirs = vec!["./", "../", "/tmp/", "~/projects/"];
67                            Ok(flag_rs::CompletionResult::new().extend(
68                                dirs.into_iter()
69                                    .filter(|d| d.starts_with(prefix))
70                                    .map(String::from),
71                            ))
72                        }),
73                ])
74                .run(|ctx| {
75                    // Type-safe flag access
76                    let name = ctx.flag_str_or("name", "my-project");
77                    let template = ctx.flag_str_or("template", "basic");
78                    let path = ctx.flag_str_or("path", ".");
79                    let verbose = ctx.flag_bool_or("verbose", false);
80
81                    if verbose {
82                        println!("Initializing {} project '{}' in {}", template, name, path);
83                    } else {
84                        println!("Creating project '{}'...", name);
85                    }
86
87                    Ok(())
88                })
89                .build(),
90            CommandBuilder::new("build")
91                .short("Build the project")
92                .flags(vec![
93                    Flag::bool("release")
94                        .short('r')
95                        .usage("Build in release mode"),
96                    Flag::string_slice("features")
97                        .short('f')
98                        .usage("Enable features (can be specified multiple times)")
99                        .completion(|_ctx, prefix| {
100                            let features = vec!["async", "tls", "compression", "metrics"];
101                            Ok(flag_rs::CompletionResult::new().extend(
102                                features
103                                    .into_iter()
104                                    .filter(|f| f.starts_with(prefix))
105                                    .map(String::from),
106                            ))
107                        }),
108                    Flag::range("jobs", 1, 32)
109                        .short('j')
110                        .usage("Number of parallel jobs")
111                        .default_int(i64::try_from(num_cpus()).unwrap_or(4)),
112                ])
113                .run(|ctx| {
114                    let release = ctx.flag_bool_or("release", false);
115                    let jobs = ctx.flag_int_or("jobs", i64::try_from(num_cpus()).unwrap_or(4));
116                    let quiet = ctx.flag_bool_or("quiet", false);
117
118                    if !quiet {
119                        println!(
120                            "Building in {} mode with {} jobs",
121                            if release { "release" } else { "debug" },
122                            jobs
123                        );
124
125                        if let Some(features) = ctx.flag("features") {
126                            println!("Features: {}", features);
127                        }
128                    }
129
130                    Ok(())
131                })
132                .build(),
133            CommandBuilder::new("test")
134                .short("Run tests")
135                .flags(vec![
136                    Flag::string("filter").usage("Only run tests matching this pattern"),
137                    Flag::bool("nocapture").usage("Don't capture test output"),
138                    Flag::int("test-threads")
139                        .usage("Number of threads to use for running tests")
140                        .default_int(1),
141                ])
142                .run(|ctx| {
143                    let threads = ctx.flag_int_or("test-threads", 1);
144                    let nocapture = ctx.flag_bool_or("nocapture", false);
145                    let verbose = ctx.flag_bool_or("verbose", false);
146
147                    if verbose {
148                        println!("Running tests with {} thread(s)", threads);
149                        if nocapture {
150                            println!("Output capture disabled");
151                        }
152
153                        if let Some(filter) = ctx.flag("filter") {
154                            println!("Filter: {}", filter);
155                        }
156                    }
157
158                    println!("Running tests...");
159                    Ok(())
160                })
161                .build(),
162        ])
163        .run(|_ctx| {
164            // Root command - show help by default
165            println!("Use --help for usage information");
166            Ok(())
167        })
168        .build();
169
170    let args: Vec<String> = std::env::args().skip(1).collect();
171    if let Err(e) = app.execute(args) {
172        eprintln!("Error: {}", e);
173        std::process::exit(1);
174    }
175}
Source

pub fn float(name: impl Into<String>) -> Self

Creates a new float flag

§Examples
use flag_rs::flag::Flag;

let flag = Flag::float("ratio");
Source

pub fn string(name: impl Into<String>) -> Self

Creates a new string flag

§Examples
use flag_rs::flag::Flag;

let flag = Flag::string("name");
Examples found in repository?
examples/builder_api_demo.rs (line 54)
4fn main() {
5    // Demonstrates all the new builder API improvements
6    let app = CommandBuilder::new("app")
7        .short("Modern CLI app with improved API")
8        .long(
9            "This example showcases the builder API improvements including:\n\
10               - Type-specific flag constructors\n\
11               - Inline flag completions\n\
12               - Bulk flag/subcommand methods\n\
13               - Type-safe context access",
14        )
15        // Bulk flag addition
16        .flags(vec![
17            // Type-specific constructors
18            Flag::bool("verbose")
19                .short('v')
20                .usage("Enable verbose output")
21                .default_bool(false),
22            Flag::bool("quiet").short('q').usage("Suppress all output"),
23            Flag::int("threads")
24                .short('t')
25                .usage("Number of worker threads")
26                .default_int(4),
27            Flag::choice("log-level", &["debug", "info", "warn", "error"])
28                .usage("Set the logging level")
29                .default_str("info")
30                .completion(|_ctx, prefix| {
31                    // Inline completion with descriptions
32                    let levels = vec![
33                        ("debug", "Show all messages including debug"),
34                        ("info", "Show informational messages and above"),
35                        ("warn", "Show warnings and errors only"),
36                        ("error", "Show errors only"),
37                    ];
38
39                    let mut result = flag_rs::CompletionResult::new();
40                    for (level, desc) in levels {
41                        if level.starts_with(prefix) {
42                            result =
43                                result.add_with_description(level.to_string(), desc.to_string());
44                        }
45                    }
46                    Ok(result)
47                }),
48        ])
49        // Bulk subcommand addition
50        .subcommands(vec![
51            CommandBuilder::new("init")
52                .short("Initialize a new project")
53                .flags(vec![
54                    Flag::string("name")
55                        .short('n')
56                        .usage("Project name")
57                        .required(),
58                    Flag::choice("template", &["basic", "web", "api", "full"])
59                        .usage("Project template to use")
60                        .default_str("basic"),
61                    Flag::directory("path")
62                        .short('p')
63                        .usage("Directory to create project in")
64                        .completion(|_ctx, prefix| {
65                            // In a real app, list actual directories
66                            let dirs = vec!["./", "../", "/tmp/", "~/projects/"];
67                            Ok(flag_rs::CompletionResult::new().extend(
68                                dirs.into_iter()
69                                    .filter(|d| d.starts_with(prefix))
70                                    .map(String::from),
71                            ))
72                        }),
73                ])
74                .run(|ctx| {
75                    // Type-safe flag access
76                    let name = ctx.flag_str_or("name", "my-project");
77                    let template = ctx.flag_str_or("template", "basic");
78                    let path = ctx.flag_str_or("path", ".");
79                    let verbose = ctx.flag_bool_or("verbose", false);
80
81                    if verbose {
82                        println!("Initializing {} project '{}' in {}", template, name, path);
83                    } else {
84                        println!("Creating project '{}'...", name);
85                    }
86
87                    Ok(())
88                })
89                .build(),
90            CommandBuilder::new("build")
91                .short("Build the project")
92                .flags(vec![
93                    Flag::bool("release")
94                        .short('r')
95                        .usage("Build in release mode"),
96                    Flag::string_slice("features")
97                        .short('f')
98                        .usage("Enable features (can be specified multiple times)")
99                        .completion(|_ctx, prefix| {
100                            let features = vec!["async", "tls", "compression", "metrics"];
101                            Ok(flag_rs::CompletionResult::new().extend(
102                                features
103                                    .into_iter()
104                                    .filter(|f| f.starts_with(prefix))
105                                    .map(String::from),
106                            ))
107                        }),
108                    Flag::range("jobs", 1, 32)
109                        .short('j')
110                        .usage("Number of parallel jobs")
111                        .default_int(i64::try_from(num_cpus()).unwrap_or(4)),
112                ])
113                .run(|ctx| {
114                    let release = ctx.flag_bool_or("release", false);
115                    let jobs = ctx.flag_int_or("jobs", i64::try_from(num_cpus()).unwrap_or(4));
116                    let quiet = ctx.flag_bool_or("quiet", false);
117
118                    if !quiet {
119                        println!(
120                            "Building in {} mode with {} jobs",
121                            if release { "release" } else { "debug" },
122                            jobs
123                        );
124
125                        if let Some(features) = ctx.flag("features") {
126                            println!("Features: {}", features);
127                        }
128                    }
129
130                    Ok(())
131                })
132                .build(),
133            CommandBuilder::new("test")
134                .short("Run tests")
135                .flags(vec![
136                    Flag::string("filter").usage("Only run tests matching this pattern"),
137                    Flag::bool("nocapture").usage("Don't capture test output"),
138                    Flag::int("test-threads")
139                        .usage("Number of threads to use for running tests")
140                        .default_int(1),
141                ])
142                .run(|ctx| {
143                    let threads = ctx.flag_int_or("test-threads", 1);
144                    let nocapture = ctx.flag_bool_or("nocapture", false);
145                    let verbose = ctx.flag_bool_or("verbose", false);
146
147                    if verbose {
148                        println!("Running tests with {} thread(s)", threads);
149                        if nocapture {
150                            println!("Output capture disabled");
151                        }
152
153                        if let Some(filter) = ctx.flag("filter") {
154                            println!("Filter: {}", filter);
155                        }
156                    }
157
158                    println!("Running tests...");
159                    Ok(())
160                })
161                .build(),
162        ])
163        .run(|_ctx| {
164            // Root command - show help by default
165            println!("Use --help for usage information");
166            Ok(())
167        })
168        .build();
169
170    let args: Vec<String> = std::env::args().skip(1).collect();
171    if let Err(e) = app.execute(args) {
172        eprintln!("Error: {}", e);
173        std::process::exit(1);
174    }
175}
Source

pub fn string_slice(name: impl Into<String>) -> Self

Creates a new string slice flag (can be specified multiple times)

§Examples
use flag_rs::flag::Flag;

let flag = Flag::string_slice("tag");
Examples found in repository?
examples/flag_completion_demo.rs (line 74)
4fn main() {
5    let app = CommandBuilder::new("deploy")
6        .short("Deploy application to various environments")
7        .flag(
8            Flag::choice("environment", &["dev", "staging", "prod"])
9                .short('e')
10                .usage("Target environment")
11                .required()
12                .completion(|_ctx, prefix| {
13                    // Dynamic completion - could check available environments
14                    let environments = vec![
15                        ("dev", "Development environment"),
16                        ("staging", "Staging environment (pre-production)"),
17                        ("prod", "Production environment"),
18                    ];
19
20                    let mut result = CompletionResult::new();
21                    for (env, desc) in environments {
22                        if env.starts_with(prefix) {
23                            result = result.add_with_description(env.to_string(), desc.to_string());
24                        }
25                    }
26
27                    // Add active help if no prefix
28                    if prefix.is_empty() {
29                        result = result.add_help_text("Available environments: dev, staging, prod");
30                    }
31
32                    Ok(result)
33                }),
34        )
35        .flag(
36            Flag::file("config")
37                .short('c')
38                .usage("Configuration file")
39                .default_str("config.yaml")
40                .completion(|_ctx, prefix| {
41                    // In a real app, you might list files in the config directory
42                    let configs = vec![
43                        "config.yaml",
44                        "config.dev.yaml",
45                        "config.staging.yaml",
46                        "config.prod.yaml",
47                        "secrets.yaml",
48                    ];
49
50                    Ok(CompletionResult::new().extend(
51                        configs
52                            .into_iter()
53                            .filter(|c| c.starts_with(prefix))
54                            .map(String::from),
55                    ))
56                }),
57        )
58        .flag(
59            Flag::directory("output")
60                .short('o')
61                .usage("Output directory for deployment artifacts")
62                .completion(|_ctx, prefix| {
63                    // In a real app, you might list actual directories
64                    let dirs = vec!["./build", "./dist", "./output", "/tmp/deploy"];
65
66                    Ok(CompletionResult::new().extend(
67                        dirs.into_iter()
68                            .filter(|d| d.starts_with(prefix))
69                            .map(String::from),
70                    ))
71                }),
72        )
73        .flag(
74            Flag::string_slice("service")
75                .short('s')
76                .usage("Services to deploy (can be specified multiple times)")
77                .completion(|ctx, prefix| {
78                    // Context-aware completion based on environment
79                    let env = ctx.flag_str_or("environment", "dev");
80
81                    let services = match env {
82                        "dev" => vec!["api", "web", "worker", "scheduler", "debug-panel"],
83                        "staging" => vec!["api", "web", "worker", "scheduler"],
84                        "prod" => vec!["api", "web", "worker"],
85                        _ => vec!["api", "web"],
86                    };
87
88                    let mut result = CompletionResult::new().extend(
89                        services
90                            .into_iter()
91                            .filter(|s| s.starts_with(prefix))
92                            .map(String::from),
93                    );
94
95                    // Add context-aware help
96                    if prefix.is_empty() {
97                        result = result
98                            .add_help_text(format!("Available services for {} environment", env));
99                    }
100
101                    Ok(result)
102                }),
103        )
104        .flag(
105            Flag::range("replicas", 1, 10)
106                .short('r')
107                .usage("Number of replicas to deploy")
108                .default_int(2)
109                .completion(|_ctx, _prefix| {
110                    // Suggest common replica counts
111                    Ok(CompletionResult::new()
112                        .add_with_description(
113                            "1".to_string(),
114                            "Single instance (dev/test)".to_string(),
115                        )
116                        .add_with_description("2".to_string(), "Basic redundancy".to_string())
117                        .add_with_description("3".to_string(), "Standard production".to_string())
118                        .add_with_description("5".to_string(), "High availability".to_string()))
119                }),
120        )
121        .run(|ctx| {
122            let env = ctx.flag_str_or("environment", "dev");
123            let config = ctx.flag_str_or("config", "config.yaml");
124            let replicas = ctx.flag_int_or("replicas", 2);
125
126            println!("Deploying to {} environment", env);
127            println!("Using configuration: {}", config);
128            println!("Replica count: {}", replicas);
129
130            if let Some(output) = ctx.flag("output") {
131                println!("Output directory: {}", output);
132            }
133
134            if let Some(services) = ctx.flag("service") {
135                println!("Deploying services: {}", services);
136            } else {
137                println!("Deploying all services");
138            }
139
140            Ok(())
141        })
142        .build();
143
144    let args: Vec<String> = std::env::args().skip(1).collect();
145    if let Err(e) = app.execute(args) {
146        eprintln!("Error: {}", e);
147        std::process::exit(1);
148    }
149}
More examples
Hide additional examples
examples/builder_api_demo.rs (line 96)
4fn main() {
5    // Demonstrates all the new builder API improvements
6    let app = CommandBuilder::new("app")
7        .short("Modern CLI app with improved API")
8        .long(
9            "This example showcases the builder API improvements including:\n\
10               - Type-specific flag constructors\n\
11               - Inline flag completions\n\
12               - Bulk flag/subcommand methods\n\
13               - Type-safe context access",
14        )
15        // Bulk flag addition
16        .flags(vec![
17            // Type-specific constructors
18            Flag::bool("verbose")
19                .short('v')
20                .usage("Enable verbose output")
21                .default_bool(false),
22            Flag::bool("quiet").short('q').usage("Suppress all output"),
23            Flag::int("threads")
24                .short('t')
25                .usage("Number of worker threads")
26                .default_int(4),
27            Flag::choice("log-level", &["debug", "info", "warn", "error"])
28                .usage("Set the logging level")
29                .default_str("info")
30                .completion(|_ctx, prefix| {
31                    // Inline completion with descriptions
32                    let levels = vec![
33                        ("debug", "Show all messages including debug"),
34                        ("info", "Show informational messages and above"),
35                        ("warn", "Show warnings and errors only"),
36                        ("error", "Show errors only"),
37                    ];
38
39                    let mut result = flag_rs::CompletionResult::new();
40                    for (level, desc) in levels {
41                        if level.starts_with(prefix) {
42                            result =
43                                result.add_with_description(level.to_string(), desc.to_string());
44                        }
45                    }
46                    Ok(result)
47                }),
48        ])
49        // Bulk subcommand addition
50        .subcommands(vec![
51            CommandBuilder::new("init")
52                .short("Initialize a new project")
53                .flags(vec![
54                    Flag::string("name")
55                        .short('n')
56                        .usage("Project name")
57                        .required(),
58                    Flag::choice("template", &["basic", "web", "api", "full"])
59                        .usage("Project template to use")
60                        .default_str("basic"),
61                    Flag::directory("path")
62                        .short('p')
63                        .usage("Directory to create project in")
64                        .completion(|_ctx, prefix| {
65                            // In a real app, list actual directories
66                            let dirs = vec!["./", "../", "/tmp/", "~/projects/"];
67                            Ok(flag_rs::CompletionResult::new().extend(
68                                dirs.into_iter()
69                                    .filter(|d| d.starts_with(prefix))
70                                    .map(String::from),
71                            ))
72                        }),
73                ])
74                .run(|ctx| {
75                    // Type-safe flag access
76                    let name = ctx.flag_str_or("name", "my-project");
77                    let template = ctx.flag_str_or("template", "basic");
78                    let path = ctx.flag_str_or("path", ".");
79                    let verbose = ctx.flag_bool_or("verbose", false);
80
81                    if verbose {
82                        println!("Initializing {} project '{}' in {}", template, name, path);
83                    } else {
84                        println!("Creating project '{}'...", name);
85                    }
86
87                    Ok(())
88                })
89                .build(),
90            CommandBuilder::new("build")
91                .short("Build the project")
92                .flags(vec![
93                    Flag::bool("release")
94                        .short('r')
95                        .usage("Build in release mode"),
96                    Flag::string_slice("features")
97                        .short('f')
98                        .usage("Enable features (can be specified multiple times)")
99                        .completion(|_ctx, prefix| {
100                            let features = vec!["async", "tls", "compression", "metrics"];
101                            Ok(flag_rs::CompletionResult::new().extend(
102                                features
103                                    .into_iter()
104                                    .filter(|f| f.starts_with(prefix))
105                                    .map(String::from),
106                            ))
107                        }),
108                    Flag::range("jobs", 1, 32)
109                        .short('j')
110                        .usage("Number of parallel jobs")
111                        .default_int(i64::try_from(num_cpus()).unwrap_or(4)),
112                ])
113                .run(|ctx| {
114                    let release = ctx.flag_bool_or("release", false);
115                    let jobs = ctx.flag_int_or("jobs", i64::try_from(num_cpus()).unwrap_or(4));
116                    let quiet = ctx.flag_bool_or("quiet", false);
117
118                    if !quiet {
119                        println!(
120                            "Building in {} mode with {} jobs",
121                            if release { "release" } else { "debug" },
122                            jobs
123                        );
124
125                        if let Some(features) = ctx.flag("features") {
126                            println!("Features: {}", features);
127                        }
128                    }
129
130                    Ok(())
131                })
132                .build(),
133            CommandBuilder::new("test")
134                .short("Run tests")
135                .flags(vec![
136                    Flag::string("filter").usage("Only run tests matching this pattern"),
137                    Flag::bool("nocapture").usage("Don't capture test output"),
138                    Flag::int("test-threads")
139                        .usage("Number of threads to use for running tests")
140                        .default_int(1),
141                ])
142                .run(|ctx| {
143                    let threads = ctx.flag_int_or("test-threads", 1);
144                    let nocapture = ctx.flag_bool_or("nocapture", false);
145                    let verbose = ctx.flag_bool_or("verbose", false);
146
147                    if verbose {
148                        println!("Running tests with {} thread(s)", threads);
149                        if nocapture {
150                            println!("Output capture disabled");
151                        }
152
153                        if let Some(filter) = ctx.flag("filter") {
154                            println!("Filter: {}", filter);
155                        }
156                    }
157
158                    println!("Running tests...");
159                    Ok(())
160                })
161                .build(),
162        ])
163        .run(|_ctx| {
164            // Root command - show help by default
165            println!("Use --help for usage information");
166            Ok(())
167        })
168        .build();
169
170    let args: Vec<String> = std::env::args().skip(1).collect();
171    if let Err(e) = app.execute(args) {
172        eprintln!("Error: {}", e);
173        std::process::exit(1);
174    }
175}
Source

pub fn choice(name: impl Into<String>, choices: &[&str]) -> Self

Creates a new choice flag with allowed values

§Examples
use flag_rs::flag::Flag;

let flag = Flag::choice("format", &["json", "yaml", "xml"]);
Examples found in repository?
examples/flag_completion_demo.rs (line 8)
4fn main() {
5    let app = CommandBuilder::new("deploy")
6        .short("Deploy application to various environments")
7        .flag(
8            Flag::choice("environment", &["dev", "staging", "prod"])
9                .short('e')
10                .usage("Target environment")
11                .required()
12                .completion(|_ctx, prefix| {
13                    // Dynamic completion - could check available environments
14                    let environments = vec![
15                        ("dev", "Development environment"),
16                        ("staging", "Staging environment (pre-production)"),
17                        ("prod", "Production environment"),
18                    ];
19
20                    let mut result = CompletionResult::new();
21                    for (env, desc) in environments {
22                        if env.starts_with(prefix) {
23                            result = result.add_with_description(env.to_string(), desc.to_string());
24                        }
25                    }
26
27                    // Add active help if no prefix
28                    if prefix.is_empty() {
29                        result = result.add_help_text("Available environments: dev, staging, prod");
30                    }
31
32                    Ok(result)
33                }),
34        )
35        .flag(
36            Flag::file("config")
37                .short('c')
38                .usage("Configuration file")
39                .default_str("config.yaml")
40                .completion(|_ctx, prefix| {
41                    // In a real app, you might list files in the config directory
42                    let configs = vec![
43                        "config.yaml",
44                        "config.dev.yaml",
45                        "config.staging.yaml",
46                        "config.prod.yaml",
47                        "secrets.yaml",
48                    ];
49
50                    Ok(CompletionResult::new().extend(
51                        configs
52                            .into_iter()
53                            .filter(|c| c.starts_with(prefix))
54                            .map(String::from),
55                    ))
56                }),
57        )
58        .flag(
59            Flag::directory("output")
60                .short('o')
61                .usage("Output directory for deployment artifacts")
62                .completion(|_ctx, prefix| {
63                    // In a real app, you might list actual directories
64                    let dirs = vec!["./build", "./dist", "./output", "/tmp/deploy"];
65
66                    Ok(CompletionResult::new().extend(
67                        dirs.into_iter()
68                            .filter(|d| d.starts_with(prefix))
69                            .map(String::from),
70                    ))
71                }),
72        )
73        .flag(
74            Flag::string_slice("service")
75                .short('s')
76                .usage("Services to deploy (can be specified multiple times)")
77                .completion(|ctx, prefix| {
78                    // Context-aware completion based on environment
79                    let env = ctx.flag_str_or("environment", "dev");
80
81                    let services = match env {
82                        "dev" => vec!["api", "web", "worker", "scheduler", "debug-panel"],
83                        "staging" => vec!["api", "web", "worker", "scheduler"],
84                        "prod" => vec!["api", "web", "worker"],
85                        _ => vec!["api", "web"],
86                    };
87
88                    let mut result = CompletionResult::new().extend(
89                        services
90                            .into_iter()
91                            .filter(|s| s.starts_with(prefix))
92                            .map(String::from),
93                    );
94
95                    // Add context-aware help
96                    if prefix.is_empty() {
97                        result = result
98                            .add_help_text(format!("Available services for {} environment", env));
99                    }
100
101                    Ok(result)
102                }),
103        )
104        .flag(
105            Flag::range("replicas", 1, 10)
106                .short('r')
107                .usage("Number of replicas to deploy")
108                .default_int(2)
109                .completion(|_ctx, _prefix| {
110                    // Suggest common replica counts
111                    Ok(CompletionResult::new()
112                        .add_with_description(
113                            "1".to_string(),
114                            "Single instance (dev/test)".to_string(),
115                        )
116                        .add_with_description("2".to_string(), "Basic redundancy".to_string())
117                        .add_with_description("3".to_string(), "Standard production".to_string())
118                        .add_with_description("5".to_string(), "High availability".to_string()))
119                }),
120        )
121        .run(|ctx| {
122            let env = ctx.flag_str_or("environment", "dev");
123            let config = ctx.flag_str_or("config", "config.yaml");
124            let replicas = ctx.flag_int_or("replicas", 2);
125
126            println!("Deploying to {} environment", env);
127            println!("Using configuration: {}", config);
128            println!("Replica count: {}", replicas);
129
130            if let Some(output) = ctx.flag("output") {
131                println!("Output directory: {}", output);
132            }
133
134            if let Some(services) = ctx.flag("service") {
135                println!("Deploying services: {}", services);
136            } else {
137                println!("Deploying all services");
138            }
139
140            Ok(())
141        })
142        .build();
143
144    let args: Vec<String> = std::env::args().skip(1).collect();
145    if let Err(e) = app.execute(args) {
146        eprintln!("Error: {}", e);
147        std::process::exit(1);
148    }
149}
More examples
Hide additional examples
examples/builder_api_demo.rs (line 27)
4fn main() {
5    // Demonstrates all the new builder API improvements
6    let app = CommandBuilder::new("app")
7        .short("Modern CLI app with improved API")
8        .long(
9            "This example showcases the builder API improvements including:\n\
10               - Type-specific flag constructors\n\
11               - Inline flag completions\n\
12               - Bulk flag/subcommand methods\n\
13               - Type-safe context access",
14        )
15        // Bulk flag addition
16        .flags(vec![
17            // Type-specific constructors
18            Flag::bool("verbose")
19                .short('v')
20                .usage("Enable verbose output")
21                .default_bool(false),
22            Flag::bool("quiet").short('q').usage("Suppress all output"),
23            Flag::int("threads")
24                .short('t')
25                .usage("Number of worker threads")
26                .default_int(4),
27            Flag::choice("log-level", &["debug", "info", "warn", "error"])
28                .usage("Set the logging level")
29                .default_str("info")
30                .completion(|_ctx, prefix| {
31                    // Inline completion with descriptions
32                    let levels = vec![
33                        ("debug", "Show all messages including debug"),
34                        ("info", "Show informational messages and above"),
35                        ("warn", "Show warnings and errors only"),
36                        ("error", "Show errors only"),
37                    ];
38
39                    let mut result = flag_rs::CompletionResult::new();
40                    for (level, desc) in levels {
41                        if level.starts_with(prefix) {
42                            result =
43                                result.add_with_description(level.to_string(), desc.to_string());
44                        }
45                    }
46                    Ok(result)
47                }),
48        ])
49        // Bulk subcommand addition
50        .subcommands(vec![
51            CommandBuilder::new("init")
52                .short("Initialize a new project")
53                .flags(vec![
54                    Flag::string("name")
55                        .short('n')
56                        .usage("Project name")
57                        .required(),
58                    Flag::choice("template", &["basic", "web", "api", "full"])
59                        .usage("Project template to use")
60                        .default_str("basic"),
61                    Flag::directory("path")
62                        .short('p')
63                        .usage("Directory to create project in")
64                        .completion(|_ctx, prefix| {
65                            // In a real app, list actual directories
66                            let dirs = vec!["./", "../", "/tmp/", "~/projects/"];
67                            Ok(flag_rs::CompletionResult::new().extend(
68                                dirs.into_iter()
69                                    .filter(|d| d.starts_with(prefix))
70                                    .map(String::from),
71                            ))
72                        }),
73                ])
74                .run(|ctx| {
75                    // Type-safe flag access
76                    let name = ctx.flag_str_or("name", "my-project");
77                    let template = ctx.flag_str_or("template", "basic");
78                    let path = ctx.flag_str_or("path", ".");
79                    let verbose = ctx.flag_bool_or("verbose", false);
80
81                    if verbose {
82                        println!("Initializing {} project '{}' in {}", template, name, path);
83                    } else {
84                        println!("Creating project '{}'...", name);
85                    }
86
87                    Ok(())
88                })
89                .build(),
90            CommandBuilder::new("build")
91                .short("Build the project")
92                .flags(vec![
93                    Flag::bool("release")
94                        .short('r')
95                        .usage("Build in release mode"),
96                    Flag::string_slice("features")
97                        .short('f')
98                        .usage("Enable features (can be specified multiple times)")
99                        .completion(|_ctx, prefix| {
100                            let features = vec!["async", "tls", "compression", "metrics"];
101                            Ok(flag_rs::CompletionResult::new().extend(
102                                features
103                                    .into_iter()
104                                    .filter(|f| f.starts_with(prefix))
105                                    .map(String::from),
106                            ))
107                        }),
108                    Flag::range("jobs", 1, 32)
109                        .short('j')
110                        .usage("Number of parallel jobs")
111                        .default_int(i64::try_from(num_cpus()).unwrap_or(4)),
112                ])
113                .run(|ctx| {
114                    let release = ctx.flag_bool_or("release", false);
115                    let jobs = ctx.flag_int_or("jobs", i64::try_from(num_cpus()).unwrap_or(4));
116                    let quiet = ctx.flag_bool_or("quiet", false);
117
118                    if !quiet {
119                        println!(
120                            "Building in {} mode with {} jobs",
121                            if release { "release" } else { "debug" },
122                            jobs
123                        );
124
125                        if let Some(features) = ctx.flag("features") {
126                            println!("Features: {}", features);
127                        }
128                    }
129
130                    Ok(())
131                })
132                .build(),
133            CommandBuilder::new("test")
134                .short("Run tests")
135                .flags(vec![
136                    Flag::string("filter").usage("Only run tests matching this pattern"),
137                    Flag::bool("nocapture").usage("Don't capture test output"),
138                    Flag::int("test-threads")
139                        .usage("Number of threads to use for running tests")
140                        .default_int(1),
141                ])
142                .run(|ctx| {
143                    let threads = ctx.flag_int_or("test-threads", 1);
144                    let nocapture = ctx.flag_bool_or("nocapture", false);
145                    let verbose = ctx.flag_bool_or("verbose", false);
146
147                    if verbose {
148                        println!("Running tests with {} thread(s)", threads);
149                        if nocapture {
150                            println!("Output capture disabled");
151                        }
152
153                        if let Some(filter) = ctx.flag("filter") {
154                            println!("Filter: {}", filter);
155                        }
156                    }
157
158                    println!("Running tests...");
159                    Ok(())
160                })
161                .build(),
162        ])
163        .run(|_ctx| {
164            // Root command - show help by default
165            println!("Use --help for usage information");
166            Ok(())
167        })
168        .build();
169
170    let args: Vec<String> = std::env::args().skip(1).collect();
171    if let Err(e) = app.execute(args) {
172        eprintln!("Error: {}", e);
173        std::process::exit(1);
174    }
175}
Source

pub fn range(name: impl Into<String>, min: i64, max: i64) -> Self

Creates a new range flag with min and max values

§Examples
use flag_rs::flag::Flag;

let flag = Flag::range("workers", 1, 16);
Examples found in repository?
examples/flag_completion_demo.rs (line 105)
4fn main() {
5    let app = CommandBuilder::new("deploy")
6        .short("Deploy application to various environments")
7        .flag(
8            Flag::choice("environment", &["dev", "staging", "prod"])
9                .short('e')
10                .usage("Target environment")
11                .required()
12                .completion(|_ctx, prefix| {
13                    // Dynamic completion - could check available environments
14                    let environments = vec![
15                        ("dev", "Development environment"),
16                        ("staging", "Staging environment (pre-production)"),
17                        ("prod", "Production environment"),
18                    ];
19
20                    let mut result = CompletionResult::new();
21                    for (env, desc) in environments {
22                        if env.starts_with(prefix) {
23                            result = result.add_with_description(env.to_string(), desc.to_string());
24                        }
25                    }
26
27                    // Add active help if no prefix
28                    if prefix.is_empty() {
29                        result = result.add_help_text("Available environments: dev, staging, prod");
30                    }
31
32                    Ok(result)
33                }),
34        )
35        .flag(
36            Flag::file("config")
37                .short('c')
38                .usage("Configuration file")
39                .default_str("config.yaml")
40                .completion(|_ctx, prefix| {
41                    // In a real app, you might list files in the config directory
42                    let configs = vec![
43                        "config.yaml",
44                        "config.dev.yaml",
45                        "config.staging.yaml",
46                        "config.prod.yaml",
47                        "secrets.yaml",
48                    ];
49
50                    Ok(CompletionResult::new().extend(
51                        configs
52                            .into_iter()
53                            .filter(|c| c.starts_with(prefix))
54                            .map(String::from),
55                    ))
56                }),
57        )
58        .flag(
59            Flag::directory("output")
60                .short('o')
61                .usage("Output directory for deployment artifacts")
62                .completion(|_ctx, prefix| {
63                    // In a real app, you might list actual directories
64                    let dirs = vec!["./build", "./dist", "./output", "/tmp/deploy"];
65
66                    Ok(CompletionResult::new().extend(
67                        dirs.into_iter()
68                            .filter(|d| d.starts_with(prefix))
69                            .map(String::from),
70                    ))
71                }),
72        )
73        .flag(
74            Flag::string_slice("service")
75                .short('s')
76                .usage("Services to deploy (can be specified multiple times)")
77                .completion(|ctx, prefix| {
78                    // Context-aware completion based on environment
79                    let env = ctx.flag_str_or("environment", "dev");
80
81                    let services = match env {
82                        "dev" => vec!["api", "web", "worker", "scheduler", "debug-panel"],
83                        "staging" => vec!["api", "web", "worker", "scheduler"],
84                        "prod" => vec!["api", "web", "worker"],
85                        _ => vec!["api", "web"],
86                    };
87
88                    let mut result = CompletionResult::new().extend(
89                        services
90                            .into_iter()
91                            .filter(|s| s.starts_with(prefix))
92                            .map(String::from),
93                    );
94
95                    // Add context-aware help
96                    if prefix.is_empty() {
97                        result = result
98                            .add_help_text(format!("Available services for {} environment", env));
99                    }
100
101                    Ok(result)
102                }),
103        )
104        .flag(
105            Flag::range("replicas", 1, 10)
106                .short('r')
107                .usage("Number of replicas to deploy")
108                .default_int(2)
109                .completion(|_ctx, _prefix| {
110                    // Suggest common replica counts
111                    Ok(CompletionResult::new()
112                        .add_with_description(
113                            "1".to_string(),
114                            "Single instance (dev/test)".to_string(),
115                        )
116                        .add_with_description("2".to_string(), "Basic redundancy".to_string())
117                        .add_with_description("3".to_string(), "Standard production".to_string())
118                        .add_with_description("5".to_string(), "High availability".to_string()))
119                }),
120        )
121        .run(|ctx| {
122            let env = ctx.flag_str_or("environment", "dev");
123            let config = ctx.flag_str_or("config", "config.yaml");
124            let replicas = ctx.flag_int_or("replicas", 2);
125
126            println!("Deploying to {} environment", env);
127            println!("Using configuration: {}", config);
128            println!("Replica count: {}", replicas);
129
130            if let Some(output) = ctx.flag("output") {
131                println!("Output directory: {}", output);
132            }
133
134            if let Some(services) = ctx.flag("service") {
135                println!("Deploying services: {}", services);
136            } else {
137                println!("Deploying all services");
138            }
139
140            Ok(())
141        })
142        .build();
143
144    let args: Vec<String> = std::env::args().skip(1).collect();
145    if let Err(e) = app.execute(args) {
146        eprintln!("Error: {}", e);
147        std::process::exit(1);
148    }
149}
More examples
Hide additional examples
examples/builder_api_demo.rs (line 108)
4fn main() {
5    // Demonstrates all the new builder API improvements
6    let app = CommandBuilder::new("app")
7        .short("Modern CLI app with improved API")
8        .long(
9            "This example showcases the builder API improvements including:\n\
10               - Type-specific flag constructors\n\
11               - Inline flag completions\n\
12               - Bulk flag/subcommand methods\n\
13               - Type-safe context access",
14        )
15        // Bulk flag addition
16        .flags(vec![
17            // Type-specific constructors
18            Flag::bool("verbose")
19                .short('v')
20                .usage("Enable verbose output")
21                .default_bool(false),
22            Flag::bool("quiet").short('q').usage("Suppress all output"),
23            Flag::int("threads")
24                .short('t')
25                .usage("Number of worker threads")
26                .default_int(4),
27            Flag::choice("log-level", &["debug", "info", "warn", "error"])
28                .usage("Set the logging level")
29                .default_str("info")
30                .completion(|_ctx, prefix| {
31                    // Inline completion with descriptions
32                    let levels = vec![
33                        ("debug", "Show all messages including debug"),
34                        ("info", "Show informational messages and above"),
35                        ("warn", "Show warnings and errors only"),
36                        ("error", "Show errors only"),
37                    ];
38
39                    let mut result = flag_rs::CompletionResult::new();
40                    for (level, desc) in levels {
41                        if level.starts_with(prefix) {
42                            result =
43                                result.add_with_description(level.to_string(), desc.to_string());
44                        }
45                    }
46                    Ok(result)
47                }),
48        ])
49        // Bulk subcommand addition
50        .subcommands(vec![
51            CommandBuilder::new("init")
52                .short("Initialize a new project")
53                .flags(vec![
54                    Flag::string("name")
55                        .short('n')
56                        .usage("Project name")
57                        .required(),
58                    Flag::choice("template", &["basic", "web", "api", "full"])
59                        .usage("Project template to use")
60                        .default_str("basic"),
61                    Flag::directory("path")
62                        .short('p')
63                        .usage("Directory to create project in")
64                        .completion(|_ctx, prefix| {
65                            // In a real app, list actual directories
66                            let dirs = vec!["./", "../", "/tmp/", "~/projects/"];
67                            Ok(flag_rs::CompletionResult::new().extend(
68                                dirs.into_iter()
69                                    .filter(|d| d.starts_with(prefix))
70                                    .map(String::from),
71                            ))
72                        }),
73                ])
74                .run(|ctx| {
75                    // Type-safe flag access
76                    let name = ctx.flag_str_or("name", "my-project");
77                    let template = ctx.flag_str_or("template", "basic");
78                    let path = ctx.flag_str_or("path", ".");
79                    let verbose = ctx.flag_bool_or("verbose", false);
80
81                    if verbose {
82                        println!("Initializing {} project '{}' in {}", template, name, path);
83                    } else {
84                        println!("Creating project '{}'...", name);
85                    }
86
87                    Ok(())
88                })
89                .build(),
90            CommandBuilder::new("build")
91                .short("Build the project")
92                .flags(vec![
93                    Flag::bool("release")
94                        .short('r')
95                        .usage("Build in release mode"),
96                    Flag::string_slice("features")
97                        .short('f')
98                        .usage("Enable features (can be specified multiple times)")
99                        .completion(|_ctx, prefix| {
100                            let features = vec!["async", "tls", "compression", "metrics"];
101                            Ok(flag_rs::CompletionResult::new().extend(
102                                features
103                                    .into_iter()
104                                    .filter(|f| f.starts_with(prefix))
105                                    .map(String::from),
106                            ))
107                        }),
108                    Flag::range("jobs", 1, 32)
109                        .short('j')
110                        .usage("Number of parallel jobs")
111                        .default_int(i64::try_from(num_cpus()).unwrap_or(4)),
112                ])
113                .run(|ctx| {
114                    let release = ctx.flag_bool_or("release", false);
115                    let jobs = ctx.flag_int_or("jobs", i64::try_from(num_cpus()).unwrap_or(4));
116                    let quiet = ctx.flag_bool_or("quiet", false);
117
118                    if !quiet {
119                        println!(
120                            "Building in {} mode with {} jobs",
121                            if release { "release" } else { "debug" },
122                            jobs
123                        );
124
125                        if let Some(features) = ctx.flag("features") {
126                            println!("Features: {}", features);
127                        }
128                    }
129
130                    Ok(())
131                })
132                .build(),
133            CommandBuilder::new("test")
134                .short("Run tests")
135                .flags(vec![
136                    Flag::string("filter").usage("Only run tests matching this pattern"),
137                    Flag::bool("nocapture").usage("Don't capture test output"),
138                    Flag::int("test-threads")
139                        .usage("Number of threads to use for running tests")
140                        .default_int(1),
141                ])
142                .run(|ctx| {
143                    let threads = ctx.flag_int_or("test-threads", 1);
144                    let nocapture = ctx.flag_bool_or("nocapture", false);
145                    let verbose = ctx.flag_bool_or("verbose", false);
146
147                    if verbose {
148                        println!("Running tests with {} thread(s)", threads);
149                        if nocapture {
150                            println!("Output capture disabled");
151                        }
152
153                        if let Some(filter) = ctx.flag("filter") {
154                            println!("Filter: {}", filter);
155                        }
156                    }
157
158                    println!("Running tests...");
159                    Ok(())
160                })
161                .build(),
162        ])
163        .run(|_ctx| {
164            // Root command - show help by default
165            println!("Use --help for usage information");
166            Ok(())
167        })
168        .build();
169
170    let args: Vec<String> = std::env::args().skip(1).collect();
171    if let Err(e) = app.execute(args) {
172        eprintln!("Error: {}", e);
173        std::process::exit(1);
174    }
175}
Source

pub fn file(name: impl Into<String>) -> Self

Creates a new file flag

§Examples
use flag_rs::flag::Flag;

let flag = Flag::file("config");
Examples found in repository?
examples/flag_completion_demo.rs (line 36)
4fn main() {
5    let app = CommandBuilder::new("deploy")
6        .short("Deploy application to various environments")
7        .flag(
8            Flag::choice("environment", &["dev", "staging", "prod"])
9                .short('e')
10                .usage("Target environment")
11                .required()
12                .completion(|_ctx, prefix| {
13                    // Dynamic completion - could check available environments
14                    let environments = vec![
15                        ("dev", "Development environment"),
16                        ("staging", "Staging environment (pre-production)"),
17                        ("prod", "Production environment"),
18                    ];
19
20                    let mut result = CompletionResult::new();
21                    for (env, desc) in environments {
22                        if env.starts_with(prefix) {
23                            result = result.add_with_description(env.to_string(), desc.to_string());
24                        }
25                    }
26
27                    // Add active help if no prefix
28                    if prefix.is_empty() {
29                        result = result.add_help_text("Available environments: dev, staging, prod");
30                    }
31
32                    Ok(result)
33                }),
34        )
35        .flag(
36            Flag::file("config")
37                .short('c')
38                .usage("Configuration file")
39                .default_str("config.yaml")
40                .completion(|_ctx, prefix| {
41                    // In a real app, you might list files in the config directory
42                    let configs = vec![
43                        "config.yaml",
44                        "config.dev.yaml",
45                        "config.staging.yaml",
46                        "config.prod.yaml",
47                        "secrets.yaml",
48                    ];
49
50                    Ok(CompletionResult::new().extend(
51                        configs
52                            .into_iter()
53                            .filter(|c| c.starts_with(prefix))
54                            .map(String::from),
55                    ))
56                }),
57        )
58        .flag(
59            Flag::directory("output")
60                .short('o')
61                .usage("Output directory for deployment artifacts")
62                .completion(|_ctx, prefix| {
63                    // In a real app, you might list actual directories
64                    let dirs = vec!["./build", "./dist", "./output", "/tmp/deploy"];
65
66                    Ok(CompletionResult::new().extend(
67                        dirs.into_iter()
68                            .filter(|d| d.starts_with(prefix))
69                            .map(String::from),
70                    ))
71                }),
72        )
73        .flag(
74            Flag::string_slice("service")
75                .short('s')
76                .usage("Services to deploy (can be specified multiple times)")
77                .completion(|ctx, prefix| {
78                    // Context-aware completion based on environment
79                    let env = ctx.flag_str_or("environment", "dev");
80
81                    let services = match env {
82                        "dev" => vec!["api", "web", "worker", "scheduler", "debug-panel"],
83                        "staging" => vec!["api", "web", "worker", "scheduler"],
84                        "prod" => vec!["api", "web", "worker"],
85                        _ => vec!["api", "web"],
86                    };
87
88                    let mut result = CompletionResult::new().extend(
89                        services
90                            .into_iter()
91                            .filter(|s| s.starts_with(prefix))
92                            .map(String::from),
93                    );
94
95                    // Add context-aware help
96                    if prefix.is_empty() {
97                        result = result
98                            .add_help_text(format!("Available services for {} environment", env));
99                    }
100
101                    Ok(result)
102                }),
103        )
104        .flag(
105            Flag::range("replicas", 1, 10)
106                .short('r')
107                .usage("Number of replicas to deploy")
108                .default_int(2)
109                .completion(|_ctx, _prefix| {
110                    // Suggest common replica counts
111                    Ok(CompletionResult::new()
112                        .add_with_description(
113                            "1".to_string(),
114                            "Single instance (dev/test)".to_string(),
115                        )
116                        .add_with_description("2".to_string(), "Basic redundancy".to_string())
117                        .add_with_description("3".to_string(), "Standard production".to_string())
118                        .add_with_description("5".to_string(), "High availability".to_string()))
119                }),
120        )
121        .run(|ctx| {
122            let env = ctx.flag_str_or("environment", "dev");
123            let config = ctx.flag_str_or("config", "config.yaml");
124            let replicas = ctx.flag_int_or("replicas", 2);
125
126            println!("Deploying to {} environment", env);
127            println!("Using configuration: {}", config);
128            println!("Replica count: {}", replicas);
129
130            if let Some(output) = ctx.flag("output") {
131                println!("Output directory: {}", output);
132            }
133
134            if let Some(services) = ctx.flag("service") {
135                println!("Deploying services: {}", services);
136            } else {
137                println!("Deploying all services");
138            }
139
140            Ok(())
141        })
142        .build();
143
144    let args: Vec<String> = std::env::args().skip(1).collect();
145    if let Err(e) = app.execute(args) {
146        eprintln!("Error: {}", e);
147        std::process::exit(1);
148    }
149}
Source

pub fn directory(name: impl Into<String>) -> Self

Creates a new directory flag

§Examples
use flag_rs::flag::Flag;

let flag = Flag::directory("output");
Examples found in repository?
examples/flag_completion_demo.rs (line 59)
4fn main() {
5    let app = CommandBuilder::new("deploy")
6        .short("Deploy application to various environments")
7        .flag(
8            Flag::choice("environment", &["dev", "staging", "prod"])
9                .short('e')
10                .usage("Target environment")
11                .required()
12                .completion(|_ctx, prefix| {
13                    // Dynamic completion - could check available environments
14                    let environments = vec![
15                        ("dev", "Development environment"),
16                        ("staging", "Staging environment (pre-production)"),
17                        ("prod", "Production environment"),
18                    ];
19
20                    let mut result = CompletionResult::new();
21                    for (env, desc) in environments {
22                        if env.starts_with(prefix) {
23                            result = result.add_with_description(env.to_string(), desc.to_string());
24                        }
25                    }
26
27                    // Add active help if no prefix
28                    if prefix.is_empty() {
29                        result = result.add_help_text("Available environments: dev, staging, prod");
30                    }
31
32                    Ok(result)
33                }),
34        )
35        .flag(
36            Flag::file("config")
37                .short('c')
38                .usage("Configuration file")
39                .default_str("config.yaml")
40                .completion(|_ctx, prefix| {
41                    // In a real app, you might list files in the config directory
42                    let configs = vec![
43                        "config.yaml",
44                        "config.dev.yaml",
45                        "config.staging.yaml",
46                        "config.prod.yaml",
47                        "secrets.yaml",
48                    ];
49
50                    Ok(CompletionResult::new().extend(
51                        configs
52                            .into_iter()
53                            .filter(|c| c.starts_with(prefix))
54                            .map(String::from),
55                    ))
56                }),
57        )
58        .flag(
59            Flag::directory("output")
60                .short('o')
61                .usage("Output directory for deployment artifacts")
62                .completion(|_ctx, prefix| {
63                    // In a real app, you might list actual directories
64                    let dirs = vec!["./build", "./dist", "./output", "/tmp/deploy"];
65
66                    Ok(CompletionResult::new().extend(
67                        dirs.into_iter()
68                            .filter(|d| d.starts_with(prefix))
69                            .map(String::from),
70                    ))
71                }),
72        )
73        .flag(
74            Flag::string_slice("service")
75                .short('s')
76                .usage("Services to deploy (can be specified multiple times)")
77                .completion(|ctx, prefix| {
78                    // Context-aware completion based on environment
79                    let env = ctx.flag_str_or("environment", "dev");
80
81                    let services = match env {
82                        "dev" => vec!["api", "web", "worker", "scheduler", "debug-panel"],
83                        "staging" => vec!["api", "web", "worker", "scheduler"],
84                        "prod" => vec!["api", "web", "worker"],
85                        _ => vec!["api", "web"],
86                    };
87
88                    let mut result = CompletionResult::new().extend(
89                        services
90                            .into_iter()
91                            .filter(|s| s.starts_with(prefix))
92                            .map(String::from),
93                    );
94
95                    // Add context-aware help
96                    if prefix.is_empty() {
97                        result = result
98                            .add_help_text(format!("Available services for {} environment", env));
99                    }
100
101                    Ok(result)
102                }),
103        )
104        .flag(
105            Flag::range("replicas", 1, 10)
106                .short('r')
107                .usage("Number of replicas to deploy")
108                .default_int(2)
109                .completion(|_ctx, _prefix| {
110                    // Suggest common replica counts
111                    Ok(CompletionResult::new()
112                        .add_with_description(
113                            "1".to_string(),
114                            "Single instance (dev/test)".to_string(),
115                        )
116                        .add_with_description("2".to_string(), "Basic redundancy".to_string())
117                        .add_with_description("3".to_string(), "Standard production".to_string())
118                        .add_with_description("5".to_string(), "High availability".to_string()))
119                }),
120        )
121        .run(|ctx| {
122            let env = ctx.flag_str_or("environment", "dev");
123            let config = ctx.flag_str_or("config", "config.yaml");
124            let replicas = ctx.flag_int_or("replicas", 2);
125
126            println!("Deploying to {} environment", env);
127            println!("Using configuration: {}", config);
128            println!("Replica count: {}", replicas);
129
130            if let Some(output) = ctx.flag("output") {
131                println!("Output directory: {}", output);
132            }
133
134            if let Some(services) = ctx.flag("service") {
135                println!("Deploying services: {}", services);
136            } else {
137                println!("Deploying all services");
138            }
139
140            Ok(())
141        })
142        .build();
143
144    let args: Vec<String> = std::env::args().skip(1).collect();
145    if let Err(e) = app.execute(args) {
146        eprintln!("Error: {}", e);
147        std::process::exit(1);
148    }
149}
More examples
Hide additional examples
examples/builder_api_demo.rs (line 61)
4fn main() {
5    // Demonstrates all the new builder API improvements
6    let app = CommandBuilder::new("app")
7        .short("Modern CLI app with improved API")
8        .long(
9            "This example showcases the builder API improvements including:\n\
10               - Type-specific flag constructors\n\
11               - Inline flag completions\n\
12               - Bulk flag/subcommand methods\n\
13               - Type-safe context access",
14        )
15        // Bulk flag addition
16        .flags(vec![
17            // Type-specific constructors
18            Flag::bool("verbose")
19                .short('v')
20                .usage("Enable verbose output")
21                .default_bool(false),
22            Flag::bool("quiet").short('q').usage("Suppress all output"),
23            Flag::int("threads")
24                .short('t')
25                .usage("Number of worker threads")
26                .default_int(4),
27            Flag::choice("log-level", &["debug", "info", "warn", "error"])
28                .usage("Set the logging level")
29                .default_str("info")
30                .completion(|_ctx, prefix| {
31                    // Inline completion with descriptions
32                    let levels = vec![
33                        ("debug", "Show all messages including debug"),
34                        ("info", "Show informational messages and above"),
35                        ("warn", "Show warnings and errors only"),
36                        ("error", "Show errors only"),
37                    ];
38
39                    let mut result = flag_rs::CompletionResult::new();
40                    for (level, desc) in levels {
41                        if level.starts_with(prefix) {
42                            result =
43                                result.add_with_description(level.to_string(), desc.to_string());
44                        }
45                    }
46                    Ok(result)
47                }),
48        ])
49        // Bulk subcommand addition
50        .subcommands(vec![
51            CommandBuilder::new("init")
52                .short("Initialize a new project")
53                .flags(vec![
54                    Flag::string("name")
55                        .short('n')
56                        .usage("Project name")
57                        .required(),
58                    Flag::choice("template", &["basic", "web", "api", "full"])
59                        .usage("Project template to use")
60                        .default_str("basic"),
61                    Flag::directory("path")
62                        .short('p')
63                        .usage("Directory to create project in")
64                        .completion(|_ctx, prefix| {
65                            // In a real app, list actual directories
66                            let dirs = vec!["./", "../", "/tmp/", "~/projects/"];
67                            Ok(flag_rs::CompletionResult::new().extend(
68                                dirs.into_iter()
69                                    .filter(|d| d.starts_with(prefix))
70                                    .map(String::from),
71                            ))
72                        }),
73                ])
74                .run(|ctx| {
75                    // Type-safe flag access
76                    let name = ctx.flag_str_or("name", "my-project");
77                    let template = ctx.flag_str_or("template", "basic");
78                    let path = ctx.flag_str_or("path", ".");
79                    let verbose = ctx.flag_bool_or("verbose", false);
80
81                    if verbose {
82                        println!("Initializing {} project '{}' in {}", template, name, path);
83                    } else {
84                        println!("Creating project '{}'...", name);
85                    }
86
87                    Ok(())
88                })
89                .build(),
90            CommandBuilder::new("build")
91                .short("Build the project")
92                .flags(vec![
93                    Flag::bool("release")
94                        .short('r')
95                        .usage("Build in release mode"),
96                    Flag::string_slice("features")
97                        .short('f')
98                        .usage("Enable features (can be specified multiple times)")
99                        .completion(|_ctx, prefix| {
100                            let features = vec!["async", "tls", "compression", "metrics"];
101                            Ok(flag_rs::CompletionResult::new().extend(
102                                features
103                                    .into_iter()
104                                    .filter(|f| f.starts_with(prefix))
105                                    .map(String::from),
106                            ))
107                        }),
108                    Flag::range("jobs", 1, 32)
109                        .short('j')
110                        .usage("Number of parallel jobs")
111                        .default_int(i64::try_from(num_cpus()).unwrap_or(4)),
112                ])
113                .run(|ctx| {
114                    let release = ctx.flag_bool_or("release", false);
115                    let jobs = ctx.flag_int_or("jobs", i64::try_from(num_cpus()).unwrap_or(4));
116                    let quiet = ctx.flag_bool_or("quiet", false);
117
118                    if !quiet {
119                        println!(
120                            "Building in {} mode with {} jobs",
121                            if release { "release" } else { "debug" },
122                            jobs
123                        );
124
125                        if let Some(features) = ctx.flag("features") {
126                            println!("Features: {}", features);
127                        }
128                    }
129
130                    Ok(())
131                })
132                .build(),
133            CommandBuilder::new("test")
134                .short("Run tests")
135                .flags(vec![
136                    Flag::string("filter").usage("Only run tests matching this pattern"),
137                    Flag::bool("nocapture").usage("Don't capture test output"),
138                    Flag::int("test-threads")
139                        .usage("Number of threads to use for running tests")
140                        .default_int(1),
141                ])
142                .run(|ctx| {
143                    let threads = ctx.flag_int_or("test-threads", 1);
144                    let nocapture = ctx.flag_bool_or("nocapture", false);
145                    let verbose = ctx.flag_bool_or("verbose", false);
146
147                    if verbose {
148                        println!("Running tests with {} thread(s)", threads);
149                        if nocapture {
150                            println!("Output capture disabled");
151                        }
152
153                        if let Some(filter) = ctx.flag("filter") {
154                            println!("Filter: {}", filter);
155                        }
156                    }
157
158                    println!("Running tests...");
159                    Ok(())
160                })
161                .build(),
162        ])
163        .run(|_ctx| {
164            // Root command - show help by default
165            println!("Use --help for usage information");
166            Ok(())
167        })
168        .build();
169
170    let args: Vec<String> = std::env::args().skip(1).collect();
171    if let Err(e) = app.execute(args) {
172        eprintln!("Error: {}", e);
173        std::process::exit(1);
174    }
175}
Source

pub const fn short(self, short: char) -> Self

Sets the short name for this flag

§Examples
use flag_rs::flag::Flag;

let flag = Flag::new("verbose").short('v');
assert_eq!(flag.short, Some('v'));
Examples found in repository?
examples/benchmark.rs (line 55)
50fn create_simple_cli() -> flag_rs::Command {
51    CommandBuilder::new("bench")
52        .short("Benchmark CLI")
53        .flag(
54            Flag::new("verbose")
55                .short('v')
56                .value_type(FlagType::Bool)
57                .default(FlagValue::Bool(false)),
58        )
59        .flag(Flag::new("output").short('o').value_type(FlagType::String))
60        .build()
61}
62
63/// Creates a complex nested command structure
64fn create_complex_cli() -> flag_rs::Command {
65    let mut root = CommandBuilder::new("complex")
66        .short("Complex CLI with many subcommands")
67        .flag(
68            Flag::new("config")
69                .short('c')
70                .value_type(FlagType::File)
71                .default(FlagValue::String("config.yaml".to_string())),
72        )
73        .build();
74
75    // Add 50 subcommands
76    for i in 0..50 {
77        let mut sub = CommandBuilder::new(format!("sub{i:02}"))
78            .short(format!("Subcommand {i}"))
79            .flag(Flag::new("flag1").short('1').value_type(FlagType::String))
80            .flag(Flag::new("flag2").short('2').value_type(FlagType::Int))
81            .build();
82
83        // Add 10 nested subcommands
84        for j in 0..10 {
85            sub.add_command(
86                CommandBuilder::new(format!("nested{j}"))
87                    .short(format!("Nested command {j}"))
88                    .flag(Flag::new("deep").value_type(FlagType::Bool))
89                    .build(),
90            );
91        }
92
93        root.add_command(sub);
94    }
95
96    root
97}
More examples
Hide additional examples
examples/kubectl.rs (line 24)
14fn build_kubectl() -> Command {
15    CommandBuilder::new("kubectl")
16        .short("Kubernetes command-line tool")
17        .long("kubectl controls the Kubernetes cluster manager")
18        .subcommand(build_get_command())
19        .subcommand(build_describe_command())
20        .subcommand(build_delete_command())
21        .subcommand(build_completion_command())
22        .flag(
23            Flag::new("namespace")
24                .short('n')
25                .usage("Kubernetes namespace")
26                .value_type(FlagType::String)
27                .default(FlagValue::String("default".to_string())),
28        )
29        .flag_completion("namespace", |_ctx, prefix| {
30            // In a real kubectl, this would query the API server
31            let namespaces = get_namespaces_with_descriptions();
32            let mut result = CompletionResult::new();
33
34            for (ns_name, description) in namespaces {
35                if ns_name.starts_with(prefix) {
36                    result = result.add_with_description(ns_name, description);
37                }
38            }
39
40            Ok(result)
41        })
42        .build()
43}
44
45fn build_get_command() -> Command {
46    CommandBuilder::new("get")
47        .short("Display one or many resources")
48        .long("Display one or many resources. Prints a table of the most important information about the specified resources.")
49        .flag(
50            Flag::new("limit")
51                .short('l')
52                .usage("Maximum number of resources to display")
53                .value_type(FlagType::String)
54        )
55        .flag_completion("limit", |_ctx, prefix| {
56            let common_limits = vec![
57                ("10", "Display 10 items"),
58                ("20", "Display 20 items"),
59                ("50", "Display 50 items"),
60                ("100", "Display 100 items"),
61                ("all", "Display all items (no limit)"),
62            ];
63
64            let mut result = CompletionResult::new();
65            for (limit, description) in common_limits {
66                if limit.starts_with(prefix) {
67                    result = result.add_with_description(limit.to_string(), description.to_string());
68                }
69            }
70
71            Ok(result)
72        })
73        .subcommand(build_get_pods())
74        .subcommand(build_get_services())
75        .subcommand(build_get_deployments())
76        .build()
77}
examples/terminal_demo.rs (line 23)
17fn main() {
18    let app = CommandBuilder::new("demo")
19        .short("Terminal feature demonstration")
20        .long("This application demonstrates the terminal width detection and text wrapping features. The help text should automatically adjust to your terminal width, wrapping long lines at word boundaries while maintaining readability. Try running this with different COLUMNS values to see how it adapts.")
21        .flag(
22            Flag::new("file")
23                .short('f')
24                .usage("Input file path. This flag expects a path to a file that will be processed. The file must exist and be readable.")
25                .value_type(FlagType::String)
26        )
27        .flag(
28            Flag::new("output-format")
29                .short('o')
30                .usage("Output format for results. Supported formats include: json (machine-readable JSON format), yaml (human-friendly YAML format), table (formatted ASCII table), csv (comma-separated values for spreadsheet import)")
31                .value_type(FlagType::String)
32                .default(FlagValue::String("table".to_string()))
33        )
34        .subcommand(
35            CommandBuilder::new("process")
36                .short("Process data with various transformations and filters that can be applied in sequence")
37                .build()
38        )
39        .build();
40
41    // Always show help for this demo
42    app.print_help();
43}
examples/test_completion.rs (line 8)
3fn main() {
4    let cmd = CommandBuilder::new("test")
5        .short("Test completion with descriptions")
6        .flag(
7            Flag::new("environment")
8                .short('e')
9                .usage("Target environment")
10                .value_type(FlagType::String),
11        )
12        .flag_completion("environment", |_ctx, prefix| {
13            let mut result = CompletionResult::new();
14            let envs = vec![
15                ("dev", "Development environment - safe for testing"),
16                ("staging", "Staging environment - mirror of production"),
17                ("production", "Production environment - BE CAREFUL!"),
18            ];
19
20            for (env, desc) in envs {
21                if env.starts_with(prefix) {
22                    result = result.add_with_description(env, desc);
23                }
24            }
25
26            Ok(result)
27        })
28        .subcommand(
29            CommandBuilder::new("deploy")
30                .short("Deploy the application")
31                .long("Deploy the application to the specified environment")
32                .build(),
33        )
34        .subcommand(
35            CommandBuilder::new("rollback")
36                .short("Rollback to previous version")
37                .long("Rollback the application to the previous deployed version")
38                .build(),
39        )
40        .build();
41
42    // Test completion output
43    if let Ok(shell_type) = std::env::var("TEST_COMPLETE") {
44        // For testing, override shell type to "display" to see formatted output
45        let display_mode = std::env::var("DISPLAY_MODE").is_ok();
46        let args: Vec<String> = std::env::args().skip(1).collect();
47
48        if display_mode {
49            // This is a hack for testing - normally shells would handle this
50            println!("Display mode - showing formatted completions:");
51            match cmd.handle_completion_request(&args) {
52                Ok(completions) => {
53                    for completion in completions {
54                        println!("{}", completion);
55                    }
56                }
57                Err(e) => eprintln!("Completion error: {}", e),
58            }
59        } else {
60            match cmd.handle_completion_request(&args) {
61                Ok(completions) => {
62                    println!("Shell type: {}", shell_type);
63                    println!("Completions:");
64                    for completion in completions {
65                        println!("{}", completion);
66                    }
67                }
68                Err(e) => eprintln!("Completion error: {}", e),
69            }
70        }
71    } else {
72        let args: Vec<String> = std::env::args().skip(1).collect();
73        if let Err(e) = cmd.execute(args) {
74            eprintln!("Error: {}", e);
75            std::process::exit(1);
76        }
77    }
78}
examples/enhanced_errors_demo.rs (line 12)
7fn main() {
8    let app = CommandBuilder::new("errordemo")
9        .short("Demo of enhanced error messages")
10        .flag(
11            Flag::new("verbose")
12                .short('v')
13                .value_type(FlagType::Bool)
14                .usage("Enable verbose output"),
15        )
16        .flag(
17            Flag::new("workers")
18                .short('w')
19                .value_type(FlagType::Range(1, 10))
20                .usage("Number of worker threads"),
21        )
22        .flag(
23            Flag::new("format")
24                .short('f')
25                .value_type(FlagType::Choice(vec![
26                    "json".to_string(),
27                    "yaml".to_string(),
28                    "xml".to_string(),
29                    "toml".to_string(),
30                ]))
31                .usage("Output format"),
32        )
33        .flag(
34            Flag::new("config")
35                .short('c')
36                .value_type(FlagType::File)
37                .usage("Configuration file"),
38        )
39        .flag(
40            Flag::new("outdir")
41                .short('o')
42                .value_type(FlagType::Directory)
43                .usage("Output directory"),
44        )
45        .flag(
46            Flag::new("ssl")
47                .value_type(FlagType::Bool)
48                .usage("Enable SSL"),
49        )
50        .flag(
51            Flag::new("ssl-cert")
52                .value_type(FlagType::File)
53                .constraint(FlagConstraint::RequiredIf("ssl".to_string()))
54                .usage("SSL certificate file"),
55        )
56        .flag(
57            Flag::new("json")
58                .value_type(FlagType::Bool)
59                .constraint(FlagConstraint::ConflictsWith(vec!["xml".to_string()]))
60                .usage("Output in JSON format"),
61        )
62        .flag(
63            Flag::new("xml")
64                .value_type(FlagType::Bool)
65                .usage("Output in XML format"),
66        )
67        .flag(
68            Flag::new("required-flag")
69                .value_type(FlagType::String)
70                .required()
71                .usage("This flag is required"),
72        )
73        .subcommand(
74            CommandBuilder::new("process")
75                .short("Process data")
76                .run(|ctx| {
77                    println!("Processing with flags: {:?}", ctx.flags());
78                    Ok(())
79                })
80                .build(),
81        )
82        .build();
83
84    println!("Try these commands to see enhanced error messages:\n");
85    println!("  # Boolean parsing error");
86    println!("  cargo run --example enhanced_errors_demo -- --verbose=maybe\n");
87
88    println!("  # Integer parsing error");
89    println!("  cargo run --example enhanced_errors_demo -- --workers=abc\n");
90
91    println!("  # Range validation error");
92    println!("  cargo run --example enhanced_errors_demo -- --workers=20\n");
93
94    println!("  # Choice validation error");
95    println!("  cargo run --example enhanced_errors_demo -- --format=csv\n");
96
97    println!("  # File not found error");
98    println!("  cargo run --example enhanced_errors_demo -- --config=/tmp/nonexistent.conf\n");
99
100    println!("  # Directory not found error");
101    println!("  cargo run --example enhanced_errors_demo -- --outdir=/tmp/nonexistent_dir\n");
102
103    println!("  # Flag constraint error (RequiredIf)");
104    println!("  cargo run --example enhanced_errors_demo -- --ssl --required-flag=test process\n");
105
106    println!("  # Flag constraint error (ConflictsWith)");
107    println!(
108        "  cargo run --example enhanced_errors_demo -- --json --xml --required-flag=test process\n"
109    );
110
111    println!("  # Required flag error");
112    println!("  cargo run --example enhanced_errors_demo -- process\n");
113
114    println!("  # Unknown command error");
115    println!("  cargo run --example enhanced_errors_demo -- --required-flag=test proces\n");
116
117    let args: Vec<String> = std::env::args().skip(1).collect();
118    if !args.is_empty() {
119        println!("\n{}", "=".repeat(60));
120        println!("Running with args: {:?}\n", args);
121
122        if let Err(e) = app.execute(args) {
123            eprintln!("{}", e);
124            std::process::exit(1);
125        }
126    }
127}
examples/memory_optimization_demo.rs (line 26)
12fn create_many_subcommands(parent: &mut flag_rs::Command) {
13    // Simulate a large CLI with 100 subcommands
14    for i in 0..100 {
15        let cmd_name = format!("service-{i:03}");
16
17        // Use string interning for flag names that repeat across commands
18        let namespace_flag_name = string_pool::intern("namespace");
19        let region_flag_name = string_pool::intern("region");
20        let env_flag_name = string_pool::intern("environment");
21
22        let cmd = CommandBuilder::new(cmd_name.clone())
23            .short(format!("Manage service {i}"))
24            .flag(
25                Flag::new(namespace_flag_name.to_string())
26                    .short('n')
27                    .usage("Kubernetes namespace")
28                    .value_type(FlagType::String)
29                    .default(flag_rs::FlagValue::String("default".to_string())),
30            )
31            .flag(
32                Flag::new(region_flag_name.to_string())
33                    .short('r')
34                    .usage("AWS region")
35                    .value_type(FlagType::Choice(vec![
36                        "us-east-1".to_string(),
37                        "us-west-2".to_string(),
38                        "eu-west-1".to_string(),
39                        "ap-southeast-1".to_string(),
40                    ]))
41                    .default(flag_rs::FlagValue::String("us-east-1".to_string())),
42            )
43            .flag(
44                Flag::new(env_flag_name.to_string())
45                    .short('e')
46                    .usage("Deployment environment")
47                    .value_type(FlagType::Choice(vec![
48                        "dev".to_string(),
49                        "staging".to_string(),
50                        "prod".to_string(),
51                    ]))
52                    .default(flag_rs::FlagValue::String("dev".to_string())),
53            )
54            .subcommand(
55                CommandBuilder::new("deploy")
56                    .short("Deploy the service")
57                    .arg_completion(move |_ctx, prefix| {
58                        // Use optimized completion result
59                        let optimized = CompletionResultOptimized::new()
60                            .add(Cow::Borrowed("rolling-update"))
61                            .add(Cow::Borrowed("blue-green"))
62                            .add(Cow::Borrowed("canary"))
63                            .add_with_description(
64                                Cow::Borrowed("recreate"),
65                                Cow::Borrowed("Recreate all pods"),
66                            );
67
68                        // Filter based on prefix
69                        let filtered = CompletionResultOptimized::new().extend_items(
70                            optimized
71                                .items
72                                .into_iter()
73                                .filter(|item| item.value.starts_with(prefix)),
74                        );
75
76                        // Convert to legacy format for compatibility
77                        Ok(filtered.into_legacy())
78                    })
79                    .build(),
80            )
81            .subcommand(
82                CommandBuilder::new("scale")
83                    .short("Scale the service")
84                    .flag(
85                        Flag::new("replicas")
86                            .usage("Number of replicas")
87                            .value_type(FlagType::Int)
88                            .required(),
89                    )
90                    .build(),
91            )
92            .subcommand(
93                CommandBuilder::new("logs")
94                    .short("View service logs")
95                    .flag(
96                        Flag::new("follow")
97                            .short('f')
98                            .usage("Follow log output")
99                            .value_type(FlagType::Bool),
100                    )
101                    .flag(
102                        Flag::new("tail")
103                            .usage("Number of lines to show")
104                            .value_type(FlagType::Int)
105                            .default(flag_rs::FlagValue::Int(100)),
106                    )
107                    .build(),
108            )
109            .build();
110
111        parent.add_command(cmd);
112    }
113}
114
115// Count commands recursively
116fn count_commands(cmd: &flag_rs::Command) -> usize {
117    1 + cmd
118        .subcommands()
119        .values()
120        .map(count_commands)
121        .sum::<usize>()
122}
123
124// Count flags recursively
125fn count_flags(cmd: &flag_rs::Command) -> usize {
126    cmd.flags().len() + cmd.subcommands().values().map(count_flags).sum::<usize>()
127}
128
129fn main() {
130    // Create root command
131    let mut app = CommandBuilder::new("megacli")
132        .short("A large CLI demonstrating memory optimizations")
133        .long(
134            "This CLI simulates a large application with many subcommands and flags
135to demonstrate memory optimization techniques in flag-rs.
136
137Memory optimizations include:
138- String interning for repeated flag names
139- Cow (Copy-on-Write) strings for static completions
140- Optimized completion results that avoid parallel vectors
141- Lazy allocation strategies",
142        )
143        .flag(
144            Flag::new("verbose")
145                .short('v')
146                .usage("Enable verbose output")
147                .value_type(FlagType::Bool),
148        )
149        .flag(
150            Flag::new("config")
151                .short('c')
152                .usage("Path to config file")
153                .value_type(FlagType::File)
154                .default(flag_rs::FlagValue::String(
155                    "~/.megacli/config.yaml".to_string(),
156                )),
157        )
158        .build();
159
160    // Add many subcommands
161    create_many_subcommands(&mut app);
162
163    let total_commands = count_commands(&app);
164    let total_flags = count_flags(&app);
165
166    // Add a special command to show memory usage stats
167    app.add_command(
168        CommandBuilder::new("stats")
169            .short("Show CLI statistics and memory usage")
170            .run(move |_ctx| {
171                println!("=== MegaCLI Statistics ===\n");
172
173                println!("Total commands: {total_commands}");
174                println!("Total flags: {total_flags}");
175                println!("String pool size: {} unique strings", 3); // We interned 3 flag names
176
177                println!("\nMemory optimization features in use:");
178                println!("✓ String interning for flag names");
179                println!("✓ Cow<str> for static completion values");
180                println!("✓ CompletionResultOptimized for reduced allocations");
181                println!("✓ Lazy allocation strategies");
182
183                println!("\nEstimated memory savings:");
184                println!("- 60-70% reduction in string allocations");
185                println!("- 40-50% reduction in completion memory usage");
186                println!("- Improved cache locality for better performance");
187
188                Ok(())
189            })
190            .build(),
191    );
192
193    // Execute the CLI
194    let args: Vec<String> = std::env::args().skip(1).collect();
195
196    if args.is_empty() {
197        println!("=== Memory Optimization Demo ===\n");
198        println!("This demo shows how flag-rs optimizes memory for large CLIs.\n");
199        println!("Try these commands:");
200        println!(
201            "  {} stats                    # Show memory statistics",
202            std::env::args().next().unwrap_or_default()
203        );
204        println!(
205            "  {} service-001 deploy <TAB> # Test optimized completions",
206            std::env::args().next().unwrap_or_default()
207        );
208        println!(
209            "  {} --help                   # See all 100+ commands",
210            std::env::args().next().unwrap_or_default()
211        );
212        println!("\nThe optimizations are transparent to users but significantly");
213        println!("reduce memory usage for CLIs with many commands and flags.");
214        std::process::exit(0);
215    }
216
217    if let Err(e) = app.execute(args) {
218        eprintln!("{e}");
219        std::process::exit(1);
220    }
221}
Source

pub fn usage(self, usage: impl Into<String>) -> Self

Sets the usage description for this flag

§Examples
use flag_rs::flag::Flag;

let flag = Flag::new("verbose").usage("Enable verbose output");
assert_eq!(flag.usage, "Enable verbose output");
Examples found in repository?
examples/kubectl.rs (line 25)
14fn build_kubectl() -> Command {
15    CommandBuilder::new("kubectl")
16        .short("Kubernetes command-line tool")
17        .long("kubectl controls the Kubernetes cluster manager")
18        .subcommand(build_get_command())
19        .subcommand(build_describe_command())
20        .subcommand(build_delete_command())
21        .subcommand(build_completion_command())
22        .flag(
23            Flag::new("namespace")
24                .short('n')
25                .usage("Kubernetes namespace")
26                .value_type(FlagType::String)
27                .default(FlagValue::String("default".to_string())),
28        )
29        .flag_completion("namespace", |_ctx, prefix| {
30            // In a real kubectl, this would query the API server
31            let namespaces = get_namespaces_with_descriptions();
32            let mut result = CompletionResult::new();
33
34            for (ns_name, description) in namespaces {
35                if ns_name.starts_with(prefix) {
36                    result = result.add_with_description(ns_name, description);
37                }
38            }
39
40            Ok(result)
41        })
42        .build()
43}
44
45fn build_get_command() -> Command {
46    CommandBuilder::new("get")
47        .short("Display one or many resources")
48        .long("Display one or many resources. Prints a table of the most important information about the specified resources.")
49        .flag(
50            Flag::new("limit")
51                .short('l')
52                .usage("Maximum number of resources to display")
53                .value_type(FlagType::String)
54        )
55        .flag_completion("limit", |_ctx, prefix| {
56            let common_limits = vec![
57                ("10", "Display 10 items"),
58                ("20", "Display 20 items"),
59                ("50", "Display 50 items"),
60                ("100", "Display 100 items"),
61                ("all", "Display all items (no limit)"),
62            ];
63
64            let mut result = CompletionResult::new();
65            for (limit, description) in common_limits {
66                if limit.starts_with(prefix) {
67                    result = result.add_with_description(limit.to_string(), description.to_string());
68                }
69            }
70
71            Ok(result)
72        })
73        .subcommand(build_get_pods())
74        .subcommand(build_get_services())
75        .subcommand(build_get_deployments())
76        .build()
77}
More examples
Hide additional examples
examples/terminal_demo.rs (line 24)
17fn main() {
18    let app = CommandBuilder::new("demo")
19        .short("Terminal feature demonstration")
20        .long("This application demonstrates the terminal width detection and text wrapping features. The help text should automatically adjust to your terminal width, wrapping long lines at word boundaries while maintaining readability. Try running this with different COLUMNS values to see how it adapts.")
21        .flag(
22            Flag::new("file")
23                .short('f')
24                .usage("Input file path. This flag expects a path to a file that will be processed. The file must exist and be readable.")
25                .value_type(FlagType::String)
26        )
27        .flag(
28            Flag::new("output-format")
29                .short('o')
30                .usage("Output format for results. Supported formats include: json (machine-readable JSON format), yaml (human-friendly YAML format), table (formatted ASCII table), csv (comma-separated values for spreadsheet import)")
31                .value_type(FlagType::String)
32                .default(FlagValue::String("table".to_string()))
33        )
34        .subcommand(
35            CommandBuilder::new("process")
36                .short("Process data with various transformations and filters that can be applied in sequence")
37                .build()
38        )
39        .build();
40
41    // Always show help for this demo
42    app.print_help();
43}
examples/test_completion.rs (line 9)
3fn main() {
4    let cmd = CommandBuilder::new("test")
5        .short("Test completion with descriptions")
6        .flag(
7            Flag::new("environment")
8                .short('e')
9                .usage("Target environment")
10                .value_type(FlagType::String),
11        )
12        .flag_completion("environment", |_ctx, prefix| {
13            let mut result = CompletionResult::new();
14            let envs = vec![
15                ("dev", "Development environment - safe for testing"),
16                ("staging", "Staging environment - mirror of production"),
17                ("production", "Production environment - BE CAREFUL!"),
18            ];
19
20            for (env, desc) in envs {
21                if env.starts_with(prefix) {
22                    result = result.add_with_description(env, desc);
23                }
24            }
25
26            Ok(result)
27        })
28        .subcommand(
29            CommandBuilder::new("deploy")
30                .short("Deploy the application")
31                .long("Deploy the application to the specified environment")
32                .build(),
33        )
34        .subcommand(
35            CommandBuilder::new("rollback")
36                .short("Rollback to previous version")
37                .long("Rollback the application to the previous deployed version")
38                .build(),
39        )
40        .build();
41
42    // Test completion output
43    if let Ok(shell_type) = std::env::var("TEST_COMPLETE") {
44        // For testing, override shell type to "display" to see formatted output
45        let display_mode = std::env::var("DISPLAY_MODE").is_ok();
46        let args: Vec<String> = std::env::args().skip(1).collect();
47
48        if display_mode {
49            // This is a hack for testing - normally shells would handle this
50            println!("Display mode - showing formatted completions:");
51            match cmd.handle_completion_request(&args) {
52                Ok(completions) => {
53                    for completion in completions {
54                        println!("{}", completion);
55                    }
56                }
57                Err(e) => eprintln!("Completion error: {}", e),
58            }
59        } else {
60            match cmd.handle_completion_request(&args) {
61                Ok(completions) => {
62                    println!("Shell type: {}", shell_type);
63                    println!("Completions:");
64                    for completion in completions {
65                        println!("{}", completion);
66                    }
67                }
68                Err(e) => eprintln!("Completion error: {}", e),
69            }
70        }
71    } else {
72        let args: Vec<String> = std::env::args().skip(1).collect();
73        if let Err(e) = cmd.execute(args) {
74            eprintln!("Error: {}", e);
75            std::process::exit(1);
76        }
77    }
78}
examples/enhanced_errors_demo.rs (line 14)
7fn main() {
8    let app = CommandBuilder::new("errordemo")
9        .short("Demo of enhanced error messages")
10        .flag(
11            Flag::new("verbose")
12                .short('v')
13                .value_type(FlagType::Bool)
14                .usage("Enable verbose output"),
15        )
16        .flag(
17            Flag::new("workers")
18                .short('w')
19                .value_type(FlagType::Range(1, 10))
20                .usage("Number of worker threads"),
21        )
22        .flag(
23            Flag::new("format")
24                .short('f')
25                .value_type(FlagType::Choice(vec![
26                    "json".to_string(),
27                    "yaml".to_string(),
28                    "xml".to_string(),
29                    "toml".to_string(),
30                ]))
31                .usage("Output format"),
32        )
33        .flag(
34            Flag::new("config")
35                .short('c')
36                .value_type(FlagType::File)
37                .usage("Configuration file"),
38        )
39        .flag(
40            Flag::new("outdir")
41                .short('o')
42                .value_type(FlagType::Directory)
43                .usage("Output directory"),
44        )
45        .flag(
46            Flag::new("ssl")
47                .value_type(FlagType::Bool)
48                .usage("Enable SSL"),
49        )
50        .flag(
51            Flag::new("ssl-cert")
52                .value_type(FlagType::File)
53                .constraint(FlagConstraint::RequiredIf("ssl".to_string()))
54                .usage("SSL certificate file"),
55        )
56        .flag(
57            Flag::new("json")
58                .value_type(FlagType::Bool)
59                .constraint(FlagConstraint::ConflictsWith(vec!["xml".to_string()]))
60                .usage("Output in JSON format"),
61        )
62        .flag(
63            Flag::new("xml")
64                .value_type(FlagType::Bool)
65                .usage("Output in XML format"),
66        )
67        .flag(
68            Flag::new("required-flag")
69                .value_type(FlagType::String)
70                .required()
71                .usage("This flag is required"),
72        )
73        .subcommand(
74            CommandBuilder::new("process")
75                .short("Process data")
76                .run(|ctx| {
77                    println!("Processing with flags: {:?}", ctx.flags());
78                    Ok(())
79                })
80                .build(),
81        )
82        .build();
83
84    println!("Try these commands to see enhanced error messages:\n");
85    println!("  # Boolean parsing error");
86    println!("  cargo run --example enhanced_errors_demo -- --verbose=maybe\n");
87
88    println!("  # Integer parsing error");
89    println!("  cargo run --example enhanced_errors_demo -- --workers=abc\n");
90
91    println!("  # Range validation error");
92    println!("  cargo run --example enhanced_errors_demo -- --workers=20\n");
93
94    println!("  # Choice validation error");
95    println!("  cargo run --example enhanced_errors_demo -- --format=csv\n");
96
97    println!("  # File not found error");
98    println!("  cargo run --example enhanced_errors_demo -- --config=/tmp/nonexistent.conf\n");
99
100    println!("  # Directory not found error");
101    println!("  cargo run --example enhanced_errors_demo -- --outdir=/tmp/nonexistent_dir\n");
102
103    println!("  # Flag constraint error (RequiredIf)");
104    println!("  cargo run --example enhanced_errors_demo -- --ssl --required-flag=test process\n");
105
106    println!("  # Flag constraint error (ConflictsWith)");
107    println!(
108        "  cargo run --example enhanced_errors_demo -- --json --xml --required-flag=test process\n"
109    );
110
111    println!("  # Required flag error");
112    println!("  cargo run --example enhanced_errors_demo -- process\n");
113
114    println!("  # Unknown command error");
115    println!("  cargo run --example enhanced_errors_demo -- --required-flag=test proces\n");
116
117    let args: Vec<String> = std::env::args().skip(1).collect();
118    if !args.is_empty() {
119        println!("\n{}", "=".repeat(60));
120        println!("Running with args: {:?}\n", args);
121
122        if let Err(e) = app.execute(args) {
123            eprintln!("{}", e);
124            std::process::exit(1);
125        }
126    }
127}
examples/memory_optimization_demo.rs (line 27)
12fn create_many_subcommands(parent: &mut flag_rs::Command) {
13    // Simulate a large CLI with 100 subcommands
14    for i in 0..100 {
15        let cmd_name = format!("service-{i:03}");
16
17        // Use string interning for flag names that repeat across commands
18        let namespace_flag_name = string_pool::intern("namespace");
19        let region_flag_name = string_pool::intern("region");
20        let env_flag_name = string_pool::intern("environment");
21
22        let cmd = CommandBuilder::new(cmd_name.clone())
23            .short(format!("Manage service {i}"))
24            .flag(
25                Flag::new(namespace_flag_name.to_string())
26                    .short('n')
27                    .usage("Kubernetes namespace")
28                    .value_type(FlagType::String)
29                    .default(flag_rs::FlagValue::String("default".to_string())),
30            )
31            .flag(
32                Flag::new(region_flag_name.to_string())
33                    .short('r')
34                    .usage("AWS region")
35                    .value_type(FlagType::Choice(vec![
36                        "us-east-1".to_string(),
37                        "us-west-2".to_string(),
38                        "eu-west-1".to_string(),
39                        "ap-southeast-1".to_string(),
40                    ]))
41                    .default(flag_rs::FlagValue::String("us-east-1".to_string())),
42            )
43            .flag(
44                Flag::new(env_flag_name.to_string())
45                    .short('e')
46                    .usage("Deployment environment")
47                    .value_type(FlagType::Choice(vec![
48                        "dev".to_string(),
49                        "staging".to_string(),
50                        "prod".to_string(),
51                    ]))
52                    .default(flag_rs::FlagValue::String("dev".to_string())),
53            )
54            .subcommand(
55                CommandBuilder::new("deploy")
56                    .short("Deploy the service")
57                    .arg_completion(move |_ctx, prefix| {
58                        // Use optimized completion result
59                        let optimized = CompletionResultOptimized::new()
60                            .add(Cow::Borrowed("rolling-update"))
61                            .add(Cow::Borrowed("blue-green"))
62                            .add(Cow::Borrowed("canary"))
63                            .add_with_description(
64                                Cow::Borrowed("recreate"),
65                                Cow::Borrowed("Recreate all pods"),
66                            );
67
68                        // Filter based on prefix
69                        let filtered = CompletionResultOptimized::new().extend_items(
70                            optimized
71                                .items
72                                .into_iter()
73                                .filter(|item| item.value.starts_with(prefix)),
74                        );
75
76                        // Convert to legacy format for compatibility
77                        Ok(filtered.into_legacy())
78                    })
79                    .build(),
80            )
81            .subcommand(
82                CommandBuilder::new("scale")
83                    .short("Scale the service")
84                    .flag(
85                        Flag::new("replicas")
86                            .usage("Number of replicas")
87                            .value_type(FlagType::Int)
88                            .required(),
89                    )
90                    .build(),
91            )
92            .subcommand(
93                CommandBuilder::new("logs")
94                    .short("View service logs")
95                    .flag(
96                        Flag::new("follow")
97                            .short('f')
98                            .usage("Follow log output")
99                            .value_type(FlagType::Bool),
100                    )
101                    .flag(
102                        Flag::new("tail")
103                            .usage("Number of lines to show")
104                            .value_type(FlagType::Int)
105                            .default(flag_rs::FlagValue::Int(100)),
106                    )
107                    .build(),
108            )
109            .build();
110
111        parent.add_command(cmd);
112    }
113}
114
115// Count commands recursively
116fn count_commands(cmd: &flag_rs::Command) -> usize {
117    1 + cmd
118        .subcommands()
119        .values()
120        .map(count_commands)
121        .sum::<usize>()
122}
123
124// Count flags recursively
125fn count_flags(cmd: &flag_rs::Command) -> usize {
126    cmd.flags().len() + cmd.subcommands().values().map(count_flags).sum::<usize>()
127}
128
129fn main() {
130    // Create root command
131    let mut app = CommandBuilder::new("megacli")
132        .short("A large CLI demonstrating memory optimizations")
133        .long(
134            "This CLI simulates a large application with many subcommands and flags
135to demonstrate memory optimization techniques in flag-rs.
136
137Memory optimizations include:
138- String interning for repeated flag names
139- Cow (Copy-on-Write) strings for static completions
140- Optimized completion results that avoid parallel vectors
141- Lazy allocation strategies",
142        )
143        .flag(
144            Flag::new("verbose")
145                .short('v')
146                .usage("Enable verbose output")
147                .value_type(FlagType::Bool),
148        )
149        .flag(
150            Flag::new("config")
151                .short('c')
152                .usage("Path to config file")
153                .value_type(FlagType::File)
154                .default(flag_rs::FlagValue::String(
155                    "~/.megacli/config.yaml".to_string(),
156                )),
157        )
158        .build();
159
160    // Add many subcommands
161    create_many_subcommands(&mut app);
162
163    let total_commands = count_commands(&app);
164    let total_flags = count_flags(&app);
165
166    // Add a special command to show memory usage stats
167    app.add_command(
168        CommandBuilder::new("stats")
169            .short("Show CLI statistics and memory usage")
170            .run(move |_ctx| {
171                println!("=== MegaCLI Statistics ===\n");
172
173                println!("Total commands: {total_commands}");
174                println!("Total flags: {total_flags}");
175                println!("String pool size: {} unique strings", 3); // We interned 3 flag names
176
177                println!("\nMemory optimization features in use:");
178                println!("✓ String interning for flag names");
179                println!("✓ Cow<str> for static completion values");
180                println!("✓ CompletionResultOptimized for reduced allocations");
181                println!("✓ Lazy allocation strategies");
182
183                println!("\nEstimated memory savings:");
184                println!("- 60-70% reduction in string allocations");
185                println!("- 40-50% reduction in completion memory usage");
186                println!("- Improved cache locality for better performance");
187
188                Ok(())
189            })
190            .build(),
191    );
192
193    // Execute the CLI
194    let args: Vec<String> = std::env::args().skip(1).collect();
195
196    if args.is_empty() {
197        println!("=== Memory Optimization Demo ===\n");
198        println!("This demo shows how flag-rs optimizes memory for large CLIs.\n");
199        println!("Try these commands:");
200        println!(
201            "  {} stats                    # Show memory statistics",
202            std::env::args().next().unwrap_or_default()
203        );
204        println!(
205            "  {} service-001 deploy <TAB> # Test optimized completions",
206            std::env::args().next().unwrap_or_default()
207        );
208        println!(
209            "  {} --help                   # See all 100+ commands",
210            std::env::args().next().unwrap_or_default()
211        );
212        println!("\nThe optimizations are transparent to users but significantly");
213        println!("reduce memory usage for CLIs with many commands and flags.");
214        std::process::exit(0);
215    }
216
217    if let Err(e) = app.execute(args) {
218        eprintln!("{e}");
219        std::process::exit(1);
220    }
221}
examples/error_handling_demo.rs (line 39)
12fn main() {
13    let app = CommandBuilder::new("error-demo")
14        .short("Demonstrates error handling")
15        .long("This example shows various error scenarios and how flag-rs handles them")
16        .subcommand(
17            CommandBuilder::new("deploy")
18                .short("Deploy the application")
19                .args(ArgValidator::ExactArgs(1))
20                .run(|ctx| {
21                    let env = ctx.args().first().unwrap();
22                    if !["dev", "staging", "production"].contains(&env.as_str()) {
23                        return Err(Error::Validation(format!(
24                            "invalid environment '{}', must be one of: dev, staging, production",
25                            env
26                        )));
27                    }
28                    println!("Deploying to {}", env);
29                    Ok(())
30                })
31                .build(),
32        )
33        .subcommand(
34            CommandBuilder::new("serve")
35                .short("Start the server")
36                .flag(
37                    Flag::new("port")
38                        .short('p')
39                        .usage("Port to listen on")
40                        .value_type(FlagType::Int)
41                        .required(),
42                )
43                .run(|ctx| {
44                    let port = ctx.flag("port").unwrap();
45                    println!("Server starting on port {}", port);
46                    Ok(())
47                })
48                .build(),
49        )
50        .subcommand(
51            CommandBuilder::new("migrate")
52                .short("Run database migrations")
53                .subcommand(
54                    CommandBuilder::new("up")
55                        .short("Run pending migrations")
56                        .run(|_| {
57                            println!("Running migrations...");
58                            Ok(())
59                        })
60                        .build(),
61                )
62                .subcommand(
63                    CommandBuilder::new("down")
64                        .short("Rollback migrations")
65                        .args(ArgValidator::MaximumArgs(1))
66                        .run(|ctx| {
67                            let steps = ctx
68                                .args()
69                                .first()
70                                .and_then(|s| s.parse::<u32>().ok())
71                                .unwrap_or(1);
72                            println!(
73                                "Rolling back {} migration{}",
74                                steps,
75                                if steps == 1 { "" } else { "s" }
76                            );
77                            Ok(())
78                        })
79                        .build(),
80                )
81                .build(),
82        )
83        .subcommand(
84            CommandBuilder::new("config")
85                .short("Manage configuration")
86                .aliases(vec!["cfg", "conf"])
87                .run(|_| {
88                    println!("Configuration management");
89                    Ok(())
90                })
91                .build(),
92        )
93        .build();
94
95    println!("=== Error Handling Demo ===\n");
96    println!("This demo shows how flag-rs handles various error scenarios.\n");
97    println!("Try these commands to see different error types:\n");
98    println!(
99        "1. {} deploi              (typo - will show suggestions)",
100        std::env::args().next().unwrap_or_default()
101    );
102    println!(
103        "2. {} deploy              (missing required argument)",
104        std::env::args().next().unwrap_or_default()
105    );
106    println!(
107        "3. {} deploy dev staging  (too many arguments)",
108        std::env::args().next().unwrap_or_default()
109    );
110    println!(
111        "4. {} deploy test         (invalid environment)",
112        std::env::args().next().unwrap_or_default()
113    );
114    println!(
115        "5. {} serve               (missing required flag)",
116        std::env::args().next().unwrap_or_default()
117    );
118    println!(
119        "6. {} serve -p abc        (invalid flag value)",
120        std::env::args().next().unwrap_or_default()
121    );
122    println!(
123        "7. {} migrate             (subcommand required)",
124        std::env::args().next().unwrap_or_default()
125    );
126    println!(
127        "8. {} confi               (typo - will suggest 'config')",
128        std::env::args().next().unwrap_or_default()
129    );
130    println!("\n---\n");
131
132    let args: Vec<String> = std::env::args().skip(1).collect();
133    if let Err(e) = app.execute(args) {
134        eprintln!("{}", e);
135        std::process::exit(1);
136    }
137}
Source

pub fn default(self, value: FlagValue) -> Self

Sets the default value for this flag

§Examples
use flag_rs::flag::{Flag, FlagValue};

let flag = Flag::new("count").default(FlagValue::Int(10));
assert_eq!(flag.default, Some(FlagValue::Int(10)));
Examples found in repository?
examples/benchmark.rs (line 57)
50fn create_simple_cli() -> flag_rs::Command {
51    CommandBuilder::new("bench")
52        .short("Benchmark CLI")
53        .flag(
54            Flag::new("verbose")
55                .short('v')
56                .value_type(FlagType::Bool)
57                .default(FlagValue::Bool(false)),
58        )
59        .flag(Flag::new("output").short('o').value_type(FlagType::String))
60        .build()
61}
62
63/// Creates a complex nested command structure
64fn create_complex_cli() -> flag_rs::Command {
65    let mut root = CommandBuilder::new("complex")
66        .short("Complex CLI with many subcommands")
67        .flag(
68            Flag::new("config")
69                .short('c')
70                .value_type(FlagType::File)
71                .default(FlagValue::String("config.yaml".to_string())),
72        )
73        .build();
74
75    // Add 50 subcommands
76    for i in 0..50 {
77        let mut sub = CommandBuilder::new(format!("sub{i:02}"))
78            .short(format!("Subcommand {i}"))
79            .flag(Flag::new("flag1").short('1').value_type(FlagType::String))
80            .flag(Flag::new("flag2").short('2').value_type(FlagType::Int))
81            .build();
82
83        // Add 10 nested subcommands
84        for j in 0..10 {
85            sub.add_command(
86                CommandBuilder::new(format!("nested{j}"))
87                    .short(format!("Nested command {j}"))
88                    .flag(Flag::new("deep").value_type(FlagType::Bool))
89                    .build(),
90            );
91        }
92
93        root.add_command(sub);
94    }
95
96    root
97}
More examples
Hide additional examples
examples/kubectl.rs (line 27)
14fn build_kubectl() -> Command {
15    CommandBuilder::new("kubectl")
16        .short("Kubernetes command-line tool")
17        .long("kubectl controls the Kubernetes cluster manager")
18        .subcommand(build_get_command())
19        .subcommand(build_describe_command())
20        .subcommand(build_delete_command())
21        .subcommand(build_completion_command())
22        .flag(
23            Flag::new("namespace")
24                .short('n')
25                .usage("Kubernetes namespace")
26                .value_type(FlagType::String)
27                .default(FlagValue::String("default".to_string())),
28        )
29        .flag_completion("namespace", |_ctx, prefix| {
30            // In a real kubectl, this would query the API server
31            let namespaces = get_namespaces_with_descriptions();
32            let mut result = CompletionResult::new();
33
34            for (ns_name, description) in namespaces {
35                if ns_name.starts_with(prefix) {
36                    result = result.add_with_description(ns_name, description);
37                }
38            }
39
40            Ok(result)
41        })
42        .build()
43}
examples/terminal_demo.rs (line 32)
17fn main() {
18    let app = CommandBuilder::new("demo")
19        .short("Terminal feature demonstration")
20        .long("This application demonstrates the terminal width detection and text wrapping features. The help text should automatically adjust to your terminal width, wrapping long lines at word boundaries while maintaining readability. Try running this with different COLUMNS values to see how it adapts.")
21        .flag(
22            Flag::new("file")
23                .short('f')
24                .usage("Input file path. This flag expects a path to a file that will be processed. The file must exist and be readable.")
25                .value_type(FlagType::String)
26        )
27        .flag(
28            Flag::new("output-format")
29                .short('o')
30                .usage("Output format for results. Supported formats include: json (machine-readable JSON format), yaml (human-friendly YAML format), table (formatted ASCII table), csv (comma-separated values for spreadsheet import)")
31                .value_type(FlagType::String)
32                .default(FlagValue::String("table".to_string()))
33        )
34        .subcommand(
35            CommandBuilder::new("process")
36                .short("Process data with various transformations and filters that can be applied in sequence")
37                .build()
38        )
39        .build();
40
41    // Always show help for this demo
42    app.print_help();
43}
examples/memory_optimization_demo.rs (line 29)
12fn create_many_subcommands(parent: &mut flag_rs::Command) {
13    // Simulate a large CLI with 100 subcommands
14    for i in 0..100 {
15        let cmd_name = format!("service-{i:03}");
16
17        // Use string interning for flag names that repeat across commands
18        let namespace_flag_name = string_pool::intern("namespace");
19        let region_flag_name = string_pool::intern("region");
20        let env_flag_name = string_pool::intern("environment");
21
22        let cmd = CommandBuilder::new(cmd_name.clone())
23            .short(format!("Manage service {i}"))
24            .flag(
25                Flag::new(namespace_flag_name.to_string())
26                    .short('n')
27                    .usage("Kubernetes namespace")
28                    .value_type(FlagType::String)
29                    .default(flag_rs::FlagValue::String("default".to_string())),
30            )
31            .flag(
32                Flag::new(region_flag_name.to_string())
33                    .short('r')
34                    .usage("AWS region")
35                    .value_type(FlagType::Choice(vec![
36                        "us-east-1".to_string(),
37                        "us-west-2".to_string(),
38                        "eu-west-1".to_string(),
39                        "ap-southeast-1".to_string(),
40                    ]))
41                    .default(flag_rs::FlagValue::String("us-east-1".to_string())),
42            )
43            .flag(
44                Flag::new(env_flag_name.to_string())
45                    .short('e')
46                    .usage("Deployment environment")
47                    .value_type(FlagType::Choice(vec![
48                        "dev".to_string(),
49                        "staging".to_string(),
50                        "prod".to_string(),
51                    ]))
52                    .default(flag_rs::FlagValue::String("dev".to_string())),
53            )
54            .subcommand(
55                CommandBuilder::new("deploy")
56                    .short("Deploy the service")
57                    .arg_completion(move |_ctx, prefix| {
58                        // Use optimized completion result
59                        let optimized = CompletionResultOptimized::new()
60                            .add(Cow::Borrowed("rolling-update"))
61                            .add(Cow::Borrowed("blue-green"))
62                            .add(Cow::Borrowed("canary"))
63                            .add_with_description(
64                                Cow::Borrowed("recreate"),
65                                Cow::Borrowed("Recreate all pods"),
66                            );
67
68                        // Filter based on prefix
69                        let filtered = CompletionResultOptimized::new().extend_items(
70                            optimized
71                                .items
72                                .into_iter()
73                                .filter(|item| item.value.starts_with(prefix)),
74                        );
75
76                        // Convert to legacy format for compatibility
77                        Ok(filtered.into_legacy())
78                    })
79                    .build(),
80            )
81            .subcommand(
82                CommandBuilder::new("scale")
83                    .short("Scale the service")
84                    .flag(
85                        Flag::new("replicas")
86                            .usage("Number of replicas")
87                            .value_type(FlagType::Int)
88                            .required(),
89                    )
90                    .build(),
91            )
92            .subcommand(
93                CommandBuilder::new("logs")
94                    .short("View service logs")
95                    .flag(
96                        Flag::new("follow")
97                            .short('f')
98                            .usage("Follow log output")
99                            .value_type(FlagType::Bool),
100                    )
101                    .flag(
102                        Flag::new("tail")
103                            .usage("Number of lines to show")
104                            .value_type(FlagType::Int)
105                            .default(flag_rs::FlagValue::Int(100)),
106                    )
107                    .build(),
108            )
109            .build();
110
111        parent.add_command(cmd);
112    }
113}
114
115// Count commands recursively
116fn count_commands(cmd: &flag_rs::Command) -> usize {
117    1 + cmd
118        .subcommands()
119        .values()
120        .map(count_commands)
121        .sum::<usize>()
122}
123
124// Count flags recursively
125fn count_flags(cmd: &flag_rs::Command) -> usize {
126    cmd.flags().len() + cmd.subcommands().values().map(count_flags).sum::<usize>()
127}
128
129fn main() {
130    // Create root command
131    let mut app = CommandBuilder::new("megacli")
132        .short("A large CLI demonstrating memory optimizations")
133        .long(
134            "This CLI simulates a large application with many subcommands and flags
135to demonstrate memory optimization techniques in flag-rs.
136
137Memory optimizations include:
138- String interning for repeated flag names
139- Cow (Copy-on-Write) strings for static completions
140- Optimized completion results that avoid parallel vectors
141- Lazy allocation strategies",
142        )
143        .flag(
144            Flag::new("verbose")
145                .short('v')
146                .usage("Enable verbose output")
147                .value_type(FlagType::Bool),
148        )
149        .flag(
150            Flag::new("config")
151                .short('c')
152                .usage("Path to config file")
153                .value_type(FlagType::File)
154                .default(flag_rs::FlagValue::String(
155                    "~/.megacli/config.yaml".to_string(),
156                )),
157        )
158        .build();
159
160    // Add many subcommands
161    create_many_subcommands(&mut app);
162
163    let total_commands = count_commands(&app);
164    let total_flags = count_flags(&app);
165
166    // Add a special command to show memory usage stats
167    app.add_command(
168        CommandBuilder::new("stats")
169            .short("Show CLI statistics and memory usage")
170            .run(move |_ctx| {
171                println!("=== MegaCLI Statistics ===\n");
172
173                println!("Total commands: {total_commands}");
174                println!("Total flags: {total_flags}");
175                println!("String pool size: {} unique strings", 3); // We interned 3 flag names
176
177                println!("\nMemory optimization features in use:");
178                println!("✓ String interning for flag names");
179                println!("✓ Cow<str> for static completion values");
180                println!("✓ CompletionResultOptimized for reduced allocations");
181                println!("✓ Lazy allocation strategies");
182
183                println!("\nEstimated memory savings:");
184                println!("- 60-70% reduction in string allocations");
185                println!("- 40-50% reduction in completion memory usage");
186                println!("- Improved cache locality for better performance");
187
188                Ok(())
189            })
190            .build(),
191    );
192
193    // Execute the CLI
194    let args: Vec<String> = std::env::args().skip(1).collect();
195
196    if args.is_empty() {
197        println!("=== Memory Optimization Demo ===\n");
198        println!("This demo shows how flag-rs optimizes memory for large CLIs.\n");
199        println!("Try these commands:");
200        println!(
201            "  {} stats                    # Show memory statistics",
202            std::env::args().next().unwrap_or_default()
203        );
204        println!(
205            "  {} service-001 deploy <TAB> # Test optimized completions",
206            std::env::args().next().unwrap_or_default()
207        );
208        println!(
209            "  {} --help                   # See all 100+ commands",
210            std::env::args().next().unwrap_or_default()
211        );
212        println!("\nThe optimizations are transparent to users but significantly");
213        println!("reduce memory usage for CLIs with many commands and flags.");
214        std::process::exit(0);
215    }
216
217    if let Err(e) = app.execute(args) {
218        eprintln!("{e}");
219        std::process::exit(1);
220    }
221}
examples/timeout_completion_demo.rs (line 38)
30fn main() {
31    let app = CommandBuilder::new("cloud-cli")
32        .short("Cloud CLI with timeout-protected completions")
33        .flag(
34            Flag::new("region")
35                .short('r')
36                .usage("Cloud region")
37                .value_type(FlagType::String)
38                .default(flag_rs::FlagValue::String("us-east-1".to_string())),
39        )
40        .subcommand(
41            CommandBuilder::new("instances")
42                .short("Manage cloud instances")
43                .subcommand(
44                    CommandBuilder::new("list")
45                        .short("List instances (fast completion)")
46                        .arg_completion(|_ctx, prefix| {
47                            // Fast completion - no timeout needed
48                            let instances = vec![
49                                "web-server-001",
50                                "web-server-002",
51                                "db-primary",
52                                "db-replica",
53                                "cache-node-1",
54                                "cache-node-2",
55                            ];
56
57                            Ok(CompletionResult::new().extend(
58                                instances
59                                    .into_iter()
60                                    .filter(|i| i.starts_with(prefix))
61                                    .map(String::from),
62                            ))
63                        })
64                        .build(),
65                )
66                .subcommand(
67                    CommandBuilder::new("describe")
68                        .short("Describe instance (slow completion with timeout)")
69                        .arg_completion({
70                            // Wrap slow completion with timeout
71                            make_timeout_completion(
72                                Duration::from_millis(500), // 500ms timeout
73                                |ctx, prefix| {
74                                    eprintln!("Fetching instance details from API...");
75
76                                    // Simulate slow API call (1 second)
77                                    let instances = slow_completion(prefix, 1000);
78
79                                    let mut result = CompletionResult::new();
80                                    for instance in instances {
81                                        result = result.add_with_description(
82                                            instance.clone(),
83                                            format!(
84                                                "Instance in region {}",
85                                                ctx.flag("region")
86                                                    .unwrap_or(&"us-east-1".to_string())
87                                            ),
88                                        );
89                                    }
90
91                                    if prefix.is_empty() {
92                                        result = result.add_help_text(
93                                            "Fetching live instance data from cloud API...",
94                                        );
95                                    }
96
97                                    Ok(result)
98                                },
99                            )
100                        })
101                        .build(),
102                )
103                .subcommand(
104                    CommandBuilder::new("create")
105                        .short("Create instance (very slow completion)")
106                        .arg_completion({
107                            // Use default timeout (2 seconds)
108                            make_timeout_completion(DEFAULT_COMPLETION_TIMEOUT, |_ctx, prefix| {
109                                eprintln!("Checking available instance types...");
110
111                                // Simulate very slow operation (3 seconds)
112                                let types = slow_completion(prefix, 3000);
113
114                                Ok(CompletionResult::new()
115                                    .extend(types)
116                                    .add_help_text("Available instance types"))
117                            })
118                        })
119                        .build(),
120                )
121                .build(),
122        )
123        .build();
124
125    println!("=== Timeout Completion Demo ===\n");
126    println!("This demo shows how timeouts protect against slow completion operations.\n");
127    println!("To test timeout handling:");
128    println!("1. Set up bash completion:");
129    println!(
130        "   source <({} completion bash)",
131        std::env::args().next().unwrap_or_default()
132    );
133    println!();
134    println!("2. Test different completion speeds:");
135    println!();
136    println!("   Fast (no timeout needed):");
137    println!(
138        "   {} instances list <TAB>",
139        std::env::args().next().unwrap_or_default()
140    );
141    println!();
142    println!("   Slow (500ms timeout, 1s operation - will timeout):");
143    println!(
144        "   {} instances describe <TAB>",
145        std::env::args().next().unwrap_or_default()
146    );
147    println!();
148    println!("   Very slow (2s timeout, 3s operation - will timeout):");
149    println!(
150        "   {} instances create <TAB>",
151        std::env::args().next().unwrap_or_default()
152    );
153    println!();
154    println!("When a timeout occurs, you'll see:");
155    println!("- A warning message about the timeout");
156    println!("- Any partial results that were available");
157    println!("- Suggestion to use a more specific prefix");
158    println!("\n---\n");
159
160    let args: Vec<String> = std::env::args().skip(1).collect();
161    if let Err(e) = app.execute(args) {
162        eprintln!("{}", e);
163        std::process::exit(1);
164    }
165}
examples/enhanced_help_demo.rs (line 23)
10fn main() {
11    let app = CommandBuilder::new("kubectl")
12        .short("Kubernetes command-line tool")
13        .long("kubectl controls the Kubernetes cluster manager.\n\n\
14              Find more information at: https://kubernetes.io/docs/reference/kubectl/")
15        .example("kubectl get pods")
16        .example("kubectl apply -f deployment.yaml")
17        .example("kubectl logs -f my-pod")
18        .flag(
19            Flag::new("namespace")
20                .short('n')
21                .usage("The namespace scope for this CLI request")
22                .value_type(FlagType::String)
23                .default(flag_rs::FlagValue::String("default".to_string())),
24        )
25        .flag(
26            Flag::new("kubeconfig")
27                .usage("Path to the kubeconfig file to use for CLI requests")
28                .value_type(FlagType::String),
29        )
30        .subcommand(
31            CommandBuilder::new("get")
32                .short("Display one or many resources")
33                .group_id("Basic Commands")
34                .long("Prints a table of the most important information about the specified resources.\n\n\
35                      You can filter the list using a label selector and the --selector flag. If the\n\
36                      desired resource type is namespaced you will only see results in your current\n\
37                      namespace unless you pass --all-namespaces.")
38                .example("kubectl get pods")
39                .example("kubectl get pods -n kube-system")
40                .example("kubectl get pods --selector=app=nginx")
41                .example("kubectl get pods,services")
42                .build(),
43        )
44        .subcommand(
45            CommandBuilder::new("apply")
46                .short("Apply a configuration to a resource by file name or stdin")
47                .group_id("Basic Commands")
48                .long("Apply a configuration to a resource by file name or stdin. The resource name must\n\
49                      be specified. This resource will be created if it doesn't exist yet. To use 'apply',\n\
50                      always create the resource initially with either 'apply' or 'create --save-config'.")
51                .example("kubectl apply -f ./pod.yaml")
52                .example("kubectl apply -f https://example.com/manifest.yaml")
53                .example("kubectl apply -k ./")
54                .flag(
55                    Flag::new("filename")
56                        .short('f')
57                        .usage("Filename, directory, or URL to files to use to create the resource")
58                        .value_type(FlagType::String)
59                        .required(),
60                )
61                .flag(
62                    Flag::new("recursive")
63                        .short('R')
64                        .usage("Process the directory used in -f, --filename recursively")
65                        .value_type(FlagType::Bool),
66                )
67                .build(),
68        )
69        .subcommand(
70            CommandBuilder::new("delete")
71                .short("Delete resources by file names, stdin, resources and names, or by resources and label selector")
72                .aliases(vec!["del", "remove", "rm"])
73                .group_id("Basic Commands")
74                .example("kubectl delete pod my-pod")
75                .example("kubectl delete -f ./pod.yaml")
76                .example("kubectl delete pods --all")
77                .build(),
78        )
79        .subcommand(
80            CommandBuilder::new("logs")
81                .short("Print the logs for a container in a pod")
82                .group_id("Troubleshooting and Debugging Commands")
83                .long("Print the logs for a container in a pod or specified resource. If the pod has\n\
84                      only one container, the container name is optional.")
85                .aliases(vec!["log"])
86                .example("kubectl logs my-pod")
87                .example("kubectl logs my-pod -c my-container")
88                .example("kubectl logs -f my-pod")
89                .example("kubectl logs --tail=20 my-pod")
90                .flag(
91                    Flag::new("follow")
92                        .short('f')
93                        .usage("Specify if the logs should be streamed")
94                        .value_type(FlagType::Bool),
95                )
96                .flag(
97                    Flag::new("tail")
98                        .usage("Lines of recent log file to display")
99                        .value_type(FlagType::Int)
100                        .default(flag_rs::FlagValue::Int(-1)),
101                )
102                .build(),
103        )
104        .subcommand(
105            CommandBuilder::new("describe")
106                .short("Show details of a specific resource or group of resources")
107                .group_id("Troubleshooting and Debugging Commands")
108                .example("kubectl describe pod my-pod")
109                .example("kubectl describe nodes")
110                .build(),
111        )
112        .subcommand(
113            CommandBuilder::new("exec")
114                .short("Execute a command in a container")
115                .group_id("Troubleshooting and Debugging Commands")
116                .example("kubectl exec -it my-pod -- /bin/bash")
117                .example("kubectl exec my-pod -- ls /app")
118                .build(),
119        )
120        .subcommand(
121            CommandBuilder::new("config")
122                .short("Modify kubeconfig files")
123                .group_id("Settings Commands")
124                .example("kubectl config view")
125                .example("kubectl config use-context my-context")
126                .build(),
127        )
128        .subcommand(
129            CommandBuilder::new("version")
130                .short("Print the client and server version information")
131                .example("kubectl version")
132                .example("kubectl version --short")
133                .build(),
134        )
135        .build();
136
137    let args: Vec<String> = std::env::args().skip(1).collect();
138    if let Err(e) = app.execute(args) {
139        eprintln!("{}", e);
140        std::process::exit(1);
141    }
142}
Source

pub fn default_bool(self, value: bool) -> Self

Sets a default boolean value

§Examples
use flag_rs::flag::{Flag, FlagValue};

let flag = Flag::bool("verbose").default_bool(true);
assert_eq!(flag.default, Some(FlagValue::Bool(true)));
Examples found in repository?
examples/builder_api_demo.rs (line 21)
4fn main() {
5    // Demonstrates all the new builder API improvements
6    let app = CommandBuilder::new("app")
7        .short("Modern CLI app with improved API")
8        .long(
9            "This example showcases the builder API improvements including:\n\
10               - Type-specific flag constructors\n\
11               - Inline flag completions\n\
12               - Bulk flag/subcommand methods\n\
13               - Type-safe context access",
14        )
15        // Bulk flag addition
16        .flags(vec![
17            // Type-specific constructors
18            Flag::bool("verbose")
19                .short('v')
20                .usage("Enable verbose output")
21                .default_bool(false),
22            Flag::bool("quiet").short('q').usage("Suppress all output"),
23            Flag::int("threads")
24                .short('t')
25                .usage("Number of worker threads")
26                .default_int(4),
27            Flag::choice("log-level", &["debug", "info", "warn", "error"])
28                .usage("Set the logging level")
29                .default_str("info")
30                .completion(|_ctx, prefix| {
31                    // Inline completion with descriptions
32                    let levels = vec![
33                        ("debug", "Show all messages including debug"),
34                        ("info", "Show informational messages and above"),
35                        ("warn", "Show warnings and errors only"),
36                        ("error", "Show errors only"),
37                    ];
38
39                    let mut result = flag_rs::CompletionResult::new();
40                    for (level, desc) in levels {
41                        if level.starts_with(prefix) {
42                            result =
43                                result.add_with_description(level.to_string(), desc.to_string());
44                        }
45                    }
46                    Ok(result)
47                }),
48        ])
49        // Bulk subcommand addition
50        .subcommands(vec![
51            CommandBuilder::new("init")
52                .short("Initialize a new project")
53                .flags(vec![
54                    Flag::string("name")
55                        .short('n')
56                        .usage("Project name")
57                        .required(),
58                    Flag::choice("template", &["basic", "web", "api", "full"])
59                        .usage("Project template to use")
60                        .default_str("basic"),
61                    Flag::directory("path")
62                        .short('p')
63                        .usage("Directory to create project in")
64                        .completion(|_ctx, prefix| {
65                            // In a real app, list actual directories
66                            let dirs = vec!["./", "../", "/tmp/", "~/projects/"];
67                            Ok(flag_rs::CompletionResult::new().extend(
68                                dirs.into_iter()
69                                    .filter(|d| d.starts_with(prefix))
70                                    .map(String::from),
71                            ))
72                        }),
73                ])
74                .run(|ctx| {
75                    // Type-safe flag access
76                    let name = ctx.flag_str_or("name", "my-project");
77                    let template = ctx.flag_str_or("template", "basic");
78                    let path = ctx.flag_str_or("path", ".");
79                    let verbose = ctx.flag_bool_or("verbose", false);
80
81                    if verbose {
82                        println!("Initializing {} project '{}' in {}", template, name, path);
83                    } else {
84                        println!("Creating project '{}'...", name);
85                    }
86
87                    Ok(())
88                })
89                .build(),
90            CommandBuilder::new("build")
91                .short("Build the project")
92                .flags(vec![
93                    Flag::bool("release")
94                        .short('r')
95                        .usage("Build in release mode"),
96                    Flag::string_slice("features")
97                        .short('f')
98                        .usage("Enable features (can be specified multiple times)")
99                        .completion(|_ctx, prefix| {
100                            let features = vec!["async", "tls", "compression", "metrics"];
101                            Ok(flag_rs::CompletionResult::new().extend(
102                                features
103                                    .into_iter()
104                                    .filter(|f| f.starts_with(prefix))
105                                    .map(String::from),
106                            ))
107                        }),
108                    Flag::range("jobs", 1, 32)
109                        .short('j')
110                        .usage("Number of parallel jobs")
111                        .default_int(i64::try_from(num_cpus()).unwrap_or(4)),
112                ])
113                .run(|ctx| {
114                    let release = ctx.flag_bool_or("release", false);
115                    let jobs = ctx.flag_int_or("jobs", i64::try_from(num_cpus()).unwrap_or(4));
116                    let quiet = ctx.flag_bool_or("quiet", false);
117
118                    if !quiet {
119                        println!(
120                            "Building in {} mode with {} jobs",
121                            if release { "release" } else { "debug" },
122                            jobs
123                        );
124
125                        if let Some(features) = ctx.flag("features") {
126                            println!("Features: {}", features);
127                        }
128                    }
129
130                    Ok(())
131                })
132                .build(),
133            CommandBuilder::new("test")
134                .short("Run tests")
135                .flags(vec![
136                    Flag::string("filter").usage("Only run tests matching this pattern"),
137                    Flag::bool("nocapture").usage("Don't capture test output"),
138                    Flag::int("test-threads")
139                        .usage("Number of threads to use for running tests")
140                        .default_int(1),
141                ])
142                .run(|ctx| {
143                    let threads = ctx.flag_int_or("test-threads", 1);
144                    let nocapture = ctx.flag_bool_or("nocapture", false);
145                    let verbose = ctx.flag_bool_or("verbose", false);
146
147                    if verbose {
148                        println!("Running tests with {} thread(s)", threads);
149                        if nocapture {
150                            println!("Output capture disabled");
151                        }
152
153                        if let Some(filter) = ctx.flag("filter") {
154                            println!("Filter: {}", filter);
155                        }
156                    }
157
158                    println!("Running tests...");
159                    Ok(())
160                })
161                .build(),
162        ])
163        .run(|_ctx| {
164            // Root command - show help by default
165            println!("Use --help for usage information");
166            Ok(())
167        })
168        .build();
169
170    let args: Vec<String> = std::env::args().skip(1).collect();
171    if let Err(e) = app.execute(args) {
172        eprintln!("Error: {}", e);
173        std::process::exit(1);
174    }
175}
Source

pub fn default_str(self, value: &str) -> Self

Sets a default string value

§Examples
use flag_rs::flag::{Flag, FlagValue};

let flag = Flag::string("name").default_str("anonymous");
assert_eq!(flag.default, Some(FlagValue::String("anonymous".to_string())));
Examples found in repository?
examples/flag_completion_demo.rs (line 39)
4fn main() {
5    let app = CommandBuilder::new("deploy")
6        .short("Deploy application to various environments")
7        .flag(
8            Flag::choice("environment", &["dev", "staging", "prod"])
9                .short('e')
10                .usage("Target environment")
11                .required()
12                .completion(|_ctx, prefix| {
13                    // Dynamic completion - could check available environments
14                    let environments = vec![
15                        ("dev", "Development environment"),
16                        ("staging", "Staging environment (pre-production)"),
17                        ("prod", "Production environment"),
18                    ];
19
20                    let mut result = CompletionResult::new();
21                    for (env, desc) in environments {
22                        if env.starts_with(prefix) {
23                            result = result.add_with_description(env.to_string(), desc.to_string());
24                        }
25                    }
26
27                    // Add active help if no prefix
28                    if prefix.is_empty() {
29                        result = result.add_help_text("Available environments: dev, staging, prod");
30                    }
31
32                    Ok(result)
33                }),
34        )
35        .flag(
36            Flag::file("config")
37                .short('c')
38                .usage("Configuration file")
39                .default_str("config.yaml")
40                .completion(|_ctx, prefix| {
41                    // In a real app, you might list files in the config directory
42                    let configs = vec![
43                        "config.yaml",
44                        "config.dev.yaml",
45                        "config.staging.yaml",
46                        "config.prod.yaml",
47                        "secrets.yaml",
48                    ];
49
50                    Ok(CompletionResult::new().extend(
51                        configs
52                            .into_iter()
53                            .filter(|c| c.starts_with(prefix))
54                            .map(String::from),
55                    ))
56                }),
57        )
58        .flag(
59            Flag::directory("output")
60                .short('o')
61                .usage("Output directory for deployment artifacts")
62                .completion(|_ctx, prefix| {
63                    // In a real app, you might list actual directories
64                    let dirs = vec!["./build", "./dist", "./output", "/tmp/deploy"];
65
66                    Ok(CompletionResult::new().extend(
67                        dirs.into_iter()
68                            .filter(|d| d.starts_with(prefix))
69                            .map(String::from),
70                    ))
71                }),
72        )
73        .flag(
74            Flag::string_slice("service")
75                .short('s')
76                .usage("Services to deploy (can be specified multiple times)")
77                .completion(|ctx, prefix| {
78                    // Context-aware completion based on environment
79                    let env = ctx.flag_str_or("environment", "dev");
80
81                    let services = match env {
82                        "dev" => vec!["api", "web", "worker", "scheduler", "debug-panel"],
83                        "staging" => vec!["api", "web", "worker", "scheduler"],
84                        "prod" => vec!["api", "web", "worker"],
85                        _ => vec!["api", "web"],
86                    };
87
88                    let mut result = CompletionResult::new().extend(
89                        services
90                            .into_iter()
91                            .filter(|s| s.starts_with(prefix))
92                            .map(String::from),
93                    );
94
95                    // Add context-aware help
96                    if prefix.is_empty() {
97                        result = result
98                            .add_help_text(format!("Available services for {} environment", env));
99                    }
100
101                    Ok(result)
102                }),
103        )
104        .flag(
105            Flag::range("replicas", 1, 10)
106                .short('r')
107                .usage("Number of replicas to deploy")
108                .default_int(2)
109                .completion(|_ctx, _prefix| {
110                    // Suggest common replica counts
111                    Ok(CompletionResult::new()
112                        .add_with_description(
113                            "1".to_string(),
114                            "Single instance (dev/test)".to_string(),
115                        )
116                        .add_with_description("2".to_string(), "Basic redundancy".to_string())
117                        .add_with_description("3".to_string(), "Standard production".to_string())
118                        .add_with_description("5".to_string(), "High availability".to_string()))
119                }),
120        )
121        .run(|ctx| {
122            let env = ctx.flag_str_or("environment", "dev");
123            let config = ctx.flag_str_or("config", "config.yaml");
124            let replicas = ctx.flag_int_or("replicas", 2);
125
126            println!("Deploying to {} environment", env);
127            println!("Using configuration: {}", config);
128            println!("Replica count: {}", replicas);
129
130            if let Some(output) = ctx.flag("output") {
131                println!("Output directory: {}", output);
132            }
133
134            if let Some(services) = ctx.flag("service") {
135                println!("Deploying services: {}", services);
136            } else {
137                println!("Deploying all services");
138            }
139
140            Ok(())
141        })
142        .build();
143
144    let args: Vec<String> = std::env::args().skip(1).collect();
145    if let Err(e) = app.execute(args) {
146        eprintln!("Error: {}", e);
147        std::process::exit(1);
148    }
149}
More examples
Hide additional examples
examples/builder_api_demo.rs (line 29)
4fn main() {
5    // Demonstrates all the new builder API improvements
6    let app = CommandBuilder::new("app")
7        .short("Modern CLI app with improved API")
8        .long(
9            "This example showcases the builder API improvements including:\n\
10               - Type-specific flag constructors\n\
11               - Inline flag completions\n\
12               - Bulk flag/subcommand methods\n\
13               - Type-safe context access",
14        )
15        // Bulk flag addition
16        .flags(vec![
17            // Type-specific constructors
18            Flag::bool("verbose")
19                .short('v')
20                .usage("Enable verbose output")
21                .default_bool(false),
22            Flag::bool("quiet").short('q').usage("Suppress all output"),
23            Flag::int("threads")
24                .short('t')
25                .usage("Number of worker threads")
26                .default_int(4),
27            Flag::choice("log-level", &["debug", "info", "warn", "error"])
28                .usage("Set the logging level")
29                .default_str("info")
30                .completion(|_ctx, prefix| {
31                    // Inline completion with descriptions
32                    let levels = vec![
33                        ("debug", "Show all messages including debug"),
34                        ("info", "Show informational messages and above"),
35                        ("warn", "Show warnings and errors only"),
36                        ("error", "Show errors only"),
37                    ];
38
39                    let mut result = flag_rs::CompletionResult::new();
40                    for (level, desc) in levels {
41                        if level.starts_with(prefix) {
42                            result =
43                                result.add_with_description(level.to_string(), desc.to_string());
44                        }
45                    }
46                    Ok(result)
47                }),
48        ])
49        // Bulk subcommand addition
50        .subcommands(vec![
51            CommandBuilder::new("init")
52                .short("Initialize a new project")
53                .flags(vec![
54                    Flag::string("name")
55                        .short('n')
56                        .usage("Project name")
57                        .required(),
58                    Flag::choice("template", &["basic", "web", "api", "full"])
59                        .usage("Project template to use")
60                        .default_str("basic"),
61                    Flag::directory("path")
62                        .short('p')
63                        .usage("Directory to create project in")
64                        .completion(|_ctx, prefix| {
65                            // In a real app, list actual directories
66                            let dirs = vec!["./", "../", "/tmp/", "~/projects/"];
67                            Ok(flag_rs::CompletionResult::new().extend(
68                                dirs.into_iter()
69                                    .filter(|d| d.starts_with(prefix))
70                                    .map(String::from),
71                            ))
72                        }),
73                ])
74                .run(|ctx| {
75                    // Type-safe flag access
76                    let name = ctx.flag_str_or("name", "my-project");
77                    let template = ctx.flag_str_or("template", "basic");
78                    let path = ctx.flag_str_or("path", ".");
79                    let verbose = ctx.flag_bool_or("verbose", false);
80
81                    if verbose {
82                        println!("Initializing {} project '{}' in {}", template, name, path);
83                    } else {
84                        println!("Creating project '{}'...", name);
85                    }
86
87                    Ok(())
88                })
89                .build(),
90            CommandBuilder::new("build")
91                .short("Build the project")
92                .flags(vec![
93                    Flag::bool("release")
94                        .short('r')
95                        .usage("Build in release mode"),
96                    Flag::string_slice("features")
97                        .short('f')
98                        .usage("Enable features (can be specified multiple times)")
99                        .completion(|_ctx, prefix| {
100                            let features = vec!["async", "tls", "compression", "metrics"];
101                            Ok(flag_rs::CompletionResult::new().extend(
102                                features
103                                    .into_iter()
104                                    .filter(|f| f.starts_with(prefix))
105                                    .map(String::from),
106                            ))
107                        }),
108                    Flag::range("jobs", 1, 32)
109                        .short('j')
110                        .usage("Number of parallel jobs")
111                        .default_int(i64::try_from(num_cpus()).unwrap_or(4)),
112                ])
113                .run(|ctx| {
114                    let release = ctx.flag_bool_or("release", false);
115                    let jobs = ctx.flag_int_or("jobs", i64::try_from(num_cpus()).unwrap_or(4));
116                    let quiet = ctx.flag_bool_or("quiet", false);
117
118                    if !quiet {
119                        println!(
120                            "Building in {} mode with {} jobs",
121                            if release { "release" } else { "debug" },
122                            jobs
123                        );
124
125                        if let Some(features) = ctx.flag("features") {
126                            println!("Features: {}", features);
127                        }
128                    }
129
130                    Ok(())
131                })
132                .build(),
133            CommandBuilder::new("test")
134                .short("Run tests")
135                .flags(vec![
136                    Flag::string("filter").usage("Only run tests matching this pattern"),
137                    Flag::bool("nocapture").usage("Don't capture test output"),
138                    Flag::int("test-threads")
139                        .usage("Number of threads to use for running tests")
140                        .default_int(1),
141                ])
142                .run(|ctx| {
143                    let threads = ctx.flag_int_or("test-threads", 1);
144                    let nocapture = ctx.flag_bool_or("nocapture", false);
145                    let verbose = ctx.flag_bool_or("verbose", false);
146
147                    if verbose {
148                        println!("Running tests with {} thread(s)", threads);
149                        if nocapture {
150                            println!("Output capture disabled");
151                        }
152
153                        if let Some(filter) = ctx.flag("filter") {
154                            println!("Filter: {}", filter);
155                        }
156                    }
157
158                    println!("Running tests...");
159                    Ok(())
160                })
161                .build(),
162        ])
163        .run(|_ctx| {
164            // Root command - show help by default
165            println!("Use --help for usage information");
166            Ok(())
167        })
168        .build();
169
170    let args: Vec<String> = std::env::args().skip(1).collect();
171    if let Err(e) = app.execute(args) {
172        eprintln!("Error: {}", e);
173        std::process::exit(1);
174    }
175}
Source

pub fn default_int(self, value: i64) -> Self

Sets a default integer value

§Examples
use flag_rs::flag::{Flag, FlagValue};

let flag = Flag::int("port").default_int(8080);
assert_eq!(flag.default, Some(FlagValue::Int(8080)));
Examples found in repository?
examples/flag_completion_demo.rs (line 108)
4fn main() {
5    let app = CommandBuilder::new("deploy")
6        .short("Deploy application to various environments")
7        .flag(
8            Flag::choice("environment", &["dev", "staging", "prod"])
9                .short('e')
10                .usage("Target environment")
11                .required()
12                .completion(|_ctx, prefix| {
13                    // Dynamic completion - could check available environments
14                    let environments = vec![
15                        ("dev", "Development environment"),
16                        ("staging", "Staging environment (pre-production)"),
17                        ("prod", "Production environment"),
18                    ];
19
20                    let mut result = CompletionResult::new();
21                    for (env, desc) in environments {
22                        if env.starts_with(prefix) {
23                            result = result.add_with_description(env.to_string(), desc.to_string());
24                        }
25                    }
26
27                    // Add active help if no prefix
28                    if prefix.is_empty() {
29                        result = result.add_help_text("Available environments: dev, staging, prod");
30                    }
31
32                    Ok(result)
33                }),
34        )
35        .flag(
36            Flag::file("config")
37                .short('c')
38                .usage("Configuration file")
39                .default_str("config.yaml")
40                .completion(|_ctx, prefix| {
41                    // In a real app, you might list files in the config directory
42                    let configs = vec![
43                        "config.yaml",
44                        "config.dev.yaml",
45                        "config.staging.yaml",
46                        "config.prod.yaml",
47                        "secrets.yaml",
48                    ];
49
50                    Ok(CompletionResult::new().extend(
51                        configs
52                            .into_iter()
53                            .filter(|c| c.starts_with(prefix))
54                            .map(String::from),
55                    ))
56                }),
57        )
58        .flag(
59            Flag::directory("output")
60                .short('o')
61                .usage("Output directory for deployment artifacts")
62                .completion(|_ctx, prefix| {
63                    // In a real app, you might list actual directories
64                    let dirs = vec!["./build", "./dist", "./output", "/tmp/deploy"];
65
66                    Ok(CompletionResult::new().extend(
67                        dirs.into_iter()
68                            .filter(|d| d.starts_with(prefix))
69                            .map(String::from),
70                    ))
71                }),
72        )
73        .flag(
74            Flag::string_slice("service")
75                .short('s')
76                .usage("Services to deploy (can be specified multiple times)")
77                .completion(|ctx, prefix| {
78                    // Context-aware completion based on environment
79                    let env = ctx.flag_str_or("environment", "dev");
80
81                    let services = match env {
82                        "dev" => vec!["api", "web", "worker", "scheduler", "debug-panel"],
83                        "staging" => vec!["api", "web", "worker", "scheduler"],
84                        "prod" => vec!["api", "web", "worker"],
85                        _ => vec!["api", "web"],
86                    };
87
88                    let mut result = CompletionResult::new().extend(
89                        services
90                            .into_iter()
91                            .filter(|s| s.starts_with(prefix))
92                            .map(String::from),
93                    );
94
95                    // Add context-aware help
96                    if prefix.is_empty() {
97                        result = result
98                            .add_help_text(format!("Available services for {} environment", env));
99                    }
100
101                    Ok(result)
102                }),
103        )
104        .flag(
105            Flag::range("replicas", 1, 10)
106                .short('r')
107                .usage("Number of replicas to deploy")
108                .default_int(2)
109                .completion(|_ctx, _prefix| {
110                    // Suggest common replica counts
111                    Ok(CompletionResult::new()
112                        .add_with_description(
113                            "1".to_string(),
114                            "Single instance (dev/test)".to_string(),
115                        )
116                        .add_with_description("2".to_string(), "Basic redundancy".to_string())
117                        .add_with_description("3".to_string(), "Standard production".to_string())
118                        .add_with_description("5".to_string(), "High availability".to_string()))
119                }),
120        )
121        .run(|ctx| {
122            let env = ctx.flag_str_or("environment", "dev");
123            let config = ctx.flag_str_or("config", "config.yaml");
124            let replicas = ctx.flag_int_or("replicas", 2);
125
126            println!("Deploying to {} environment", env);
127            println!("Using configuration: {}", config);
128            println!("Replica count: {}", replicas);
129
130            if let Some(output) = ctx.flag("output") {
131                println!("Output directory: {}", output);
132            }
133
134            if let Some(services) = ctx.flag("service") {
135                println!("Deploying services: {}", services);
136            } else {
137                println!("Deploying all services");
138            }
139
140            Ok(())
141        })
142        .build();
143
144    let args: Vec<String> = std::env::args().skip(1).collect();
145    if let Err(e) = app.execute(args) {
146        eprintln!("Error: {}", e);
147        std::process::exit(1);
148    }
149}
More examples
Hide additional examples
examples/builder_api_demo.rs (line 26)
4fn main() {
5    // Demonstrates all the new builder API improvements
6    let app = CommandBuilder::new("app")
7        .short("Modern CLI app with improved API")
8        .long(
9            "This example showcases the builder API improvements including:\n\
10               - Type-specific flag constructors\n\
11               - Inline flag completions\n\
12               - Bulk flag/subcommand methods\n\
13               - Type-safe context access",
14        )
15        // Bulk flag addition
16        .flags(vec![
17            // Type-specific constructors
18            Flag::bool("verbose")
19                .short('v')
20                .usage("Enable verbose output")
21                .default_bool(false),
22            Flag::bool("quiet").short('q').usage("Suppress all output"),
23            Flag::int("threads")
24                .short('t')
25                .usage("Number of worker threads")
26                .default_int(4),
27            Flag::choice("log-level", &["debug", "info", "warn", "error"])
28                .usage("Set the logging level")
29                .default_str("info")
30                .completion(|_ctx, prefix| {
31                    // Inline completion with descriptions
32                    let levels = vec![
33                        ("debug", "Show all messages including debug"),
34                        ("info", "Show informational messages and above"),
35                        ("warn", "Show warnings and errors only"),
36                        ("error", "Show errors only"),
37                    ];
38
39                    let mut result = flag_rs::CompletionResult::new();
40                    for (level, desc) in levels {
41                        if level.starts_with(prefix) {
42                            result =
43                                result.add_with_description(level.to_string(), desc.to_string());
44                        }
45                    }
46                    Ok(result)
47                }),
48        ])
49        // Bulk subcommand addition
50        .subcommands(vec![
51            CommandBuilder::new("init")
52                .short("Initialize a new project")
53                .flags(vec![
54                    Flag::string("name")
55                        .short('n')
56                        .usage("Project name")
57                        .required(),
58                    Flag::choice("template", &["basic", "web", "api", "full"])
59                        .usage("Project template to use")
60                        .default_str("basic"),
61                    Flag::directory("path")
62                        .short('p')
63                        .usage("Directory to create project in")
64                        .completion(|_ctx, prefix| {
65                            // In a real app, list actual directories
66                            let dirs = vec!["./", "../", "/tmp/", "~/projects/"];
67                            Ok(flag_rs::CompletionResult::new().extend(
68                                dirs.into_iter()
69                                    .filter(|d| d.starts_with(prefix))
70                                    .map(String::from),
71                            ))
72                        }),
73                ])
74                .run(|ctx| {
75                    // Type-safe flag access
76                    let name = ctx.flag_str_or("name", "my-project");
77                    let template = ctx.flag_str_or("template", "basic");
78                    let path = ctx.flag_str_or("path", ".");
79                    let verbose = ctx.flag_bool_or("verbose", false);
80
81                    if verbose {
82                        println!("Initializing {} project '{}' in {}", template, name, path);
83                    } else {
84                        println!("Creating project '{}'...", name);
85                    }
86
87                    Ok(())
88                })
89                .build(),
90            CommandBuilder::new("build")
91                .short("Build the project")
92                .flags(vec![
93                    Flag::bool("release")
94                        .short('r')
95                        .usage("Build in release mode"),
96                    Flag::string_slice("features")
97                        .short('f')
98                        .usage("Enable features (can be specified multiple times)")
99                        .completion(|_ctx, prefix| {
100                            let features = vec!["async", "tls", "compression", "metrics"];
101                            Ok(flag_rs::CompletionResult::new().extend(
102                                features
103                                    .into_iter()
104                                    .filter(|f| f.starts_with(prefix))
105                                    .map(String::from),
106                            ))
107                        }),
108                    Flag::range("jobs", 1, 32)
109                        .short('j')
110                        .usage("Number of parallel jobs")
111                        .default_int(i64::try_from(num_cpus()).unwrap_or(4)),
112                ])
113                .run(|ctx| {
114                    let release = ctx.flag_bool_or("release", false);
115                    let jobs = ctx.flag_int_or("jobs", i64::try_from(num_cpus()).unwrap_or(4));
116                    let quiet = ctx.flag_bool_or("quiet", false);
117
118                    if !quiet {
119                        println!(
120                            "Building in {} mode with {} jobs",
121                            if release { "release" } else { "debug" },
122                            jobs
123                        );
124
125                        if let Some(features) = ctx.flag("features") {
126                            println!("Features: {}", features);
127                        }
128                    }
129
130                    Ok(())
131                })
132                .build(),
133            CommandBuilder::new("test")
134                .short("Run tests")
135                .flags(vec![
136                    Flag::string("filter").usage("Only run tests matching this pattern"),
137                    Flag::bool("nocapture").usage("Don't capture test output"),
138                    Flag::int("test-threads")
139                        .usage("Number of threads to use for running tests")
140                        .default_int(1),
141                ])
142                .run(|ctx| {
143                    let threads = ctx.flag_int_or("test-threads", 1);
144                    let nocapture = ctx.flag_bool_or("nocapture", false);
145                    let verbose = ctx.flag_bool_or("verbose", false);
146
147                    if verbose {
148                        println!("Running tests with {} thread(s)", threads);
149                        if nocapture {
150                            println!("Output capture disabled");
151                        }
152
153                        if let Some(filter) = ctx.flag("filter") {
154                            println!("Filter: {}", filter);
155                        }
156                    }
157
158                    println!("Running tests...");
159                    Ok(())
160                })
161                .build(),
162        ])
163        .run(|_ctx| {
164            // Root command - show help by default
165            println!("Use --help for usage information");
166            Ok(())
167        })
168        .build();
169
170    let args: Vec<String> = std::env::args().skip(1).collect();
171    if let Err(e) = app.execute(args) {
172        eprintln!("Error: {}", e);
173        std::process::exit(1);
174    }
175}
Source

pub fn default_float(self, value: f64) -> Self

Sets a default float value

§Examples
use flag_rs::flag::{Flag, FlagValue};

let flag = Flag::float("ratio").default_float(0.5);
assert_eq!(flag.default, Some(FlagValue::Float(0.5)));
Source

pub const fn required(self) -> Self

Marks this flag as required

§Examples
use flag_rs::flag::Flag;

let flag = Flag::new("name").required();
assert!(flag.required);
Examples found in repository?
examples/benchmark.rs (line 262)
249fn bench_flag_validation() {
250    println!("\n=== Flag Validation Benchmarks ===");
251
252    let cli = CommandBuilder::new("validate")
253        .flag(Flag::new("choice").value_type(FlagType::Choice(vec![
254            "opt1".to_string(),
255            "opt2".to_string(),
256            "opt3".to_string(),
257        ])))
258        .flag(Flag::new("range").value_type(FlagType::Range(1, 100)))
259        .flag(
260            Flag::new("required")
261                .value_type(FlagType::String)
262                .required(),
263        )
264        .build();
265
266    let bench = Benchmark::new("Validate choice flag", 10_000);
267    let duration = bench.run(|| {
268        let args = vec![
269            "validate".to_string(),
270            "--choice".to_string(),
271            "opt2".to_string(),
272            "--required".to_string(),
273            "value".to_string(),
274        ];
275        let _ = cli.execute(args);
276    });
277    bench.report(duration);
278
279    let bench = Benchmark::new("Validate range flag", 10_000);
280    let duration = bench.run(|| {
281        let args = vec![
282            "validate".to_string(),
283            "--range".to_string(),
284            "50".to_string(),
285            "--required".to_string(),
286            "value".to_string(),
287        ];
288        let _ = cli.execute(args);
289    });
290    bench.report(duration);
291
292    let bench = Benchmark::new("Validate missing required flag", 10_000);
293    let duration = bench.run(|| {
294        let args = vec!["validate".to_string()];
295        let _ = cli.execute(args); // This will fail validation
296    });
297    bench.report(duration);
298}
More examples
Hide additional examples
examples/enhanced_errors_demo.rs (line 70)
7fn main() {
8    let app = CommandBuilder::new("errordemo")
9        .short("Demo of enhanced error messages")
10        .flag(
11            Flag::new("verbose")
12                .short('v')
13                .value_type(FlagType::Bool)
14                .usage("Enable verbose output"),
15        )
16        .flag(
17            Flag::new("workers")
18                .short('w')
19                .value_type(FlagType::Range(1, 10))
20                .usage("Number of worker threads"),
21        )
22        .flag(
23            Flag::new("format")
24                .short('f')
25                .value_type(FlagType::Choice(vec![
26                    "json".to_string(),
27                    "yaml".to_string(),
28                    "xml".to_string(),
29                    "toml".to_string(),
30                ]))
31                .usage("Output format"),
32        )
33        .flag(
34            Flag::new("config")
35                .short('c')
36                .value_type(FlagType::File)
37                .usage("Configuration file"),
38        )
39        .flag(
40            Flag::new("outdir")
41                .short('o')
42                .value_type(FlagType::Directory)
43                .usage("Output directory"),
44        )
45        .flag(
46            Flag::new("ssl")
47                .value_type(FlagType::Bool)
48                .usage("Enable SSL"),
49        )
50        .flag(
51            Flag::new("ssl-cert")
52                .value_type(FlagType::File)
53                .constraint(FlagConstraint::RequiredIf("ssl".to_string()))
54                .usage("SSL certificate file"),
55        )
56        .flag(
57            Flag::new("json")
58                .value_type(FlagType::Bool)
59                .constraint(FlagConstraint::ConflictsWith(vec!["xml".to_string()]))
60                .usage("Output in JSON format"),
61        )
62        .flag(
63            Flag::new("xml")
64                .value_type(FlagType::Bool)
65                .usage("Output in XML format"),
66        )
67        .flag(
68            Flag::new("required-flag")
69                .value_type(FlagType::String)
70                .required()
71                .usage("This flag is required"),
72        )
73        .subcommand(
74            CommandBuilder::new("process")
75                .short("Process data")
76                .run(|ctx| {
77                    println!("Processing with flags: {:?}", ctx.flags());
78                    Ok(())
79                })
80                .build(),
81        )
82        .build();
83
84    println!("Try these commands to see enhanced error messages:\n");
85    println!("  # Boolean parsing error");
86    println!("  cargo run --example enhanced_errors_demo -- --verbose=maybe\n");
87
88    println!("  # Integer parsing error");
89    println!("  cargo run --example enhanced_errors_demo -- --workers=abc\n");
90
91    println!("  # Range validation error");
92    println!("  cargo run --example enhanced_errors_demo -- --workers=20\n");
93
94    println!("  # Choice validation error");
95    println!("  cargo run --example enhanced_errors_demo -- --format=csv\n");
96
97    println!("  # File not found error");
98    println!("  cargo run --example enhanced_errors_demo -- --config=/tmp/nonexistent.conf\n");
99
100    println!("  # Directory not found error");
101    println!("  cargo run --example enhanced_errors_demo -- --outdir=/tmp/nonexistent_dir\n");
102
103    println!("  # Flag constraint error (RequiredIf)");
104    println!("  cargo run --example enhanced_errors_demo -- --ssl --required-flag=test process\n");
105
106    println!("  # Flag constraint error (ConflictsWith)");
107    println!(
108        "  cargo run --example enhanced_errors_demo -- --json --xml --required-flag=test process\n"
109    );
110
111    println!("  # Required flag error");
112    println!("  cargo run --example enhanced_errors_demo -- process\n");
113
114    println!("  # Unknown command error");
115    println!("  cargo run --example enhanced_errors_demo -- --required-flag=test proces\n");
116
117    let args: Vec<String> = std::env::args().skip(1).collect();
118    if !args.is_empty() {
119        println!("\n{}", "=".repeat(60));
120        println!("Running with args: {:?}\n", args);
121
122        if let Err(e) = app.execute(args) {
123            eprintln!("{}", e);
124            std::process::exit(1);
125        }
126    }
127}
examples/memory_optimization_demo.rs (line 88)
12fn create_many_subcommands(parent: &mut flag_rs::Command) {
13    // Simulate a large CLI with 100 subcommands
14    for i in 0..100 {
15        let cmd_name = format!("service-{i:03}");
16
17        // Use string interning for flag names that repeat across commands
18        let namespace_flag_name = string_pool::intern("namespace");
19        let region_flag_name = string_pool::intern("region");
20        let env_flag_name = string_pool::intern("environment");
21
22        let cmd = CommandBuilder::new(cmd_name.clone())
23            .short(format!("Manage service {i}"))
24            .flag(
25                Flag::new(namespace_flag_name.to_string())
26                    .short('n')
27                    .usage("Kubernetes namespace")
28                    .value_type(FlagType::String)
29                    .default(flag_rs::FlagValue::String("default".to_string())),
30            )
31            .flag(
32                Flag::new(region_flag_name.to_string())
33                    .short('r')
34                    .usage("AWS region")
35                    .value_type(FlagType::Choice(vec![
36                        "us-east-1".to_string(),
37                        "us-west-2".to_string(),
38                        "eu-west-1".to_string(),
39                        "ap-southeast-1".to_string(),
40                    ]))
41                    .default(flag_rs::FlagValue::String("us-east-1".to_string())),
42            )
43            .flag(
44                Flag::new(env_flag_name.to_string())
45                    .short('e')
46                    .usage("Deployment environment")
47                    .value_type(FlagType::Choice(vec![
48                        "dev".to_string(),
49                        "staging".to_string(),
50                        "prod".to_string(),
51                    ]))
52                    .default(flag_rs::FlagValue::String("dev".to_string())),
53            )
54            .subcommand(
55                CommandBuilder::new("deploy")
56                    .short("Deploy the service")
57                    .arg_completion(move |_ctx, prefix| {
58                        // Use optimized completion result
59                        let optimized = CompletionResultOptimized::new()
60                            .add(Cow::Borrowed("rolling-update"))
61                            .add(Cow::Borrowed("blue-green"))
62                            .add(Cow::Borrowed("canary"))
63                            .add_with_description(
64                                Cow::Borrowed("recreate"),
65                                Cow::Borrowed("Recreate all pods"),
66                            );
67
68                        // Filter based on prefix
69                        let filtered = CompletionResultOptimized::new().extend_items(
70                            optimized
71                                .items
72                                .into_iter()
73                                .filter(|item| item.value.starts_with(prefix)),
74                        );
75
76                        // Convert to legacy format for compatibility
77                        Ok(filtered.into_legacy())
78                    })
79                    .build(),
80            )
81            .subcommand(
82                CommandBuilder::new("scale")
83                    .short("Scale the service")
84                    .flag(
85                        Flag::new("replicas")
86                            .usage("Number of replicas")
87                            .value_type(FlagType::Int)
88                            .required(),
89                    )
90                    .build(),
91            )
92            .subcommand(
93                CommandBuilder::new("logs")
94                    .short("View service logs")
95                    .flag(
96                        Flag::new("follow")
97                            .short('f')
98                            .usage("Follow log output")
99                            .value_type(FlagType::Bool),
100                    )
101                    .flag(
102                        Flag::new("tail")
103                            .usage("Number of lines to show")
104                            .value_type(FlagType::Int)
105                            .default(flag_rs::FlagValue::Int(100)),
106                    )
107                    .build(),
108            )
109            .build();
110
111        parent.add_command(cmd);
112    }
113}
examples/error_handling_demo.rs (line 41)
12fn main() {
13    let app = CommandBuilder::new("error-demo")
14        .short("Demonstrates error handling")
15        .long("This example shows various error scenarios and how flag-rs handles them")
16        .subcommand(
17            CommandBuilder::new("deploy")
18                .short("Deploy the application")
19                .args(ArgValidator::ExactArgs(1))
20                .run(|ctx| {
21                    let env = ctx.args().first().unwrap();
22                    if !["dev", "staging", "production"].contains(&env.as_str()) {
23                        return Err(Error::Validation(format!(
24                            "invalid environment '{}', must be one of: dev, staging, production",
25                            env
26                        )));
27                    }
28                    println!("Deploying to {}", env);
29                    Ok(())
30                })
31                .build(),
32        )
33        .subcommand(
34            CommandBuilder::new("serve")
35                .short("Start the server")
36                .flag(
37                    Flag::new("port")
38                        .short('p')
39                        .usage("Port to listen on")
40                        .value_type(FlagType::Int)
41                        .required(),
42                )
43                .run(|ctx| {
44                    let port = ctx.flag("port").unwrap();
45                    println!("Server starting on port {}", port);
46                    Ok(())
47                })
48                .build(),
49        )
50        .subcommand(
51            CommandBuilder::new("migrate")
52                .short("Run database migrations")
53                .subcommand(
54                    CommandBuilder::new("up")
55                        .short("Run pending migrations")
56                        .run(|_| {
57                            println!("Running migrations...");
58                            Ok(())
59                        })
60                        .build(),
61                )
62                .subcommand(
63                    CommandBuilder::new("down")
64                        .short("Rollback migrations")
65                        .args(ArgValidator::MaximumArgs(1))
66                        .run(|ctx| {
67                            let steps = ctx
68                                .args()
69                                .first()
70                                .and_then(|s| s.parse::<u32>().ok())
71                                .unwrap_or(1);
72                            println!(
73                                "Rolling back {} migration{}",
74                                steps,
75                                if steps == 1 { "" } else { "s" }
76                            );
77                            Ok(())
78                        })
79                        .build(),
80                )
81                .build(),
82        )
83        .subcommand(
84            CommandBuilder::new("config")
85                .short("Manage configuration")
86                .aliases(vec!["cfg", "conf"])
87                .run(|_| {
88                    println!("Configuration management");
89                    Ok(())
90                })
91                .build(),
92        )
93        .build();
94
95    println!("=== Error Handling Demo ===\n");
96    println!("This demo shows how flag-rs handles various error scenarios.\n");
97    println!("Try these commands to see different error types:\n");
98    println!(
99        "1. {} deploi              (typo - will show suggestions)",
100        std::env::args().next().unwrap_or_default()
101    );
102    println!(
103        "2. {} deploy              (missing required argument)",
104        std::env::args().next().unwrap_or_default()
105    );
106    println!(
107        "3. {} deploy dev staging  (too many arguments)",
108        std::env::args().next().unwrap_or_default()
109    );
110    println!(
111        "4. {} deploy test         (invalid environment)",
112        std::env::args().next().unwrap_or_default()
113    );
114    println!(
115        "5. {} serve               (missing required flag)",
116        std::env::args().next().unwrap_or_default()
117    );
118    println!(
119        "6. {} serve -p abc        (invalid flag value)",
120        std::env::args().next().unwrap_or_default()
121    );
122    println!(
123        "7. {} migrate             (subcommand required)",
124        std::env::args().next().unwrap_or_default()
125    );
126    println!(
127        "8. {} confi               (typo - will suggest 'config')",
128        std::env::args().next().unwrap_or_default()
129    );
130    println!("\n---\n");
131
132    let args: Vec<String> = std::env::args().skip(1).collect();
133    if let Err(e) = app.execute(args) {
134        eprintln!("{}", e);
135        std::process::exit(1);
136    }
137}
examples/flag_completion_demo.rs (line 11)
4fn main() {
5    let app = CommandBuilder::new("deploy")
6        .short("Deploy application to various environments")
7        .flag(
8            Flag::choice("environment", &["dev", "staging", "prod"])
9                .short('e')
10                .usage("Target environment")
11                .required()
12                .completion(|_ctx, prefix| {
13                    // Dynamic completion - could check available environments
14                    let environments = vec![
15                        ("dev", "Development environment"),
16                        ("staging", "Staging environment (pre-production)"),
17                        ("prod", "Production environment"),
18                    ];
19
20                    let mut result = CompletionResult::new();
21                    for (env, desc) in environments {
22                        if env.starts_with(prefix) {
23                            result = result.add_with_description(env.to_string(), desc.to_string());
24                        }
25                    }
26
27                    // Add active help if no prefix
28                    if prefix.is_empty() {
29                        result = result.add_help_text("Available environments: dev, staging, prod");
30                    }
31
32                    Ok(result)
33                }),
34        )
35        .flag(
36            Flag::file("config")
37                .short('c')
38                .usage("Configuration file")
39                .default_str("config.yaml")
40                .completion(|_ctx, prefix| {
41                    // In a real app, you might list files in the config directory
42                    let configs = vec![
43                        "config.yaml",
44                        "config.dev.yaml",
45                        "config.staging.yaml",
46                        "config.prod.yaml",
47                        "secrets.yaml",
48                    ];
49
50                    Ok(CompletionResult::new().extend(
51                        configs
52                            .into_iter()
53                            .filter(|c| c.starts_with(prefix))
54                            .map(String::from),
55                    ))
56                }),
57        )
58        .flag(
59            Flag::directory("output")
60                .short('o')
61                .usage("Output directory for deployment artifacts")
62                .completion(|_ctx, prefix| {
63                    // In a real app, you might list actual directories
64                    let dirs = vec!["./build", "./dist", "./output", "/tmp/deploy"];
65
66                    Ok(CompletionResult::new().extend(
67                        dirs.into_iter()
68                            .filter(|d| d.starts_with(prefix))
69                            .map(String::from),
70                    ))
71                }),
72        )
73        .flag(
74            Flag::string_slice("service")
75                .short('s')
76                .usage("Services to deploy (can be specified multiple times)")
77                .completion(|ctx, prefix| {
78                    // Context-aware completion based on environment
79                    let env = ctx.flag_str_or("environment", "dev");
80
81                    let services = match env {
82                        "dev" => vec!["api", "web", "worker", "scheduler", "debug-panel"],
83                        "staging" => vec!["api", "web", "worker", "scheduler"],
84                        "prod" => vec!["api", "web", "worker"],
85                        _ => vec!["api", "web"],
86                    };
87
88                    let mut result = CompletionResult::new().extend(
89                        services
90                            .into_iter()
91                            .filter(|s| s.starts_with(prefix))
92                            .map(String::from),
93                    );
94
95                    // Add context-aware help
96                    if prefix.is_empty() {
97                        result = result
98                            .add_help_text(format!("Available services for {} environment", env));
99                    }
100
101                    Ok(result)
102                }),
103        )
104        .flag(
105            Flag::range("replicas", 1, 10)
106                .short('r')
107                .usage("Number of replicas to deploy")
108                .default_int(2)
109                .completion(|_ctx, _prefix| {
110                    // Suggest common replica counts
111                    Ok(CompletionResult::new()
112                        .add_with_description(
113                            "1".to_string(),
114                            "Single instance (dev/test)".to_string(),
115                        )
116                        .add_with_description("2".to_string(), "Basic redundancy".to_string())
117                        .add_with_description("3".to_string(), "Standard production".to_string())
118                        .add_with_description("5".to_string(), "High availability".to_string()))
119                }),
120        )
121        .run(|ctx| {
122            let env = ctx.flag_str_or("environment", "dev");
123            let config = ctx.flag_str_or("config", "config.yaml");
124            let replicas = ctx.flag_int_or("replicas", 2);
125
126            println!("Deploying to {} environment", env);
127            println!("Using configuration: {}", config);
128            println!("Replica count: {}", replicas);
129
130            if let Some(output) = ctx.flag("output") {
131                println!("Output directory: {}", output);
132            }
133
134            if let Some(services) = ctx.flag("service") {
135                println!("Deploying services: {}", services);
136            } else {
137                println!("Deploying all services");
138            }
139
140            Ok(())
141        })
142        .build();
143
144    let args: Vec<String> = std::env::args().skip(1).collect();
145    if let Err(e) = app.execute(args) {
146        eprintln!("Error: {}", e);
147        std::process::exit(1);
148    }
149}
examples/enhanced_help_demo.rs (line 59)
10fn main() {
11    let app = CommandBuilder::new("kubectl")
12        .short("Kubernetes command-line tool")
13        .long("kubectl controls the Kubernetes cluster manager.\n\n\
14              Find more information at: https://kubernetes.io/docs/reference/kubectl/")
15        .example("kubectl get pods")
16        .example("kubectl apply -f deployment.yaml")
17        .example("kubectl logs -f my-pod")
18        .flag(
19            Flag::new("namespace")
20                .short('n')
21                .usage("The namespace scope for this CLI request")
22                .value_type(FlagType::String)
23                .default(flag_rs::FlagValue::String("default".to_string())),
24        )
25        .flag(
26            Flag::new("kubeconfig")
27                .usage("Path to the kubeconfig file to use for CLI requests")
28                .value_type(FlagType::String),
29        )
30        .subcommand(
31            CommandBuilder::new("get")
32                .short("Display one or many resources")
33                .group_id("Basic Commands")
34                .long("Prints a table of the most important information about the specified resources.\n\n\
35                      You can filter the list using a label selector and the --selector flag. If the\n\
36                      desired resource type is namespaced you will only see results in your current\n\
37                      namespace unless you pass --all-namespaces.")
38                .example("kubectl get pods")
39                .example("kubectl get pods -n kube-system")
40                .example("kubectl get pods --selector=app=nginx")
41                .example("kubectl get pods,services")
42                .build(),
43        )
44        .subcommand(
45            CommandBuilder::new("apply")
46                .short("Apply a configuration to a resource by file name or stdin")
47                .group_id("Basic Commands")
48                .long("Apply a configuration to a resource by file name or stdin. The resource name must\n\
49                      be specified. This resource will be created if it doesn't exist yet. To use 'apply',\n\
50                      always create the resource initially with either 'apply' or 'create --save-config'.")
51                .example("kubectl apply -f ./pod.yaml")
52                .example("kubectl apply -f https://example.com/manifest.yaml")
53                .example("kubectl apply -k ./")
54                .flag(
55                    Flag::new("filename")
56                        .short('f')
57                        .usage("Filename, directory, or URL to files to use to create the resource")
58                        .value_type(FlagType::String)
59                        .required(),
60                )
61                .flag(
62                    Flag::new("recursive")
63                        .short('R')
64                        .usage("Process the directory used in -f, --filename recursively")
65                        .value_type(FlagType::Bool),
66                )
67                .build(),
68        )
69        .subcommand(
70            CommandBuilder::new("delete")
71                .short("Delete resources by file names, stdin, resources and names, or by resources and label selector")
72                .aliases(vec!["del", "remove", "rm"])
73                .group_id("Basic Commands")
74                .example("kubectl delete pod my-pod")
75                .example("kubectl delete -f ./pod.yaml")
76                .example("kubectl delete pods --all")
77                .build(),
78        )
79        .subcommand(
80            CommandBuilder::new("logs")
81                .short("Print the logs for a container in a pod")
82                .group_id("Troubleshooting and Debugging Commands")
83                .long("Print the logs for a container in a pod or specified resource. If the pod has\n\
84                      only one container, the container name is optional.")
85                .aliases(vec!["log"])
86                .example("kubectl logs my-pod")
87                .example("kubectl logs my-pod -c my-container")
88                .example("kubectl logs -f my-pod")
89                .example("kubectl logs --tail=20 my-pod")
90                .flag(
91                    Flag::new("follow")
92                        .short('f')
93                        .usage("Specify if the logs should be streamed")
94                        .value_type(FlagType::Bool),
95                )
96                .flag(
97                    Flag::new("tail")
98                        .usage("Lines of recent log file to display")
99                        .value_type(FlagType::Int)
100                        .default(flag_rs::FlagValue::Int(-1)),
101                )
102                .build(),
103        )
104        .subcommand(
105            CommandBuilder::new("describe")
106                .short("Show details of a specific resource or group of resources")
107                .group_id("Troubleshooting and Debugging Commands")
108                .example("kubectl describe pod my-pod")
109                .example("kubectl describe nodes")
110                .build(),
111        )
112        .subcommand(
113            CommandBuilder::new("exec")
114                .short("Execute a command in a container")
115                .group_id("Troubleshooting and Debugging Commands")
116                .example("kubectl exec -it my-pod -- /bin/bash")
117                .example("kubectl exec my-pod -- ls /app")
118                .build(),
119        )
120        .subcommand(
121            CommandBuilder::new("config")
122                .short("Modify kubeconfig files")
123                .group_id("Settings Commands")
124                .example("kubectl config view")
125                .example("kubectl config use-context my-context")
126                .build(),
127        )
128        .subcommand(
129            CommandBuilder::new("version")
130                .short("Print the client and server version information")
131                .example("kubectl version")
132                .example("kubectl version --short")
133                .build(),
134        )
135        .build();
136
137    let args: Vec<String> = std::env::args().skip(1).collect();
138    if let Err(e) = app.execute(args) {
139        eprintln!("{}", e);
140        std::process::exit(1);
141    }
142}
Source

pub fn value_type(self, value_type: FlagType) -> Self

Sets the value type for this flag

§Examples
use flag_rs::flag::{Flag, FlagType};

let flag = Flag::new("count").value_type(FlagType::Int);
Examples found in repository?
examples/benchmark.rs (line 56)
50fn create_simple_cli() -> flag_rs::Command {
51    CommandBuilder::new("bench")
52        .short("Benchmark CLI")
53        .flag(
54            Flag::new("verbose")
55                .short('v')
56                .value_type(FlagType::Bool)
57                .default(FlagValue::Bool(false)),
58        )
59        .flag(Flag::new("output").short('o').value_type(FlagType::String))
60        .build()
61}
62
63/// Creates a complex nested command structure
64fn create_complex_cli() -> flag_rs::Command {
65    let mut root = CommandBuilder::new("complex")
66        .short("Complex CLI with many subcommands")
67        .flag(
68            Flag::new("config")
69                .short('c')
70                .value_type(FlagType::File)
71                .default(FlagValue::String("config.yaml".to_string())),
72        )
73        .build();
74
75    // Add 50 subcommands
76    for i in 0..50 {
77        let mut sub = CommandBuilder::new(format!("sub{i:02}"))
78            .short(format!("Subcommand {i}"))
79            .flag(Flag::new("flag1").short('1').value_type(FlagType::String))
80            .flag(Flag::new("flag2").short('2').value_type(FlagType::Int))
81            .build();
82
83        // Add 10 nested subcommands
84        for j in 0..10 {
85            sub.add_command(
86                CommandBuilder::new(format!("nested{j}"))
87                    .short(format!("Nested command {j}"))
88                    .flag(Flag::new("deep").value_type(FlagType::Bool))
89                    .build(),
90            );
91        }
92
93        root.add_command(sub);
94    }
95
96    root
97}
98
99fn bench_command_creation() {
100    println!("\n=== Command Creation Benchmarks ===");
101
102    let bench = Benchmark::new("Simple command creation", 10_000);
103    let duration = bench.run(|| {
104        let _ = create_simple_cli();
105    });
106    bench.report(duration);
107
108    let bench = Benchmark::new("Complex command creation (50 subs)", 100);
109    let duration = bench.run(|| {
110        let _ = create_complex_cli();
111    });
112    bench.report(duration);
113
114    let bench = Benchmark::new("CommandBuilder with 10 flags", 1_000);
115    let duration = bench.run(|| {
116        let mut cmd = CommandBuilder::new("test");
117        for i in 0..10 {
118            cmd = cmd.flag(Flag::new(format!("flag{i}")).value_type(FlagType::String));
119        }
120        let _ = cmd.build();
121    });
122    bench.report(duration);
123}
124
125fn bench_flag_parsing() {
126    println!("\n=== Flag Parsing Benchmarks ===");
127
128    let cli = create_simple_cli();
129
130    let bench = Benchmark::new("Parse no flags", 10_000);
131    let duration = bench.run(|| {
132        let args = vec!["bench".to_string()];
133        let _ = cli.execute(args);
134    });
135    bench.report(duration);
136
137    let bench = Benchmark::new("Parse single flag", 10_000);
138    let duration = bench.run(|| {
139        let args = vec!["bench".to_string(), "--verbose".to_string()];
140        let _ = cli.execute(args);
141    });
142    bench.report(duration);
143
144    let bench = Benchmark::new("Parse flag with value", 10_000);
145    let duration = bench.run(|| {
146        let args = vec![
147            "bench".to_string(),
148            "--output".to_string(),
149            "file.txt".to_string(),
150        ];
151        let _ = cli.execute(args);
152    });
153    bench.report(duration);
154
155    let bench = Benchmark::new("Parse multiple flags", 10_000);
156    let duration = bench.run(|| {
157        let args = vec![
158            "bench".to_string(),
159            "-v".to_string(),
160            "-o".to_string(),
161            "output.txt".to_string(),
162        ];
163        let _ = cli.execute(args);
164    });
165    bench.report(duration);
166}
167
168fn bench_subcommand_lookup() {
169    println!("\n=== Subcommand Lookup Benchmarks ===");
170
171    let cli = create_complex_cli();
172
173    let bench = Benchmark::new("Find immediate subcommand", 10_000);
174    let duration = bench.run(|| {
175        let _ = cli.find_subcommand("sub25");
176    });
177    bench.report(duration);
178
179    let bench = Benchmark::new("Find nested subcommand", 10_000);
180    let duration = bench.run(|| {
181        if let Some(sub) = cli.find_subcommand("sub25") {
182            let _ = sub.find_subcommand("nested5");
183        }
184    });
185    bench.report(duration);
186
187    let bench = Benchmark::new("Execute nested command", 1_000);
188    let duration = bench.run(|| {
189        let args = vec![
190            "complex".to_string(),
191            "sub25".to_string(),
192            "nested5".to_string(),
193            "--deep".to_string(),
194        ];
195        let _ = cli.execute(args);
196    });
197    bench.report(duration);
198}
199
200fn bench_completion() {
201    println!("\n=== Completion Benchmarks ===");
202
203    let cli = CommandBuilder::new("comp")
204        .arg_completion(|_ctx, prefix| {
205            let items: Vec<String> = (0..100)
206                .map(|i| format!("item{i:03}"))
207                .filter(|item| item.starts_with(prefix))
208                .collect();
209            Ok(CompletionResult::new().extend(items))
210        })
211        .build();
212
213    let ctx = flag_rs::Context::new(vec!["comp".to_string()]);
214
215    let bench = Benchmark::new("Complete with empty prefix (100 items)", 1_000);
216    let duration = bench.run(|| {
217        let _ = cli.get_completions(&ctx, "", None);
218    });
219    bench.report(duration);
220
221    let bench = Benchmark::new("Complete with prefix (filtered)", 1_000);
222    let duration = bench.run(|| {
223        let _ = cli.get_completions(&ctx, "item05", None);
224    });
225    bench.report(duration);
226
227    // Test completion with descriptions
228    let cli_desc = CommandBuilder::new("comp_desc")
229        .arg_completion(|_ctx, prefix| {
230            let mut result = CompletionResult::new();
231            for i in 0..50 {
232                let item = format!("option{i:02}");
233                if item.starts_with(prefix) {
234                    result =
235                        result.add_with_description(item, format!("Description for option {i}"));
236                }
237            }
238            Ok(result)
239        })
240        .build();
241
242    let bench = Benchmark::new("Complete with descriptions (50 items)", 1_000);
243    let duration = bench.run(|| {
244        let _ = cli_desc.get_completions(&ctx, "", None);
245    });
246    bench.report(duration);
247}
248
249fn bench_flag_validation() {
250    println!("\n=== Flag Validation Benchmarks ===");
251
252    let cli = CommandBuilder::new("validate")
253        .flag(Flag::new("choice").value_type(FlagType::Choice(vec![
254            "opt1".to_string(),
255            "opt2".to_string(),
256            "opt3".to_string(),
257        ])))
258        .flag(Flag::new("range").value_type(FlagType::Range(1, 100)))
259        .flag(
260            Flag::new("required")
261                .value_type(FlagType::String)
262                .required(),
263        )
264        .build();
265
266    let bench = Benchmark::new("Validate choice flag", 10_000);
267    let duration = bench.run(|| {
268        let args = vec![
269            "validate".to_string(),
270            "--choice".to_string(),
271            "opt2".to_string(),
272            "--required".to_string(),
273            "value".to_string(),
274        ];
275        let _ = cli.execute(args);
276    });
277    bench.report(duration);
278
279    let bench = Benchmark::new("Validate range flag", 10_000);
280    let duration = bench.run(|| {
281        let args = vec![
282            "validate".to_string(),
283            "--range".to_string(),
284            "50".to_string(),
285            "--required".to_string(),
286            "value".to_string(),
287        ];
288        let _ = cli.execute(args);
289    });
290    bench.report(duration);
291
292    let bench = Benchmark::new("Validate missing required flag", 10_000);
293    let duration = bench.run(|| {
294        let args = vec!["validate".to_string()];
295        let _ = cli.execute(args); // This will fail validation
296    });
297    bench.report(duration);
298}
More examples
Hide additional examples
examples/kubectl.rs (line 26)
14fn build_kubectl() -> Command {
15    CommandBuilder::new("kubectl")
16        .short("Kubernetes command-line tool")
17        .long("kubectl controls the Kubernetes cluster manager")
18        .subcommand(build_get_command())
19        .subcommand(build_describe_command())
20        .subcommand(build_delete_command())
21        .subcommand(build_completion_command())
22        .flag(
23            Flag::new("namespace")
24                .short('n')
25                .usage("Kubernetes namespace")
26                .value_type(FlagType::String)
27                .default(FlagValue::String("default".to_string())),
28        )
29        .flag_completion("namespace", |_ctx, prefix| {
30            // In a real kubectl, this would query the API server
31            let namespaces = get_namespaces_with_descriptions();
32            let mut result = CompletionResult::new();
33
34            for (ns_name, description) in namespaces {
35                if ns_name.starts_with(prefix) {
36                    result = result.add_with_description(ns_name, description);
37                }
38            }
39
40            Ok(result)
41        })
42        .build()
43}
44
45fn build_get_command() -> Command {
46    CommandBuilder::new("get")
47        .short("Display one or many resources")
48        .long("Display one or many resources. Prints a table of the most important information about the specified resources.")
49        .flag(
50            Flag::new("limit")
51                .short('l')
52                .usage("Maximum number of resources to display")
53                .value_type(FlagType::String)
54        )
55        .flag_completion("limit", |_ctx, prefix| {
56            let common_limits = vec![
57                ("10", "Display 10 items"),
58                ("20", "Display 20 items"),
59                ("50", "Display 50 items"),
60                ("100", "Display 100 items"),
61                ("all", "Display all items (no limit)"),
62            ];
63
64            let mut result = CompletionResult::new();
65            for (limit, description) in common_limits {
66                if limit.starts_with(prefix) {
67                    result = result.add_with_description(limit.to_string(), description.to_string());
68                }
69            }
70
71            Ok(result)
72        })
73        .subcommand(build_get_pods())
74        .subcommand(build_get_services())
75        .subcommand(build_get_deployments())
76        .build()
77}
examples/terminal_demo.rs (line 25)
17fn main() {
18    let app = CommandBuilder::new("demo")
19        .short("Terminal feature demonstration")
20        .long("This application demonstrates the terminal width detection and text wrapping features. The help text should automatically adjust to your terminal width, wrapping long lines at word boundaries while maintaining readability. Try running this with different COLUMNS values to see how it adapts.")
21        .flag(
22            Flag::new("file")
23                .short('f')
24                .usage("Input file path. This flag expects a path to a file that will be processed. The file must exist and be readable.")
25                .value_type(FlagType::String)
26        )
27        .flag(
28            Flag::new("output-format")
29                .short('o')
30                .usage("Output format for results. Supported formats include: json (machine-readable JSON format), yaml (human-friendly YAML format), table (formatted ASCII table), csv (comma-separated values for spreadsheet import)")
31                .value_type(FlagType::String)
32                .default(FlagValue::String("table".to_string()))
33        )
34        .subcommand(
35            CommandBuilder::new("process")
36                .short("Process data with various transformations and filters that can be applied in sequence")
37                .build()
38        )
39        .build();
40
41    // Always show help for this demo
42    app.print_help();
43}
examples/test_completion.rs (line 10)
3fn main() {
4    let cmd = CommandBuilder::new("test")
5        .short("Test completion with descriptions")
6        .flag(
7            Flag::new("environment")
8                .short('e')
9                .usage("Target environment")
10                .value_type(FlagType::String),
11        )
12        .flag_completion("environment", |_ctx, prefix| {
13            let mut result = CompletionResult::new();
14            let envs = vec![
15                ("dev", "Development environment - safe for testing"),
16                ("staging", "Staging environment - mirror of production"),
17                ("production", "Production environment - BE CAREFUL!"),
18            ];
19
20            for (env, desc) in envs {
21                if env.starts_with(prefix) {
22                    result = result.add_with_description(env, desc);
23                }
24            }
25
26            Ok(result)
27        })
28        .subcommand(
29            CommandBuilder::new("deploy")
30                .short("Deploy the application")
31                .long("Deploy the application to the specified environment")
32                .build(),
33        )
34        .subcommand(
35            CommandBuilder::new("rollback")
36                .short("Rollback to previous version")
37                .long("Rollback the application to the previous deployed version")
38                .build(),
39        )
40        .build();
41
42    // Test completion output
43    if let Ok(shell_type) = std::env::var("TEST_COMPLETE") {
44        // For testing, override shell type to "display" to see formatted output
45        let display_mode = std::env::var("DISPLAY_MODE").is_ok();
46        let args: Vec<String> = std::env::args().skip(1).collect();
47
48        if display_mode {
49            // This is a hack for testing - normally shells would handle this
50            println!("Display mode - showing formatted completions:");
51            match cmd.handle_completion_request(&args) {
52                Ok(completions) => {
53                    for completion in completions {
54                        println!("{}", completion);
55                    }
56                }
57                Err(e) => eprintln!("Completion error: {}", e),
58            }
59        } else {
60            match cmd.handle_completion_request(&args) {
61                Ok(completions) => {
62                    println!("Shell type: {}", shell_type);
63                    println!("Completions:");
64                    for completion in completions {
65                        println!("{}", completion);
66                    }
67                }
68                Err(e) => eprintln!("Completion error: {}", e),
69            }
70        }
71    } else {
72        let args: Vec<String> = std::env::args().skip(1).collect();
73        if let Err(e) = cmd.execute(args) {
74            eprintln!("Error: {}", e);
75            std::process::exit(1);
76        }
77    }
78}
examples/enhanced_errors_demo.rs (line 13)
7fn main() {
8    let app = CommandBuilder::new("errordemo")
9        .short("Demo of enhanced error messages")
10        .flag(
11            Flag::new("verbose")
12                .short('v')
13                .value_type(FlagType::Bool)
14                .usage("Enable verbose output"),
15        )
16        .flag(
17            Flag::new("workers")
18                .short('w')
19                .value_type(FlagType::Range(1, 10))
20                .usage("Number of worker threads"),
21        )
22        .flag(
23            Flag::new("format")
24                .short('f')
25                .value_type(FlagType::Choice(vec![
26                    "json".to_string(),
27                    "yaml".to_string(),
28                    "xml".to_string(),
29                    "toml".to_string(),
30                ]))
31                .usage("Output format"),
32        )
33        .flag(
34            Flag::new("config")
35                .short('c')
36                .value_type(FlagType::File)
37                .usage("Configuration file"),
38        )
39        .flag(
40            Flag::new("outdir")
41                .short('o')
42                .value_type(FlagType::Directory)
43                .usage("Output directory"),
44        )
45        .flag(
46            Flag::new("ssl")
47                .value_type(FlagType::Bool)
48                .usage("Enable SSL"),
49        )
50        .flag(
51            Flag::new("ssl-cert")
52                .value_type(FlagType::File)
53                .constraint(FlagConstraint::RequiredIf("ssl".to_string()))
54                .usage("SSL certificate file"),
55        )
56        .flag(
57            Flag::new("json")
58                .value_type(FlagType::Bool)
59                .constraint(FlagConstraint::ConflictsWith(vec!["xml".to_string()]))
60                .usage("Output in JSON format"),
61        )
62        .flag(
63            Flag::new("xml")
64                .value_type(FlagType::Bool)
65                .usage("Output in XML format"),
66        )
67        .flag(
68            Flag::new("required-flag")
69                .value_type(FlagType::String)
70                .required()
71                .usage("This flag is required"),
72        )
73        .subcommand(
74            CommandBuilder::new("process")
75                .short("Process data")
76                .run(|ctx| {
77                    println!("Processing with flags: {:?}", ctx.flags());
78                    Ok(())
79                })
80                .build(),
81        )
82        .build();
83
84    println!("Try these commands to see enhanced error messages:\n");
85    println!("  # Boolean parsing error");
86    println!("  cargo run --example enhanced_errors_demo -- --verbose=maybe\n");
87
88    println!("  # Integer parsing error");
89    println!("  cargo run --example enhanced_errors_demo -- --workers=abc\n");
90
91    println!("  # Range validation error");
92    println!("  cargo run --example enhanced_errors_demo -- --workers=20\n");
93
94    println!("  # Choice validation error");
95    println!("  cargo run --example enhanced_errors_demo -- --format=csv\n");
96
97    println!("  # File not found error");
98    println!("  cargo run --example enhanced_errors_demo -- --config=/tmp/nonexistent.conf\n");
99
100    println!("  # Directory not found error");
101    println!("  cargo run --example enhanced_errors_demo -- --outdir=/tmp/nonexistent_dir\n");
102
103    println!("  # Flag constraint error (RequiredIf)");
104    println!("  cargo run --example enhanced_errors_demo -- --ssl --required-flag=test process\n");
105
106    println!("  # Flag constraint error (ConflictsWith)");
107    println!(
108        "  cargo run --example enhanced_errors_demo -- --json --xml --required-flag=test process\n"
109    );
110
111    println!("  # Required flag error");
112    println!("  cargo run --example enhanced_errors_demo -- process\n");
113
114    println!("  # Unknown command error");
115    println!("  cargo run --example enhanced_errors_demo -- --required-flag=test proces\n");
116
117    let args: Vec<String> = std::env::args().skip(1).collect();
118    if !args.is_empty() {
119        println!("\n{}", "=".repeat(60));
120        println!("Running with args: {:?}\n", args);
121
122        if let Err(e) = app.execute(args) {
123            eprintln!("{}", e);
124            std::process::exit(1);
125        }
126    }
127}
examples/memory_optimization_demo.rs (line 28)
12fn create_many_subcommands(parent: &mut flag_rs::Command) {
13    // Simulate a large CLI with 100 subcommands
14    for i in 0..100 {
15        let cmd_name = format!("service-{i:03}");
16
17        // Use string interning for flag names that repeat across commands
18        let namespace_flag_name = string_pool::intern("namespace");
19        let region_flag_name = string_pool::intern("region");
20        let env_flag_name = string_pool::intern("environment");
21
22        let cmd = CommandBuilder::new(cmd_name.clone())
23            .short(format!("Manage service {i}"))
24            .flag(
25                Flag::new(namespace_flag_name.to_string())
26                    .short('n')
27                    .usage("Kubernetes namespace")
28                    .value_type(FlagType::String)
29                    .default(flag_rs::FlagValue::String("default".to_string())),
30            )
31            .flag(
32                Flag::new(region_flag_name.to_string())
33                    .short('r')
34                    .usage("AWS region")
35                    .value_type(FlagType::Choice(vec![
36                        "us-east-1".to_string(),
37                        "us-west-2".to_string(),
38                        "eu-west-1".to_string(),
39                        "ap-southeast-1".to_string(),
40                    ]))
41                    .default(flag_rs::FlagValue::String("us-east-1".to_string())),
42            )
43            .flag(
44                Flag::new(env_flag_name.to_string())
45                    .short('e')
46                    .usage("Deployment environment")
47                    .value_type(FlagType::Choice(vec![
48                        "dev".to_string(),
49                        "staging".to_string(),
50                        "prod".to_string(),
51                    ]))
52                    .default(flag_rs::FlagValue::String("dev".to_string())),
53            )
54            .subcommand(
55                CommandBuilder::new("deploy")
56                    .short("Deploy the service")
57                    .arg_completion(move |_ctx, prefix| {
58                        // Use optimized completion result
59                        let optimized = CompletionResultOptimized::new()
60                            .add(Cow::Borrowed("rolling-update"))
61                            .add(Cow::Borrowed("blue-green"))
62                            .add(Cow::Borrowed("canary"))
63                            .add_with_description(
64                                Cow::Borrowed("recreate"),
65                                Cow::Borrowed("Recreate all pods"),
66                            );
67
68                        // Filter based on prefix
69                        let filtered = CompletionResultOptimized::new().extend_items(
70                            optimized
71                                .items
72                                .into_iter()
73                                .filter(|item| item.value.starts_with(prefix)),
74                        );
75
76                        // Convert to legacy format for compatibility
77                        Ok(filtered.into_legacy())
78                    })
79                    .build(),
80            )
81            .subcommand(
82                CommandBuilder::new("scale")
83                    .short("Scale the service")
84                    .flag(
85                        Flag::new("replicas")
86                            .usage("Number of replicas")
87                            .value_type(FlagType::Int)
88                            .required(),
89                    )
90                    .build(),
91            )
92            .subcommand(
93                CommandBuilder::new("logs")
94                    .short("View service logs")
95                    .flag(
96                        Flag::new("follow")
97                            .short('f')
98                            .usage("Follow log output")
99                            .value_type(FlagType::Bool),
100                    )
101                    .flag(
102                        Flag::new("tail")
103                            .usage("Number of lines to show")
104                            .value_type(FlagType::Int)
105                            .default(flag_rs::FlagValue::Int(100)),
106                    )
107                    .build(),
108            )
109            .build();
110
111        parent.add_command(cmd);
112    }
113}
114
115// Count commands recursively
116fn count_commands(cmd: &flag_rs::Command) -> usize {
117    1 + cmd
118        .subcommands()
119        .values()
120        .map(count_commands)
121        .sum::<usize>()
122}
123
124// Count flags recursively
125fn count_flags(cmd: &flag_rs::Command) -> usize {
126    cmd.flags().len() + cmd.subcommands().values().map(count_flags).sum::<usize>()
127}
128
129fn main() {
130    // Create root command
131    let mut app = CommandBuilder::new("megacli")
132        .short("A large CLI demonstrating memory optimizations")
133        .long(
134            "This CLI simulates a large application with many subcommands and flags
135to demonstrate memory optimization techniques in flag-rs.
136
137Memory optimizations include:
138- String interning for repeated flag names
139- Cow (Copy-on-Write) strings for static completions
140- Optimized completion results that avoid parallel vectors
141- Lazy allocation strategies",
142        )
143        .flag(
144            Flag::new("verbose")
145                .short('v')
146                .usage("Enable verbose output")
147                .value_type(FlagType::Bool),
148        )
149        .flag(
150            Flag::new("config")
151                .short('c')
152                .usage("Path to config file")
153                .value_type(FlagType::File)
154                .default(flag_rs::FlagValue::String(
155                    "~/.megacli/config.yaml".to_string(),
156                )),
157        )
158        .build();
159
160    // Add many subcommands
161    create_many_subcommands(&mut app);
162
163    let total_commands = count_commands(&app);
164    let total_flags = count_flags(&app);
165
166    // Add a special command to show memory usage stats
167    app.add_command(
168        CommandBuilder::new("stats")
169            .short("Show CLI statistics and memory usage")
170            .run(move |_ctx| {
171                println!("=== MegaCLI Statistics ===\n");
172
173                println!("Total commands: {total_commands}");
174                println!("Total flags: {total_flags}");
175                println!("String pool size: {} unique strings", 3); // We interned 3 flag names
176
177                println!("\nMemory optimization features in use:");
178                println!("✓ String interning for flag names");
179                println!("✓ Cow<str> for static completion values");
180                println!("✓ CompletionResultOptimized for reduced allocations");
181                println!("✓ Lazy allocation strategies");
182
183                println!("\nEstimated memory savings:");
184                println!("- 60-70% reduction in string allocations");
185                println!("- 40-50% reduction in completion memory usage");
186                println!("- Improved cache locality for better performance");
187
188                Ok(())
189            })
190            .build(),
191    );
192
193    // Execute the CLI
194    let args: Vec<String> = std::env::args().skip(1).collect();
195
196    if args.is_empty() {
197        println!("=== Memory Optimization Demo ===\n");
198        println!("This demo shows how flag-rs optimizes memory for large CLIs.\n");
199        println!("Try these commands:");
200        println!(
201            "  {} stats                    # Show memory statistics",
202            std::env::args().next().unwrap_or_default()
203        );
204        println!(
205            "  {} service-001 deploy <TAB> # Test optimized completions",
206            std::env::args().next().unwrap_or_default()
207        );
208        println!(
209            "  {} --help                   # See all 100+ commands",
210            std::env::args().next().unwrap_or_default()
211        );
212        println!("\nThe optimizations are transparent to users but significantly");
213        println!("reduce memory usage for CLIs with many commands and flags.");
214        std::process::exit(0);
215    }
216
217    if let Err(e) = app.execute(args) {
218        eprintln!("{e}");
219        std::process::exit(1);
220    }
221}
Source

pub fn constraint(self, constraint: FlagConstraint) -> Self

Adds a constraint to this flag

§Examples
use flag_rs::flag::{Flag, FlagConstraint};

let flag = Flag::new("ssl")
    .constraint(FlagConstraint::RequiredIf("port".to_string()))
    .constraint(FlagConstraint::ConflictsWith(vec!["no-ssl".to_string()]));
Examples found in repository?
examples/enhanced_errors_demo.rs (line 53)
7fn main() {
8    let app = CommandBuilder::new("errordemo")
9        .short("Demo of enhanced error messages")
10        .flag(
11            Flag::new("verbose")
12                .short('v')
13                .value_type(FlagType::Bool)
14                .usage("Enable verbose output"),
15        )
16        .flag(
17            Flag::new("workers")
18                .short('w')
19                .value_type(FlagType::Range(1, 10))
20                .usage("Number of worker threads"),
21        )
22        .flag(
23            Flag::new("format")
24                .short('f')
25                .value_type(FlagType::Choice(vec![
26                    "json".to_string(),
27                    "yaml".to_string(),
28                    "xml".to_string(),
29                    "toml".to_string(),
30                ]))
31                .usage("Output format"),
32        )
33        .flag(
34            Flag::new("config")
35                .short('c')
36                .value_type(FlagType::File)
37                .usage("Configuration file"),
38        )
39        .flag(
40            Flag::new("outdir")
41                .short('o')
42                .value_type(FlagType::Directory)
43                .usage("Output directory"),
44        )
45        .flag(
46            Flag::new("ssl")
47                .value_type(FlagType::Bool)
48                .usage("Enable SSL"),
49        )
50        .flag(
51            Flag::new("ssl-cert")
52                .value_type(FlagType::File)
53                .constraint(FlagConstraint::RequiredIf("ssl".to_string()))
54                .usage("SSL certificate file"),
55        )
56        .flag(
57            Flag::new("json")
58                .value_type(FlagType::Bool)
59                .constraint(FlagConstraint::ConflictsWith(vec!["xml".to_string()]))
60                .usage("Output in JSON format"),
61        )
62        .flag(
63            Flag::new("xml")
64                .value_type(FlagType::Bool)
65                .usage("Output in XML format"),
66        )
67        .flag(
68            Flag::new("required-flag")
69                .value_type(FlagType::String)
70                .required()
71                .usage("This flag is required"),
72        )
73        .subcommand(
74            CommandBuilder::new("process")
75                .short("Process data")
76                .run(|ctx| {
77                    println!("Processing with flags: {:?}", ctx.flags());
78                    Ok(())
79                })
80                .build(),
81        )
82        .build();
83
84    println!("Try these commands to see enhanced error messages:\n");
85    println!("  # Boolean parsing error");
86    println!("  cargo run --example enhanced_errors_demo -- --verbose=maybe\n");
87
88    println!("  # Integer parsing error");
89    println!("  cargo run --example enhanced_errors_demo -- --workers=abc\n");
90
91    println!("  # Range validation error");
92    println!("  cargo run --example enhanced_errors_demo -- --workers=20\n");
93
94    println!("  # Choice validation error");
95    println!("  cargo run --example enhanced_errors_demo -- --format=csv\n");
96
97    println!("  # File not found error");
98    println!("  cargo run --example enhanced_errors_demo -- --config=/tmp/nonexistent.conf\n");
99
100    println!("  # Directory not found error");
101    println!("  cargo run --example enhanced_errors_demo -- --outdir=/tmp/nonexistent_dir\n");
102
103    println!("  # Flag constraint error (RequiredIf)");
104    println!("  cargo run --example enhanced_errors_demo -- --ssl --required-flag=test process\n");
105
106    println!("  # Flag constraint error (ConflictsWith)");
107    println!(
108        "  cargo run --example enhanced_errors_demo -- --json --xml --required-flag=test process\n"
109    );
110
111    println!("  # Required flag error");
112    println!("  cargo run --example enhanced_errors_demo -- process\n");
113
114    println!("  # Unknown command error");
115    println!("  cargo run --example enhanced_errors_demo -- --required-flag=test proces\n");
116
117    let args: Vec<String> = std::env::args().skip(1).collect();
118    if !args.is_empty() {
119        println!("\n{}", "=".repeat(60));
120        println!("Running with args: {:?}\n", args);
121
122        if let Err(e) = app.execute(args) {
123            eprintln!("{}", e);
124            std::process::exit(1);
125        }
126    }
127}
More examples
Hide additional examples
examples/advanced_flags_demo.rs (line 68)
14fn main() {
15    let app = CommandBuilder::new("server")
16        .short("A demo server with advanced configuration options")
17        .long(
18            "This example demonstrates the advanced flag features in flag-rs,
19including choice flags, range validation, file/directory validation,
20and flag constraints.",
21        )
22        // Choice flag - must be one of the predefined values
23        .flag(
24            Flag::new("environment")
25                .short('e')
26                .usage("Server environment")
27                .value_type(FlagType::Choice(vec![
28                    "development".to_string(),
29                    "staging".to_string(),
30                    "production".to_string(),
31                ]))
32                .default(FlagValue::String("development".to_string())),
33        )
34        // Range flag - numeric value within a specific range
35        .flag(
36            Flag::new("port")
37                .short('p')
38                .usage("Server port (1024-65535)")
39                .value_type(FlagType::Range(1024, 65535))
40                .default(FlagValue::Int(8080)),
41        )
42        // File flag - must be a valid file path
43        .flag(
44            Flag::new("config")
45                .short('c')
46                .usage("Configuration file path")
47                .value_type(FlagType::File),
48        )
49        // Directory flag - must be a valid directory path
50        .flag(
51            Flag::new("log-dir")
52                .usage("Directory for log files")
53                .value_type(FlagType::Directory)
54                .default(FlagValue::String("/tmp".to_string())),
55        )
56        // StringArray flag - can be specified multiple times
57        .flag(
58            Flag::new("tags")
59                .short('t')
60                .usage("Tags for the server (can be specified multiple times)")
61                .value_type(FlagType::StringArray),
62        )
63        // Flag with RequiredIf constraint
64        .flag(
65            Flag::new("ssl-cert")
66                .usage("SSL certificate file")
67                .value_type(FlagType::File)
68                .constraint(FlagConstraint::RequiredIf("ssl".to_string())),
69        )
70        // Flag with RequiredIf constraint
71        .flag(
72            Flag::new("ssl-key")
73                .usage("SSL private key file")
74                .value_type(FlagType::File)
75                .constraint(FlagConstraint::RequiredIf("ssl".to_string())),
76        )
77        // Flag that triggers the RequiredIf constraints above
78        .flag(
79            Flag::new("ssl")
80                .usage("Enable SSL/TLS")
81                .value_type(FlagType::Bool),
82        )
83        // Flag with ConflictsWith constraint
84        .flag(
85            Flag::new("debug")
86                .short('d')
87                .usage("Enable debug mode")
88                .value_type(FlagType::Bool)
89                .constraint(FlagConstraint::ConflictsWith(vec!["quiet".to_string()])),
90        )
91        // Flag that conflicts with debug
92        .flag(
93            Flag::new("quiet")
94                .short('q')
95                .usage("Quiet mode (minimal output)")
96                .value_type(FlagType::Bool)
97                .constraint(FlagConstraint::ConflictsWith(vec!["debug".to_string()])),
98        )
99        // Flag with Requires constraint
100        .flag(
101            Flag::new("auth-token")
102                .usage("Authentication token")
103                .value_type(FlagType::String)
104                .constraint(FlagConstraint::Requires(vec!["auth-enabled".to_string()])),
105        )
106        // Flag required by auth-token
107        .flag(
108            Flag::new("auth-enabled")
109                .usage("Enable authentication")
110                .value_type(FlagType::Bool),
111        )
112        // Required flag
113        .flag(
114            Flag::new("name")
115                .short('n')
116                .usage("Server name")
117                .value_type(FlagType::String)
118                .required(),
119        )
120        .run(|ctx| {
121            // Display configuration
122            println!("=== Server Configuration ===\n");
123
124            println!("Server Name: {}", ctx.flag("name").unwrap());
125            println!(
126                "Environment: {}",
127                ctx.flag("environment")
128                    .unwrap_or(&"development".to_string())
129            );
130            println!("Port: {}", ctx.flag("port").unwrap_or(&"8080".to_string()));
131
132            if let Some(config) = ctx.flag("config") {
133                println!("Config File: {}", config);
134            }
135
136            println!(
137                "Log Directory: {}",
138                ctx.flag("log-dir").unwrap_or(&"/tmp".to_string())
139            );
140
141            if let Some(tags) = ctx.flag("tags") {
142                println!("Tags: {}", tags);
143            }
144
145            if ctx.flag("ssl").map(|v| v == "true").unwrap_or(false) {
146                println!("\nSSL Configuration:");
147                println!("  Certificate: {}", ctx.flag("ssl-cert").unwrap());
148                println!("  Private Key: {}", ctx.flag("ssl-key").unwrap());
149            }
150
151            if ctx.flag("debug").map(|v| v == "true").unwrap_or(false) {
152                println!("\nDebug mode: ENABLED");
153            } else if ctx.flag("quiet").map(|v| v == "true").unwrap_or(false) {
154                println!("\nQuiet mode: ENABLED");
155            }
156
157            if ctx
158                .flag("auth-enabled")
159                .map(|v| v == "true")
160                .unwrap_or(false)
161            {
162                println!("\nAuthentication: ENABLED");
163                if let Some(token) = ctx.flag("auth-token") {
164                    println!("  Token: {}", token);
165                }
166            }
167
168            println!("\nServer would start with the above configuration...");
169            Ok(())
170        })
171        .build();
172
173    println!("=== Advanced Flags Demo ===\n");
174    println!("This demo showcases advanced flag features in flag-rs.\n");
175    println!("Try these commands to see different features:");
176    println!();
177    println!("1. Basic usage with required flag:");
178    println!(
179        "   {} --name myserver",
180        std::env::args().next().unwrap_or_default()
181    );
182    println!();
183    println!("2. Choice flag validation:");
184    println!(
185        "   {} --name myserver --environment invalid  (will fail)",
186        std::env::args().next().unwrap_or_default()
187    );
188    println!(
189        "   {} --name myserver --environment production",
190        std::env::args().next().unwrap_or_default()
191    );
192    println!();
193    println!("3. Range validation:");
194    println!(
195        "   {} --name myserver --port 80  (will fail - below 1024)",
196        std::env::args().next().unwrap_or_default()
197    );
198    println!(
199        "   {} --name myserver --port 3000",
200        std::env::args().next().unwrap_or_default()
201    );
202    println!();
203    println!("4. File/Directory validation:");
204    println!(
205        "   {} --name myserver --config ./Cargo.toml",
206        std::env::args().next().unwrap_or_default()
207    );
208    println!(
209        "   {} --name myserver --log-dir ./src",
210        std::env::args().next().unwrap_or_default()
211    );
212    println!();
213    println!("5. Flag constraints:");
214    println!(
215        "   {} --name myserver --ssl  (will fail - missing cert and key)",
216        std::env::args().next().unwrap_or_default()
217    );
218    println!(
219        "   {} --name myserver --ssl --ssl-cert cert.pem --ssl-key key.pem",
220        std::env::args().next().unwrap_or_default()
221    );
222    println!(
223        "   {} --name myserver --debug --quiet  (will fail - conflicts)",
224        std::env::args().next().unwrap_or_default()
225    );
226    println!(
227        "   {} --name myserver --auth-token secret  (will fail - requires --auth-enabled)",
228        std::env::args().next().unwrap_or_default()
229    );
230    println!();
231    println!("6. View help:");
232    println!("   {} --help", std::env::args().next().unwrap_or_default());
233    println!("\n---\n");
234
235    let args: Vec<String> = std::env::args().skip(1).collect();
236    if let Err(e) = app.execute(args) {
237        eprintln!("{}", e);
238        std::process::exit(1);
239    }
240}
examples/help_formatting_demo.rs (line 133)
7fn main() {
8    let app = CommandBuilder::new("helpdemo")
9        .short("A demo of enhanced help formatting")
10        .long("This is a comprehensive demonstration of the enhanced help formatting system in flag-rs. \
11               It shows how help text is beautifully formatted with proper grouping, constraint \
12               information, and visual hierarchy.")
13        .group_id("utilities")
14        .example("helpdemo config --format=yaml --output=config.yaml")
15        .example("helpdemo process --workers=4 --verbose data.json")
16        .example("helpdemo serve --port=8080 --ssl --ssl-cert=cert.pem")
17        .flag(
18            Flag::new("verbose")
19                .short('v')
20                .value_type(FlagType::Bool)
21                .usage("Enable verbose output (can be repeated for more verbosity)"),
22        )
23        .flag(
24            Flag::new("config")
25                .short('c')
26                .value_type(FlagType::File)
27                .default(FlagValue::String("~/.config/app.toml".to_string()))
28                .usage("Configuration file path"),
29        )
30        .flag(
31            Flag::new("workers")
32                .short('w')
33                .value_type(FlagType::Range(1, 16))
34                .default(FlagValue::Int(4))
35                .usage("Number of worker threads"),
36        )
37        .flag(
38            Flag::new("timeout")
39                .short('t')
40                .value_type(FlagType::Int)
41                .default(FlagValue::Int(30))
42                .usage("Request timeout in seconds"),
43        )
44        .subcommand(
45            CommandBuilder::new("config")
46                .short("Manage configuration")
47                .long("The config command allows you to view, edit, and validate configuration files. \
48                      It supports multiple output formats and can merge configurations from various sources.")
49                .alias("cfg")
50                .alias("conf")
51                .example("helpdemo config show")
52                .example("helpdemo config validate --strict")
53                .flag(
54                    Flag::new("format")
55                        .short('f')
56                        .value_type(FlagType::Choice(vec![
57                            "json".to_string(),
58                            "yaml".to_string(),
59                            "toml".to_string(),
60                            "ini".to_string(),
61                        ]))
62                        .default(FlagValue::String("yaml".to_string()))
63                        .usage("Configuration file format"),
64                )
65                .flag(
66                    Flag::new("output")
67                        .short('o')
68                        .value_type(FlagType::String)
69                        .required()
70                        .usage("Output file path"),
71                )
72                .flag(
73                    Flag::new("merge")
74                        .value_type(FlagType::StringArray)
75                        .usage("Additional config files to merge"),
76                )
77                .flag(
78                    Flag::new("strict")
79                        .value_type(FlagType::Bool)
80                        .usage("Enable strict validation mode"),
81                )
82                .subcommand(
83                    CommandBuilder::new("show")
84                        .short("Display current configuration")
85                        .run(|_| Ok(()))
86                        .build(),
87                )
88                .subcommand(
89                    CommandBuilder::new("validate")
90                        .short("Validate configuration syntax")
91                        .run(|_| Ok(()))
92                        .build(),
93                )
94                .build(),
95        )
96        .subcommand(
97            CommandBuilder::new("process")
98                .short("Process data files")
99                .group_id("operations")
100                .flag(
101                    Flag::new("input")
102                        .short('i')
103                        .value_type(FlagType::File)
104                        .required()
105                        .usage("Input data file"),
106                )
107                .flag(
108                    Flag::new("output")
109                        .short('o')
110                        .value_type(FlagType::String)
111                        .required()
112                        .usage("Output file path"),
113                )
114                .flag(
115                    Flag::new("format")
116                        .short('f')
117                        .value_type(FlagType::Choice(vec![
118                            "csv".to_string(),
119                            "json".to_string(),
120                            "parquet".to_string(),
121                        ]))
122                        .usage("Output format"),
123                )
124                .flag(
125                    Flag::new("compress")
126                        .value_type(FlagType::Bool)
127                        .usage("Compress output"),
128                )
129                .flag(
130                    Flag::new("compression-level")
131                        .value_type(FlagType::Range(1, 9))
132                        .default(FlagValue::Int(6))
133                        .constraint(FlagConstraint::RequiredIf("compress".to_string()))
134                        .usage("Compression level"),
135                )
136                .run(|_| Ok(()))
137                .build(),
138        )
139        .subcommand(
140            CommandBuilder::new("serve")
141                .short("Start the server")
142                .group_id("operations")
143                .flag(
144                    Flag::new("port")
145                        .short('p')
146                        .value_type(FlagType::Range(1, 65535))
147                        .default(FlagValue::Int(8080))
148                        .usage("Port to listen on"),
149                )
150                .flag(
151                    Flag::new("host")
152                        .short('h')
153                        .value_type(FlagType::String)
154                        .default(FlagValue::String("127.0.0.1".to_string()))
155                        .usage("Host to bind to"),
156                )
157                .flag(
158                    Flag::new("ssl")
159                        .value_type(FlagType::Bool)
160                        .usage("Enable SSL/TLS"),
161                )
162                .flag(
163                    Flag::new("ssl-cert")
164                        .value_type(FlagType::File)
165                        .constraint(FlagConstraint::RequiredIf("ssl".to_string()))
166                        .usage("SSL certificate file"),
167                )
168                .flag(
169                    Flag::new("ssl-key")
170                        .value_type(FlagType::File)
171                        .constraint(FlagConstraint::RequiredIf("ssl".to_string()))
172                        .usage("SSL private key file"),
173                )
174                .flag(
175                    Flag::new("http2")
176                        .value_type(FlagType::Bool)
177                        .constraint(FlagConstraint::Requires(vec!["ssl".to_string()]))
178                        .usage("Enable HTTP/2 support"),
179                )
180                .flag(
181                    Flag::new("debug")
182                        .short('d')
183                        .value_type(FlagType::Bool)
184                        .constraint(FlagConstraint::ConflictsWith(vec!["production".to_string()]))
185                        .usage("Enable debug mode"),
186                )
187                .flag(
188                    Flag::new("production")
189                        .value_type(FlagType::Bool)
190                        .usage("Enable production mode"),
191                )
192                .run(|_| Ok(()))
193                .build(),
194        )
195        .build();
196
197    println!("This example demonstrates enhanced help formatting.");
198    println!("Try these commands to see different help layouts:\n");
199    println!("  # Main help with command groups");
200    println!("  cargo run --example help_formatting_demo -- --help\n");
201
202    println!("  # Subcommand help with required flags");
203    println!("  cargo run --example help_formatting_demo -- config --help\n");
204
205    println!("  # Subcommand with flag constraints");
206    println!("  cargo run --example help_formatting_demo -- serve --help\n");
207
208    let args: Vec<String> = std::env::args().skip(1).collect();
209    if !args.is_empty() {
210        if let Err(e) = app.execute(args) {
211            eprintln!("{}", e);
212            std::process::exit(1);
213        }
214    }
215}
Source

pub fn completion<F>(self, completion: F) -> Self
where F: Fn(&Context, &str) -> Result<CompletionResult> + Send + Sync + 'static,

Sets a completion function for this flag’s values

§Arguments
  • completion - A function that generates completions for flag values
§Examples
use flag_rs::flag::Flag;
use flag_rs::completion::CompletionResult;

let flag = Flag::file("config")
    .completion(|ctx, prefix| {
        // In a real application, you might list config files
        let configs = vec!["default.conf", "production.conf", "test.conf"];
        Ok(CompletionResult::new().extend(
            configs.into_iter()
                .filter(|c| c.starts_with(prefix))
                .map(String::from)
        ))
    });
Examples found in repository?
examples/flag_completion_demo.rs (lines 12-33)
4fn main() {
5    let app = CommandBuilder::new("deploy")
6        .short("Deploy application to various environments")
7        .flag(
8            Flag::choice("environment", &["dev", "staging", "prod"])
9                .short('e')
10                .usage("Target environment")
11                .required()
12                .completion(|_ctx, prefix| {
13                    // Dynamic completion - could check available environments
14                    let environments = vec![
15                        ("dev", "Development environment"),
16                        ("staging", "Staging environment (pre-production)"),
17                        ("prod", "Production environment"),
18                    ];
19
20                    let mut result = CompletionResult::new();
21                    for (env, desc) in environments {
22                        if env.starts_with(prefix) {
23                            result = result.add_with_description(env.to_string(), desc.to_string());
24                        }
25                    }
26
27                    // Add active help if no prefix
28                    if prefix.is_empty() {
29                        result = result.add_help_text("Available environments: dev, staging, prod");
30                    }
31
32                    Ok(result)
33                }),
34        )
35        .flag(
36            Flag::file("config")
37                .short('c')
38                .usage("Configuration file")
39                .default_str("config.yaml")
40                .completion(|_ctx, prefix| {
41                    // In a real app, you might list files in the config directory
42                    let configs = vec![
43                        "config.yaml",
44                        "config.dev.yaml",
45                        "config.staging.yaml",
46                        "config.prod.yaml",
47                        "secrets.yaml",
48                    ];
49
50                    Ok(CompletionResult::new().extend(
51                        configs
52                            .into_iter()
53                            .filter(|c| c.starts_with(prefix))
54                            .map(String::from),
55                    ))
56                }),
57        )
58        .flag(
59            Flag::directory("output")
60                .short('o')
61                .usage("Output directory for deployment artifacts")
62                .completion(|_ctx, prefix| {
63                    // In a real app, you might list actual directories
64                    let dirs = vec!["./build", "./dist", "./output", "/tmp/deploy"];
65
66                    Ok(CompletionResult::new().extend(
67                        dirs.into_iter()
68                            .filter(|d| d.starts_with(prefix))
69                            .map(String::from),
70                    ))
71                }),
72        )
73        .flag(
74            Flag::string_slice("service")
75                .short('s')
76                .usage("Services to deploy (can be specified multiple times)")
77                .completion(|ctx, prefix| {
78                    // Context-aware completion based on environment
79                    let env = ctx.flag_str_or("environment", "dev");
80
81                    let services = match env {
82                        "dev" => vec!["api", "web", "worker", "scheduler", "debug-panel"],
83                        "staging" => vec!["api", "web", "worker", "scheduler"],
84                        "prod" => vec!["api", "web", "worker"],
85                        _ => vec!["api", "web"],
86                    };
87
88                    let mut result = CompletionResult::new().extend(
89                        services
90                            .into_iter()
91                            .filter(|s| s.starts_with(prefix))
92                            .map(String::from),
93                    );
94
95                    // Add context-aware help
96                    if prefix.is_empty() {
97                        result = result
98                            .add_help_text(format!("Available services for {} environment", env));
99                    }
100
101                    Ok(result)
102                }),
103        )
104        .flag(
105            Flag::range("replicas", 1, 10)
106                .short('r')
107                .usage("Number of replicas to deploy")
108                .default_int(2)
109                .completion(|_ctx, _prefix| {
110                    // Suggest common replica counts
111                    Ok(CompletionResult::new()
112                        .add_with_description(
113                            "1".to_string(),
114                            "Single instance (dev/test)".to_string(),
115                        )
116                        .add_with_description("2".to_string(), "Basic redundancy".to_string())
117                        .add_with_description("3".to_string(), "Standard production".to_string())
118                        .add_with_description("5".to_string(), "High availability".to_string()))
119                }),
120        )
121        .run(|ctx| {
122            let env = ctx.flag_str_or("environment", "dev");
123            let config = ctx.flag_str_or("config", "config.yaml");
124            let replicas = ctx.flag_int_or("replicas", 2);
125
126            println!("Deploying to {} environment", env);
127            println!("Using configuration: {}", config);
128            println!("Replica count: {}", replicas);
129
130            if let Some(output) = ctx.flag("output") {
131                println!("Output directory: {}", output);
132            }
133
134            if let Some(services) = ctx.flag("service") {
135                println!("Deploying services: {}", services);
136            } else {
137                println!("Deploying all services");
138            }
139
140            Ok(())
141        })
142        .build();
143
144    let args: Vec<String> = std::env::args().skip(1).collect();
145    if let Err(e) = app.execute(args) {
146        eprintln!("Error: {}", e);
147        std::process::exit(1);
148    }
149}
More examples
Hide additional examples
examples/builder_api_demo.rs (lines 30-47)
4fn main() {
5    // Demonstrates all the new builder API improvements
6    let app = CommandBuilder::new("app")
7        .short("Modern CLI app with improved API")
8        .long(
9            "This example showcases the builder API improvements including:\n\
10               - Type-specific flag constructors\n\
11               - Inline flag completions\n\
12               - Bulk flag/subcommand methods\n\
13               - Type-safe context access",
14        )
15        // Bulk flag addition
16        .flags(vec![
17            // Type-specific constructors
18            Flag::bool("verbose")
19                .short('v')
20                .usage("Enable verbose output")
21                .default_bool(false),
22            Flag::bool("quiet").short('q').usage("Suppress all output"),
23            Flag::int("threads")
24                .short('t')
25                .usage("Number of worker threads")
26                .default_int(4),
27            Flag::choice("log-level", &["debug", "info", "warn", "error"])
28                .usage("Set the logging level")
29                .default_str("info")
30                .completion(|_ctx, prefix| {
31                    // Inline completion with descriptions
32                    let levels = vec![
33                        ("debug", "Show all messages including debug"),
34                        ("info", "Show informational messages and above"),
35                        ("warn", "Show warnings and errors only"),
36                        ("error", "Show errors only"),
37                    ];
38
39                    let mut result = flag_rs::CompletionResult::new();
40                    for (level, desc) in levels {
41                        if level.starts_with(prefix) {
42                            result =
43                                result.add_with_description(level.to_string(), desc.to_string());
44                        }
45                    }
46                    Ok(result)
47                }),
48        ])
49        // Bulk subcommand addition
50        .subcommands(vec![
51            CommandBuilder::new("init")
52                .short("Initialize a new project")
53                .flags(vec![
54                    Flag::string("name")
55                        .short('n')
56                        .usage("Project name")
57                        .required(),
58                    Flag::choice("template", &["basic", "web", "api", "full"])
59                        .usage("Project template to use")
60                        .default_str("basic"),
61                    Flag::directory("path")
62                        .short('p')
63                        .usage("Directory to create project in")
64                        .completion(|_ctx, prefix| {
65                            // In a real app, list actual directories
66                            let dirs = vec!["./", "../", "/tmp/", "~/projects/"];
67                            Ok(flag_rs::CompletionResult::new().extend(
68                                dirs.into_iter()
69                                    .filter(|d| d.starts_with(prefix))
70                                    .map(String::from),
71                            ))
72                        }),
73                ])
74                .run(|ctx| {
75                    // Type-safe flag access
76                    let name = ctx.flag_str_or("name", "my-project");
77                    let template = ctx.flag_str_or("template", "basic");
78                    let path = ctx.flag_str_or("path", ".");
79                    let verbose = ctx.flag_bool_or("verbose", false);
80
81                    if verbose {
82                        println!("Initializing {} project '{}' in {}", template, name, path);
83                    } else {
84                        println!("Creating project '{}'...", name);
85                    }
86
87                    Ok(())
88                })
89                .build(),
90            CommandBuilder::new("build")
91                .short("Build the project")
92                .flags(vec![
93                    Flag::bool("release")
94                        .short('r')
95                        .usage("Build in release mode"),
96                    Flag::string_slice("features")
97                        .short('f')
98                        .usage("Enable features (can be specified multiple times)")
99                        .completion(|_ctx, prefix| {
100                            let features = vec!["async", "tls", "compression", "metrics"];
101                            Ok(flag_rs::CompletionResult::new().extend(
102                                features
103                                    .into_iter()
104                                    .filter(|f| f.starts_with(prefix))
105                                    .map(String::from),
106                            ))
107                        }),
108                    Flag::range("jobs", 1, 32)
109                        .short('j')
110                        .usage("Number of parallel jobs")
111                        .default_int(i64::try_from(num_cpus()).unwrap_or(4)),
112                ])
113                .run(|ctx| {
114                    let release = ctx.flag_bool_or("release", false);
115                    let jobs = ctx.flag_int_or("jobs", i64::try_from(num_cpus()).unwrap_or(4));
116                    let quiet = ctx.flag_bool_or("quiet", false);
117
118                    if !quiet {
119                        println!(
120                            "Building in {} mode with {} jobs",
121                            if release { "release" } else { "debug" },
122                            jobs
123                        );
124
125                        if let Some(features) = ctx.flag("features") {
126                            println!("Features: {}", features);
127                        }
128                    }
129
130                    Ok(())
131                })
132                .build(),
133            CommandBuilder::new("test")
134                .short("Run tests")
135                .flags(vec![
136                    Flag::string("filter").usage("Only run tests matching this pattern"),
137                    Flag::bool("nocapture").usage("Don't capture test output"),
138                    Flag::int("test-threads")
139                        .usage("Number of threads to use for running tests")
140                        .default_int(1),
141                ])
142                .run(|ctx| {
143                    let threads = ctx.flag_int_or("test-threads", 1);
144                    let nocapture = ctx.flag_bool_or("nocapture", false);
145                    let verbose = ctx.flag_bool_or("verbose", false);
146
147                    if verbose {
148                        println!("Running tests with {} thread(s)", threads);
149                        if nocapture {
150                            println!("Output capture disabled");
151                        }
152
153                        if let Some(filter) = ctx.flag("filter") {
154                            println!("Filter: {}", filter);
155                        }
156                    }
157
158                    println!("Running tests...");
159                    Ok(())
160                })
161                .build(),
162        ])
163        .run(|_ctx| {
164            // Root command - show help by default
165            println!("Use --help for usage information");
166            Ok(())
167        })
168        .build();
169
170    let args: Vec<String> = std::env::args().skip(1).collect();
171    if let Err(e) = app.execute(args) {
172        eprintln!("Error: {}", e);
173        std::process::exit(1);
174    }
175}
Source§

impl Flag

Source

pub fn parse_value(&self, input: &str) -> Result<FlagValue>

Parses a string value according to this flag’s type

§Arguments
  • input - The string value to parse
§Returns

Returns the parsed FlagValue on success

§Errors

Returns Error::FlagParsing if the input cannot be parsed as the expected type

§Examples
use flag_rs::flag::{Flag, FlagType, FlagValue};

let int_flag = Flag::new("count").value_type(FlagType::Int);
match int_flag.parse_value("42") {
    Ok(FlagValue::Int(n)) => assert_eq!(n, 42),
    _ => panic!("Expected Int value"),
}

let bool_flag = Flag::new("verbose").value_type(FlagType::Bool);
match bool_flag.parse_value("true") {
    Ok(FlagValue::Bool(b)) => assert!(b),
    _ => panic!("Expected Bool value"),
}
Source

pub fn validate_constraints( &self, flag_name: &str, provided_flags: &HashSet<String>, ) -> Result<()>

Validates this flag’s constraints against the provided flags

§Arguments
  • flag_name - The name of this flag
  • provided_flags - Set of flag names that were provided
§Returns

Returns Ok(()) if all constraints are satisfied

§Errors

Returns Error::FlagParsing if any constraint is violated

Trait Implementations§

Source§

impl Clone for Flag

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more

Auto Trait Implementations§

§

impl Freeze for Flag

§

impl !RefUnwindSafe for Flag

§

impl Send for Flag

§

impl Sync for Flag

§

impl Unpin for Flag

§

impl !UnwindSafe for Flag

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.