CommandBuilder

Struct CommandBuilder 

Source
pub struct CommandBuilder { /* private fields */ }
Expand description

Builder for creating commands with a fluent API

CommandBuilder provides a convenient way to construct commands with method chaining. This is the recommended way to create commands.

§Examples

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

let cmd = CommandBuilder::new("serve")
    .short("Start the web server")
    .long("Start the web server on the specified port with the given configuration")
    .aliases(vec!["server", "s"])
    .flag(
        Flag::new("port")
            .short('p')
            .usage("Port to listen on")
            .value_type(FlagType::Int)
            .default(FlagValue::Int(8080))
    )
    .flag(
        Flag::new("config")
            .short('c')
            .usage("Configuration file path")
            .value_type(FlagType::String)
            .required()
    )
    .run(|ctx| {
        let port = ctx.flag("port")
            .and_then(|s| s.parse::<i64>().ok())
            .unwrap_or(8080);
        let config = ctx.flag("config")
            .map(|s| s.as_str())
            .unwrap_or("config.toml");

        println!("Starting server on port {} with config {}", port, config);
        Ok(())
    })
    .build();

Implementations§

Source§

impl CommandBuilder

Source

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

Creates a new command builder with the given name

Examples found in repository?
examples/benchmark.rs (line 51)
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 15)
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}
78
79fn build_get_pods() -> Command {
80    CommandBuilder::new("pods")
81        .aliases(vec!["po", "pod"])
82        .short("List pods")
83        .arg_completion(|ctx, prefix| {
84            // This is the key feature - dynamic completion based on runtime state!
85            let namespace = ctx
86                .flag("namespace")
87                .map(String::as_str)
88                .unwrap_or("default");
89
90            // In real kubectl, this would query the K8s API
91            let pods = get_pods_with_status(namespace);
92            let mut result = CompletionResult::new();
93
94            for (pod_name, status) in pods {
95                if pod_name.starts_with(prefix) {
96                    result = result.add_with_description(pod_name, status);
97                }
98            }
99
100            Ok(result)
101        })
102        .run(|ctx| {
103            let namespace = ctx
104                .flag("namespace")
105                .map(String::as_str)
106                .unwrap_or("default");
107
108            println!("Listing pods in namespace: {namespace}");
109
110            if let Some(pod_name) = ctx.args().first() {
111                println!("Getting specific pod: {pod_name}");
112            } else {
113                for pod in get_pods_in_namespace(namespace) {
114                    println!("pod/{}", pod);
115                }
116            }
117
118            Ok(())
119        })
120        .build()
121}
122
123fn build_get_services() -> Command {
124    CommandBuilder::new("services")
125        .aliases(vec!["svc", "service"])
126        .short("List services")
127        .arg_completion(|ctx, prefix| {
128            let namespace = ctx
129                .flag("namespace")
130                .map(String::as_str)
131                .unwrap_or("default");
132
133            let services = get_services_in_namespace(namespace);
134            Ok(CompletionResult::new()
135                .extend(services.into_iter().filter(|svc| svc.starts_with(prefix))))
136        })
137        .run(|ctx| {
138            let namespace = ctx
139                .flag("namespace")
140                .map(String::as_str)
141                .unwrap_or("default");
142
143            println!("Listing services in namespace: {namespace}");
144            Ok(())
145        })
146        .build()
147}
148
149fn build_get_deployments() -> Command {
150    CommandBuilder::new("deployments")
151        .aliases(vec!["deploy", "deployment"])
152        .short("List deployments")
153        .run(|ctx| {
154            let namespace = ctx
155                .flag("namespace")
156                .map(String::as_str)
157                .unwrap_or("default");
158
159            println!("Listing deployments in namespace: {namespace}");
160            Ok(())
161        })
162        .build()
163}
164
165fn build_describe_command() -> Command {
166    CommandBuilder::new("describe")
167        .short("Show details of a specific resource")
168        .run(|_ctx| {
169            println!("Describe command - add resource type subcommands");
170            Ok(())
171        })
172        .build()
173}
174
175fn build_delete_command() -> Command {
176    CommandBuilder::new("delete")
177        .short("Delete resources")
178        .run(|_ctx| {
179            println!("Delete command - add resource type subcommands");
180            Ok(())
181        })
182        .build()
183}
184
185// Mock functions that would normally query the Kubernetes API
186fn get_namespaces_with_descriptions() -> Vec<(String, String)> {
187    vec![
188        (
189            "default".to_string(),
190            "Default namespace for user workloads".to_string(),
191        ),
192        (
193            "kube-system".to_string(),
194            "Kubernetes system components".to_string(),
195        ),
196        (
197            "kube-public".to_string(),
198            "Public resources accessible to all users".to_string(),
199        ),
200        (
201            "development".to_string(),
202            "Development environment".to_string(),
203        ),
204        (
205            "staging".to_string(),
206            "Staging environment for pre-production testing".to_string(),
207        ),
208        (
209            "production".to_string(),
210            "Production environment (CAUTION)".to_string(),
211        ),
212    ]
213}
214
215fn get_pods_with_status(namespace: &str) -> Vec<(String, String)> {
216    use std::time::{SystemTime, UNIX_EPOCH};
217
218    // Generate random suffix based on current time
219    let timestamp = SystemTime::now()
220        .duration_since(UNIX_EPOCH)
221        .unwrap()
222        .as_secs();
223
224    // Simple pseudo-random generation
225    let rand1 = ((timestamp * 1_103_515_245 + 12345) / 65536) % 100_000;
226    let rand2 = ((rand1 * 1_103_515_245 + 12345) / 65536) % 100_000;
227    let rand3 = ((rand2 * 1_103_515_245 + 12345) / 65536) % 100_000;
228
229    match namespace {
230        "default" => vec![
231            (
232                format!("nginx-deployment-7fb96c846b-{:05x}", rand1),
233                "Running (2/2 containers)".to_string(),
234            ),
235            (
236                format!("nginx-deployment-7fb96c846b-{:05x}", rand2),
237                "Running (2/2 containers)".to_string(),
238            ),
239            (
240                "redis-master-0".to_string(),
241                "Running (1/1 containers)".to_string(),
242            ),
243            (
244                "redis-slave-0".to_string(),
245                "Running (1/1 containers)".to_string(),
246            ),
247            ("redis-slave-1".to_string(), "Pending".to_string()),
248        ],
249        "kube-system" => vec![
250            (
251                format!("coredns-5d78c9869d-{:05x}", rand1),
252                "Running (1/1 containers)".to_string(),
253            ),
254            (
255                format!("coredns-5d78c9869d-{:05x}", rand2),
256                "Running (1/1 containers)".to_string(),
257            ),
258            ("etcd-minikube".to_string(), "Running".to_string()),
259            ("kube-apiserver-minikube".to_string(), "Running".to_string()),
260            (
261                "kube-controller-manager-minikube".to_string(),
262                "Running".to_string(),
263            ),
264            (format!("kube-proxy-{:05x}", rand3), "Running".to_string()),
265            ("kube-scheduler-minikube".to_string(), "Running".to_string()),
266        ],
267        _ => vec![],
268    }
269}
270
271fn get_pods_in_namespace(namespace: &str) -> Vec<String> {
272    use std::time::{SystemTime, UNIX_EPOCH};
273
274    // Generate random suffix based on current time
275    let timestamp = SystemTime::now()
276        .duration_since(UNIX_EPOCH)
277        .unwrap()
278        .as_secs();
279
280    // Simple pseudo-random generation
281    let rand1 = ((timestamp * 1_103_515_245 + 12345) / 65536) % 100_000;
282    let rand2 = ((rand1 * 1_103_515_245 + 12345) / 65536) % 100_000;
283    let rand3 = ((rand2 * 1_103_515_245 + 12345) / 65536) % 100_000;
284
285    match namespace {
286        "default" => vec![
287            format!("nginx-deployment-7fb96c846b-{:05x}", rand1),
288            format!("nginx-deployment-7fb96c846b-{:05x}", rand2),
289            format!("redis-master-0"),
290            format!("redis-slave-0"),
291            format!("redis-slave-1"),
292        ],
293        "kube-system" => vec![
294            format!("coredns-5d78c9869d-{:05x}", rand1),
295            format!("coredns-5d78c9869d-{:05x}", rand2),
296            format!("etcd-minikube"),
297            format!("kube-apiserver-minikube"),
298            format!("kube-controller-manager-minikube"),
299            format!("kube-proxy-{:05x}", rand3),
300            format!("kube-scheduler-minikube"),
301        ],
302        _ => vec![],
303    }
304}
305
306fn get_services_in_namespace(namespace: &str) -> Vec<String> {
307    match namespace {
308        "default" => vec![
309            "kubernetes".to_string(),
310            "nginx-service".to_string(),
311            "redis-master".to_string(),
312            "redis-slave".to_string(),
313        ],
314        "kube-system" => vec!["kube-dns".to_string()],
315        _ => vec![],
316    }
317}
318
319fn build_completion_command() -> Command {
320    CommandBuilder::new("completion")
321        .short("Generate shell completion scripts")
322        .long("Generate shell completion scripts for kubectl")
323        .arg_completion(|_ctx, prefix| {
324            let shells = vec![
325                ("bash", "Bash shell completion"),
326                ("zsh", "Zsh shell completion"),
327                ("fish", "Fish shell completion"),
328            ];
329
330            let mut result = CompletionResult::new();
331            for (shell, description) in shells {
332                if shell.starts_with(prefix) {
333                    result =
334                        result.add_with_description(shell.to_string(), description.to_string());
335                }
336            }
337
338            Ok(result)
339        })
340        .run(|ctx| {
341            let shell_name = ctx.args().first().ok_or_else(|| {
342                flag_rs::Error::ArgumentParsing(
343                    "shell name required (bash, zsh, or fish)".to_string(),
344                )
345            })?;
346
347            let shell = match shell_name.as_str() {
348                "bash" => Shell::Bash,
349                "zsh" => Shell::Zsh,
350                "fish" => Shell::Fish,
351                _ => {
352                    return Err(flag_rs::Error::ArgumentParsing(format!(
353                        "unsupported shell: {}",
354                        shell_name
355                    )));
356                }
357            };
358
359            // In a real app, you'd get the root command from a shared reference
360            // For this example, we'll recreate it
361            let root = build_kubectl();
362            println!("{}", root.generate_completion(shell));
363
364            Ok(())
365        })
366        .build()
367}
examples/terminal_demo.rs (line 18)
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/suggestion_demo.rs (line 5)
4fn main() {
5    let app = CommandBuilder::new("suggestion-demo")
6        .short("Demonstrates command suggestions")
7        .subcommand(
8            CommandBuilder::new("start")
9                .short("Start the service")
10                .run(|_| {
11                    println!("Starting service...");
12                    Ok(())
13                })
14                .build(),
15        )
16        .subcommand(
17            CommandBuilder::new("stop")
18                .short("Stop the service")
19                .run(|_| {
20                    println!("Stopping service...");
21                    Ok(())
22                })
23                .build(),
24        )
25        .subcommand(
26            CommandBuilder::new("restart")
27                .short("Restart the service")
28                .run(|_| {
29                    println!("Restarting service...");
30                    Ok(())
31                })
32                .build(),
33        )
34        .subcommand(
35            CommandBuilder::new("status")
36                .short("Show service status")
37                .run(|_| {
38                    println!("Service is running");
39                    Ok(())
40                })
41                .build(),
42        )
43        .subcommand(
44            CommandBuilder::new("config")
45                .short("Manage configuration")
46                .subcommand(
47                    CommandBuilder::new("get")
48                        .short("Get configuration value")
49                        .run(|_| {
50                            println!("Configuration value: enabled");
51                            Ok(())
52                        })
53                        .build(),
54                )
55                .subcommand(
56                    CommandBuilder::new("set")
57                        .short("Set configuration value")
58                        .run(|_| {
59                            println!("Configuration updated");
60                            Ok(())
61                        })
62                        .build(),
63                )
64                .build(),
65        )
66        .build();
67
68    let args: Vec<String> = std::env::args().skip(1).collect();
69
70    // Show what command was attempted
71    if !args.is_empty() {
72        println!("Command attempted: {}\n", args[0]);
73    }
74
75    if let Err(e) = app.execute(args) {
76        eprintln!("Error: {}", e);
77        std::process::exit(1);
78    }
79}
examples/test_completion.rs (line 4)
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/validator_demo.rs (line 5)
4fn main() {
5    let app = CommandBuilder::new("validator-demo")
6        .short("Demonstrates argument validation")
7        .subcommand(
8            CommandBuilder::new("copy")
9                .short("Copy files (requires exactly 2 arguments)")
10                .args(ArgValidator::ExactArgs(2))
11                .run(|ctx| {
12                    let args = ctx.args();
13                    println!("Copying from '{}' to '{}'", args[0], args[1]);
14                    Ok(())
15                })
16                .build(),
17        )
18        .subcommand(
19            CommandBuilder::new("delete")
20                .short("Delete files (requires at least 1 argument)")
21                .args(ArgValidator::MinimumArgs(1))
22                .run(|ctx| {
23                    println!("Deleting {} file(s):", ctx.args().len());
24                    for file in ctx.args() {
25                        println!("  - {}", file);
26                    }
27                    Ok(())
28                })
29                .build(),
30        )
31        .subcommand(
32            CommandBuilder::new("list")
33                .short("List items (accepts 0-3 arguments)")
34                .args(ArgValidator::RangeArgs(0, 3))
35                .run(|ctx| {
36                    if ctx.args().is_empty() {
37                        println!("Listing all items");
38                    } else {
39                        println!("Listing specific items:");
40                        for item in ctx.args() {
41                            println!("  - {}", item);
42                        }
43                    }
44                    Ok(())
45                })
46                .build(),
47        )
48        .subcommand(
49            CommandBuilder::new("action")
50                .short("Perform action (only start/stop/restart allowed)")
51                .args(ArgValidator::OnlyValidArgs(vec![
52                    "start".to_string(),
53                    "stop".to_string(),
54                    "restart".to_string(),
55                ]))
56                .run(|ctx| {
57                    let action = ctx.args().first().map(String::as_str).unwrap_or("start");
58                    println!("Performing action: {}", action);
59                    Ok(())
60                })
61                .build(),
62        )
63        .subcommand(
64            CommandBuilder::new("numbers")
65                .short("Process numbers (custom validator for integers)")
66                .args(ArgValidator::Custom(std::sync::Arc::new(|args| {
67                    if args.is_empty() {
68                        return Err(Error::ArgumentValidation {
69                            message: "at least one number required".to_string(),
70                            expected: "numbers".to_string(),
71                            received: 0,
72                        });
73                    }
74
75                    for (i, arg) in args.iter().enumerate() {
76                        if arg.parse::<i32>().is_err() {
77                            return Err(Error::ArgumentValidation {
78                                message: format!(
79                                    "argument {} ('{}') must be an integer",
80                                    i + 1,
81                                    arg
82                                ),
83                                expected: "integer".to_string(),
84                                received: args.len(),
85                            });
86                        }
87                    }
88                    Ok(())
89                })))
90                .run(|ctx| {
91                    let numbers: Vec<i32> = ctx.args().iter().map(|s| s.parse().unwrap()).collect();
92                    let sum: i32 = numbers.iter().sum();
93                    println!("Sum of {} numbers: {}", numbers.len(), sum);
94                    Ok(())
95                })
96                .build(),
97        )
98        .build();
99
100    let args: Vec<String> = std::env::args().skip(1).collect();
101    if let Err(e) = app.execute(args) {
102        eprintln!("Error: {}", e);
103        std::process::exit(1);
104    }
105}
Source

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

Adds a single alias for this command

§Examples
use flag_rs::CommandBuilder;

let cmd = CommandBuilder::new("remove")
    .alias("rm")
    .alias("delete")
    .build();
Examples found in repository?
examples/help_formatting_demo.rs (line 49)
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 aliases<I, S>(self, aliases: I) -> Self
where I: IntoIterator<Item = S>, S: Into<String>,

Adds multiple aliases for this command

§Examples
use flag_rs::CommandBuilder;

let cmd = CommandBuilder::new("remove")
    .aliases(vec!["rm", "delete", "del"])
    .build();
Examples found in repository?
examples/kubectl.rs (line 81)
79fn build_get_pods() -> Command {
80    CommandBuilder::new("pods")
81        .aliases(vec!["po", "pod"])
82        .short("List pods")
83        .arg_completion(|ctx, prefix| {
84            // This is the key feature - dynamic completion based on runtime state!
85            let namespace = ctx
86                .flag("namespace")
87                .map(String::as_str)
88                .unwrap_or("default");
89
90            // In real kubectl, this would query the K8s API
91            let pods = get_pods_with_status(namespace);
92            let mut result = CompletionResult::new();
93
94            for (pod_name, status) in pods {
95                if pod_name.starts_with(prefix) {
96                    result = result.add_with_description(pod_name, status);
97                }
98            }
99
100            Ok(result)
101        })
102        .run(|ctx| {
103            let namespace = ctx
104                .flag("namespace")
105                .map(String::as_str)
106                .unwrap_or("default");
107
108            println!("Listing pods in namespace: {namespace}");
109
110            if let Some(pod_name) = ctx.args().first() {
111                println!("Getting specific pod: {pod_name}");
112            } else {
113                for pod in get_pods_in_namespace(namespace) {
114                    println!("pod/{}", pod);
115                }
116            }
117
118            Ok(())
119        })
120        .build()
121}
122
123fn build_get_services() -> Command {
124    CommandBuilder::new("services")
125        .aliases(vec!["svc", "service"])
126        .short("List services")
127        .arg_completion(|ctx, prefix| {
128            let namespace = ctx
129                .flag("namespace")
130                .map(String::as_str)
131                .unwrap_or("default");
132
133            let services = get_services_in_namespace(namespace);
134            Ok(CompletionResult::new()
135                .extend(services.into_iter().filter(|svc| svc.starts_with(prefix))))
136        })
137        .run(|ctx| {
138            let namespace = ctx
139                .flag("namespace")
140                .map(String::as_str)
141                .unwrap_or("default");
142
143            println!("Listing services in namespace: {namespace}");
144            Ok(())
145        })
146        .build()
147}
148
149fn build_get_deployments() -> Command {
150    CommandBuilder::new("deployments")
151        .aliases(vec!["deploy", "deployment"])
152        .short("List deployments")
153        .run(|ctx| {
154            let namespace = ctx
155                .flag("namespace")
156                .map(String::as_str)
157                .unwrap_or("default");
158
159            println!("Listing deployments in namespace: {namespace}");
160            Ok(())
161        })
162        .build()
163}
More examples
Hide additional examples
examples/error_handling_demo.rs (line 86)
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/enhanced_help_demo.rs (line 72)
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 short(self, short: impl Into<String>) -> Self

Sets the short description for this command

The short description is shown in the parent command’s help output.

Examples found in repository?
examples/benchmark.rs (line 52)
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 16)
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}
78
79fn build_get_pods() -> Command {
80    CommandBuilder::new("pods")
81        .aliases(vec!["po", "pod"])
82        .short("List pods")
83        .arg_completion(|ctx, prefix| {
84            // This is the key feature - dynamic completion based on runtime state!
85            let namespace = ctx
86                .flag("namespace")
87                .map(String::as_str)
88                .unwrap_or("default");
89
90            // In real kubectl, this would query the K8s API
91            let pods = get_pods_with_status(namespace);
92            let mut result = CompletionResult::new();
93
94            for (pod_name, status) in pods {
95                if pod_name.starts_with(prefix) {
96                    result = result.add_with_description(pod_name, status);
97                }
98            }
99
100            Ok(result)
101        })
102        .run(|ctx| {
103            let namespace = ctx
104                .flag("namespace")
105                .map(String::as_str)
106                .unwrap_or("default");
107
108            println!("Listing pods in namespace: {namespace}");
109
110            if let Some(pod_name) = ctx.args().first() {
111                println!("Getting specific pod: {pod_name}");
112            } else {
113                for pod in get_pods_in_namespace(namespace) {
114                    println!("pod/{}", pod);
115                }
116            }
117
118            Ok(())
119        })
120        .build()
121}
122
123fn build_get_services() -> Command {
124    CommandBuilder::new("services")
125        .aliases(vec!["svc", "service"])
126        .short("List services")
127        .arg_completion(|ctx, prefix| {
128            let namespace = ctx
129                .flag("namespace")
130                .map(String::as_str)
131                .unwrap_or("default");
132
133            let services = get_services_in_namespace(namespace);
134            Ok(CompletionResult::new()
135                .extend(services.into_iter().filter(|svc| svc.starts_with(prefix))))
136        })
137        .run(|ctx| {
138            let namespace = ctx
139                .flag("namespace")
140                .map(String::as_str)
141                .unwrap_or("default");
142
143            println!("Listing services in namespace: {namespace}");
144            Ok(())
145        })
146        .build()
147}
148
149fn build_get_deployments() -> Command {
150    CommandBuilder::new("deployments")
151        .aliases(vec!["deploy", "deployment"])
152        .short("List deployments")
153        .run(|ctx| {
154            let namespace = ctx
155                .flag("namespace")
156                .map(String::as_str)
157                .unwrap_or("default");
158
159            println!("Listing deployments in namespace: {namespace}");
160            Ok(())
161        })
162        .build()
163}
164
165fn build_describe_command() -> Command {
166    CommandBuilder::new("describe")
167        .short("Show details of a specific resource")
168        .run(|_ctx| {
169            println!("Describe command - add resource type subcommands");
170            Ok(())
171        })
172        .build()
173}
174
175fn build_delete_command() -> Command {
176    CommandBuilder::new("delete")
177        .short("Delete resources")
178        .run(|_ctx| {
179            println!("Delete command - add resource type subcommands");
180            Ok(())
181        })
182        .build()
183}
184
185// Mock functions that would normally query the Kubernetes API
186fn get_namespaces_with_descriptions() -> Vec<(String, String)> {
187    vec![
188        (
189            "default".to_string(),
190            "Default namespace for user workloads".to_string(),
191        ),
192        (
193            "kube-system".to_string(),
194            "Kubernetes system components".to_string(),
195        ),
196        (
197            "kube-public".to_string(),
198            "Public resources accessible to all users".to_string(),
199        ),
200        (
201            "development".to_string(),
202            "Development environment".to_string(),
203        ),
204        (
205            "staging".to_string(),
206            "Staging environment for pre-production testing".to_string(),
207        ),
208        (
209            "production".to_string(),
210            "Production environment (CAUTION)".to_string(),
211        ),
212    ]
213}
214
215fn get_pods_with_status(namespace: &str) -> Vec<(String, String)> {
216    use std::time::{SystemTime, UNIX_EPOCH};
217
218    // Generate random suffix based on current time
219    let timestamp = SystemTime::now()
220        .duration_since(UNIX_EPOCH)
221        .unwrap()
222        .as_secs();
223
224    // Simple pseudo-random generation
225    let rand1 = ((timestamp * 1_103_515_245 + 12345) / 65536) % 100_000;
226    let rand2 = ((rand1 * 1_103_515_245 + 12345) / 65536) % 100_000;
227    let rand3 = ((rand2 * 1_103_515_245 + 12345) / 65536) % 100_000;
228
229    match namespace {
230        "default" => vec![
231            (
232                format!("nginx-deployment-7fb96c846b-{:05x}", rand1),
233                "Running (2/2 containers)".to_string(),
234            ),
235            (
236                format!("nginx-deployment-7fb96c846b-{:05x}", rand2),
237                "Running (2/2 containers)".to_string(),
238            ),
239            (
240                "redis-master-0".to_string(),
241                "Running (1/1 containers)".to_string(),
242            ),
243            (
244                "redis-slave-0".to_string(),
245                "Running (1/1 containers)".to_string(),
246            ),
247            ("redis-slave-1".to_string(), "Pending".to_string()),
248        ],
249        "kube-system" => vec![
250            (
251                format!("coredns-5d78c9869d-{:05x}", rand1),
252                "Running (1/1 containers)".to_string(),
253            ),
254            (
255                format!("coredns-5d78c9869d-{:05x}", rand2),
256                "Running (1/1 containers)".to_string(),
257            ),
258            ("etcd-minikube".to_string(), "Running".to_string()),
259            ("kube-apiserver-minikube".to_string(), "Running".to_string()),
260            (
261                "kube-controller-manager-minikube".to_string(),
262                "Running".to_string(),
263            ),
264            (format!("kube-proxy-{:05x}", rand3), "Running".to_string()),
265            ("kube-scheduler-minikube".to_string(), "Running".to_string()),
266        ],
267        _ => vec![],
268    }
269}
270
271fn get_pods_in_namespace(namespace: &str) -> Vec<String> {
272    use std::time::{SystemTime, UNIX_EPOCH};
273
274    // Generate random suffix based on current time
275    let timestamp = SystemTime::now()
276        .duration_since(UNIX_EPOCH)
277        .unwrap()
278        .as_secs();
279
280    // Simple pseudo-random generation
281    let rand1 = ((timestamp * 1_103_515_245 + 12345) / 65536) % 100_000;
282    let rand2 = ((rand1 * 1_103_515_245 + 12345) / 65536) % 100_000;
283    let rand3 = ((rand2 * 1_103_515_245 + 12345) / 65536) % 100_000;
284
285    match namespace {
286        "default" => vec![
287            format!("nginx-deployment-7fb96c846b-{:05x}", rand1),
288            format!("nginx-deployment-7fb96c846b-{:05x}", rand2),
289            format!("redis-master-0"),
290            format!("redis-slave-0"),
291            format!("redis-slave-1"),
292        ],
293        "kube-system" => vec![
294            format!("coredns-5d78c9869d-{:05x}", rand1),
295            format!("coredns-5d78c9869d-{:05x}", rand2),
296            format!("etcd-minikube"),
297            format!("kube-apiserver-minikube"),
298            format!("kube-controller-manager-minikube"),
299            format!("kube-proxy-{:05x}", rand3),
300            format!("kube-scheduler-minikube"),
301        ],
302        _ => vec![],
303    }
304}
305
306fn get_services_in_namespace(namespace: &str) -> Vec<String> {
307    match namespace {
308        "default" => vec![
309            "kubernetes".to_string(),
310            "nginx-service".to_string(),
311            "redis-master".to_string(),
312            "redis-slave".to_string(),
313        ],
314        "kube-system" => vec!["kube-dns".to_string()],
315        _ => vec![],
316    }
317}
318
319fn build_completion_command() -> Command {
320    CommandBuilder::new("completion")
321        .short("Generate shell completion scripts")
322        .long("Generate shell completion scripts for kubectl")
323        .arg_completion(|_ctx, prefix| {
324            let shells = vec![
325                ("bash", "Bash shell completion"),
326                ("zsh", "Zsh shell completion"),
327                ("fish", "Fish shell completion"),
328            ];
329
330            let mut result = CompletionResult::new();
331            for (shell, description) in shells {
332                if shell.starts_with(prefix) {
333                    result =
334                        result.add_with_description(shell.to_string(), description.to_string());
335                }
336            }
337
338            Ok(result)
339        })
340        .run(|ctx| {
341            let shell_name = ctx.args().first().ok_or_else(|| {
342                flag_rs::Error::ArgumentParsing(
343                    "shell name required (bash, zsh, or fish)".to_string(),
344                )
345            })?;
346
347            let shell = match shell_name.as_str() {
348                "bash" => Shell::Bash,
349                "zsh" => Shell::Zsh,
350                "fish" => Shell::Fish,
351                _ => {
352                    return Err(flag_rs::Error::ArgumentParsing(format!(
353                        "unsupported shell: {}",
354                        shell_name
355                    )));
356                }
357            };
358
359            // In a real app, you'd get the root command from a shared reference
360            // For this example, we'll recreate it
361            let root = build_kubectl();
362            println!("{}", root.generate_completion(shell));
363
364            Ok(())
365        })
366        .build()
367}
examples/terminal_demo.rs (line 19)
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/suggestion_demo.rs (line 6)
4fn main() {
5    let app = CommandBuilder::new("suggestion-demo")
6        .short("Demonstrates command suggestions")
7        .subcommand(
8            CommandBuilder::new("start")
9                .short("Start the service")
10                .run(|_| {
11                    println!("Starting service...");
12                    Ok(())
13                })
14                .build(),
15        )
16        .subcommand(
17            CommandBuilder::new("stop")
18                .short("Stop the service")
19                .run(|_| {
20                    println!("Stopping service...");
21                    Ok(())
22                })
23                .build(),
24        )
25        .subcommand(
26            CommandBuilder::new("restart")
27                .short("Restart the service")
28                .run(|_| {
29                    println!("Restarting service...");
30                    Ok(())
31                })
32                .build(),
33        )
34        .subcommand(
35            CommandBuilder::new("status")
36                .short("Show service status")
37                .run(|_| {
38                    println!("Service is running");
39                    Ok(())
40                })
41                .build(),
42        )
43        .subcommand(
44            CommandBuilder::new("config")
45                .short("Manage configuration")
46                .subcommand(
47                    CommandBuilder::new("get")
48                        .short("Get configuration value")
49                        .run(|_| {
50                            println!("Configuration value: enabled");
51                            Ok(())
52                        })
53                        .build(),
54                )
55                .subcommand(
56                    CommandBuilder::new("set")
57                        .short("Set configuration value")
58                        .run(|_| {
59                            println!("Configuration updated");
60                            Ok(())
61                        })
62                        .build(),
63                )
64                .build(),
65        )
66        .build();
67
68    let args: Vec<String> = std::env::args().skip(1).collect();
69
70    // Show what command was attempted
71    if !args.is_empty() {
72        println!("Command attempted: {}\n", args[0]);
73    }
74
75    if let Err(e) = app.execute(args) {
76        eprintln!("Error: {}", e);
77        std::process::exit(1);
78    }
79}
examples/test_completion.rs (line 5)
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/validator_demo.rs (line 6)
4fn main() {
5    let app = CommandBuilder::new("validator-demo")
6        .short("Demonstrates argument validation")
7        .subcommand(
8            CommandBuilder::new("copy")
9                .short("Copy files (requires exactly 2 arguments)")
10                .args(ArgValidator::ExactArgs(2))
11                .run(|ctx| {
12                    let args = ctx.args();
13                    println!("Copying from '{}' to '{}'", args[0], args[1]);
14                    Ok(())
15                })
16                .build(),
17        )
18        .subcommand(
19            CommandBuilder::new("delete")
20                .short("Delete files (requires at least 1 argument)")
21                .args(ArgValidator::MinimumArgs(1))
22                .run(|ctx| {
23                    println!("Deleting {} file(s):", ctx.args().len());
24                    for file in ctx.args() {
25                        println!("  - {}", file);
26                    }
27                    Ok(())
28                })
29                .build(),
30        )
31        .subcommand(
32            CommandBuilder::new("list")
33                .short("List items (accepts 0-3 arguments)")
34                .args(ArgValidator::RangeArgs(0, 3))
35                .run(|ctx| {
36                    if ctx.args().is_empty() {
37                        println!("Listing all items");
38                    } else {
39                        println!("Listing specific items:");
40                        for item in ctx.args() {
41                            println!("  - {}", item);
42                        }
43                    }
44                    Ok(())
45                })
46                .build(),
47        )
48        .subcommand(
49            CommandBuilder::new("action")
50                .short("Perform action (only start/stop/restart allowed)")
51                .args(ArgValidator::OnlyValidArgs(vec![
52                    "start".to_string(),
53                    "stop".to_string(),
54                    "restart".to_string(),
55                ]))
56                .run(|ctx| {
57                    let action = ctx.args().first().map(String::as_str).unwrap_or("start");
58                    println!("Performing action: {}", action);
59                    Ok(())
60                })
61                .build(),
62        )
63        .subcommand(
64            CommandBuilder::new("numbers")
65                .short("Process numbers (custom validator for integers)")
66                .args(ArgValidator::Custom(std::sync::Arc::new(|args| {
67                    if args.is_empty() {
68                        return Err(Error::ArgumentValidation {
69                            message: "at least one number required".to_string(),
70                            expected: "numbers".to_string(),
71                            received: 0,
72                        });
73                    }
74
75                    for (i, arg) in args.iter().enumerate() {
76                        if arg.parse::<i32>().is_err() {
77                            return Err(Error::ArgumentValidation {
78                                message: format!(
79                                    "argument {} ('{}') must be an integer",
80                                    i + 1,
81                                    arg
82                                ),
83                                expected: "integer".to_string(),
84                                received: args.len(),
85                            });
86                        }
87                    }
88                    Ok(())
89                })))
90                .run(|ctx| {
91                    let numbers: Vec<i32> = ctx.args().iter().map(|s| s.parse().unwrap()).collect();
92                    let sum: i32 = numbers.iter().sum();
93                    println!("Sum of {} numbers: {}", numbers.len(), sum);
94                    Ok(())
95                })
96                .build(),
97        )
98        .build();
99
100    let args: Vec<String> = std::env::args().skip(1).collect();
101    if let Err(e) = app.execute(args) {
102        eprintln!("Error: {}", e);
103        std::process::exit(1);
104    }
105}
Source

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

Sets the long description for this command

The long description is shown in this command’s help output.

Examples found in repository?
examples/kubectl.rs (line 17)
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}
78
79fn build_get_pods() -> Command {
80    CommandBuilder::new("pods")
81        .aliases(vec!["po", "pod"])
82        .short("List pods")
83        .arg_completion(|ctx, prefix| {
84            // This is the key feature - dynamic completion based on runtime state!
85            let namespace = ctx
86                .flag("namespace")
87                .map(String::as_str)
88                .unwrap_or("default");
89
90            // In real kubectl, this would query the K8s API
91            let pods = get_pods_with_status(namespace);
92            let mut result = CompletionResult::new();
93
94            for (pod_name, status) in pods {
95                if pod_name.starts_with(prefix) {
96                    result = result.add_with_description(pod_name, status);
97                }
98            }
99
100            Ok(result)
101        })
102        .run(|ctx| {
103            let namespace = ctx
104                .flag("namespace")
105                .map(String::as_str)
106                .unwrap_or("default");
107
108            println!("Listing pods in namespace: {namespace}");
109
110            if let Some(pod_name) = ctx.args().first() {
111                println!("Getting specific pod: {pod_name}");
112            } else {
113                for pod in get_pods_in_namespace(namespace) {
114                    println!("pod/{}", pod);
115                }
116            }
117
118            Ok(())
119        })
120        .build()
121}
122
123fn build_get_services() -> Command {
124    CommandBuilder::new("services")
125        .aliases(vec!["svc", "service"])
126        .short("List services")
127        .arg_completion(|ctx, prefix| {
128            let namespace = ctx
129                .flag("namespace")
130                .map(String::as_str)
131                .unwrap_or("default");
132
133            let services = get_services_in_namespace(namespace);
134            Ok(CompletionResult::new()
135                .extend(services.into_iter().filter(|svc| svc.starts_with(prefix))))
136        })
137        .run(|ctx| {
138            let namespace = ctx
139                .flag("namespace")
140                .map(String::as_str)
141                .unwrap_or("default");
142
143            println!("Listing services in namespace: {namespace}");
144            Ok(())
145        })
146        .build()
147}
148
149fn build_get_deployments() -> Command {
150    CommandBuilder::new("deployments")
151        .aliases(vec!["deploy", "deployment"])
152        .short("List deployments")
153        .run(|ctx| {
154            let namespace = ctx
155                .flag("namespace")
156                .map(String::as_str)
157                .unwrap_or("default");
158
159            println!("Listing deployments in namespace: {namespace}");
160            Ok(())
161        })
162        .build()
163}
164
165fn build_describe_command() -> Command {
166    CommandBuilder::new("describe")
167        .short("Show details of a specific resource")
168        .run(|_ctx| {
169            println!("Describe command - add resource type subcommands");
170            Ok(())
171        })
172        .build()
173}
174
175fn build_delete_command() -> Command {
176    CommandBuilder::new("delete")
177        .short("Delete resources")
178        .run(|_ctx| {
179            println!("Delete command - add resource type subcommands");
180            Ok(())
181        })
182        .build()
183}
184
185// Mock functions that would normally query the Kubernetes API
186fn get_namespaces_with_descriptions() -> Vec<(String, String)> {
187    vec![
188        (
189            "default".to_string(),
190            "Default namespace for user workloads".to_string(),
191        ),
192        (
193            "kube-system".to_string(),
194            "Kubernetes system components".to_string(),
195        ),
196        (
197            "kube-public".to_string(),
198            "Public resources accessible to all users".to_string(),
199        ),
200        (
201            "development".to_string(),
202            "Development environment".to_string(),
203        ),
204        (
205            "staging".to_string(),
206            "Staging environment for pre-production testing".to_string(),
207        ),
208        (
209            "production".to_string(),
210            "Production environment (CAUTION)".to_string(),
211        ),
212    ]
213}
214
215fn get_pods_with_status(namespace: &str) -> Vec<(String, String)> {
216    use std::time::{SystemTime, UNIX_EPOCH};
217
218    // Generate random suffix based on current time
219    let timestamp = SystemTime::now()
220        .duration_since(UNIX_EPOCH)
221        .unwrap()
222        .as_secs();
223
224    // Simple pseudo-random generation
225    let rand1 = ((timestamp * 1_103_515_245 + 12345) / 65536) % 100_000;
226    let rand2 = ((rand1 * 1_103_515_245 + 12345) / 65536) % 100_000;
227    let rand3 = ((rand2 * 1_103_515_245 + 12345) / 65536) % 100_000;
228
229    match namespace {
230        "default" => vec![
231            (
232                format!("nginx-deployment-7fb96c846b-{:05x}", rand1),
233                "Running (2/2 containers)".to_string(),
234            ),
235            (
236                format!("nginx-deployment-7fb96c846b-{:05x}", rand2),
237                "Running (2/2 containers)".to_string(),
238            ),
239            (
240                "redis-master-0".to_string(),
241                "Running (1/1 containers)".to_string(),
242            ),
243            (
244                "redis-slave-0".to_string(),
245                "Running (1/1 containers)".to_string(),
246            ),
247            ("redis-slave-1".to_string(), "Pending".to_string()),
248        ],
249        "kube-system" => vec![
250            (
251                format!("coredns-5d78c9869d-{:05x}", rand1),
252                "Running (1/1 containers)".to_string(),
253            ),
254            (
255                format!("coredns-5d78c9869d-{:05x}", rand2),
256                "Running (1/1 containers)".to_string(),
257            ),
258            ("etcd-minikube".to_string(), "Running".to_string()),
259            ("kube-apiserver-minikube".to_string(), "Running".to_string()),
260            (
261                "kube-controller-manager-minikube".to_string(),
262                "Running".to_string(),
263            ),
264            (format!("kube-proxy-{:05x}", rand3), "Running".to_string()),
265            ("kube-scheduler-minikube".to_string(), "Running".to_string()),
266        ],
267        _ => vec![],
268    }
269}
270
271fn get_pods_in_namespace(namespace: &str) -> Vec<String> {
272    use std::time::{SystemTime, UNIX_EPOCH};
273
274    // Generate random suffix based on current time
275    let timestamp = SystemTime::now()
276        .duration_since(UNIX_EPOCH)
277        .unwrap()
278        .as_secs();
279
280    // Simple pseudo-random generation
281    let rand1 = ((timestamp * 1_103_515_245 + 12345) / 65536) % 100_000;
282    let rand2 = ((rand1 * 1_103_515_245 + 12345) / 65536) % 100_000;
283    let rand3 = ((rand2 * 1_103_515_245 + 12345) / 65536) % 100_000;
284
285    match namespace {
286        "default" => vec![
287            format!("nginx-deployment-7fb96c846b-{:05x}", rand1),
288            format!("nginx-deployment-7fb96c846b-{:05x}", rand2),
289            format!("redis-master-0"),
290            format!("redis-slave-0"),
291            format!("redis-slave-1"),
292        ],
293        "kube-system" => vec![
294            format!("coredns-5d78c9869d-{:05x}", rand1),
295            format!("coredns-5d78c9869d-{:05x}", rand2),
296            format!("etcd-minikube"),
297            format!("kube-apiserver-minikube"),
298            format!("kube-controller-manager-minikube"),
299            format!("kube-proxy-{:05x}", rand3),
300            format!("kube-scheduler-minikube"),
301        ],
302        _ => vec![],
303    }
304}
305
306fn get_services_in_namespace(namespace: &str) -> Vec<String> {
307    match namespace {
308        "default" => vec![
309            "kubernetes".to_string(),
310            "nginx-service".to_string(),
311            "redis-master".to_string(),
312            "redis-slave".to_string(),
313        ],
314        "kube-system" => vec!["kube-dns".to_string()],
315        _ => vec![],
316    }
317}
318
319fn build_completion_command() -> Command {
320    CommandBuilder::new("completion")
321        .short("Generate shell completion scripts")
322        .long("Generate shell completion scripts for kubectl")
323        .arg_completion(|_ctx, prefix| {
324            let shells = vec![
325                ("bash", "Bash shell completion"),
326                ("zsh", "Zsh shell completion"),
327                ("fish", "Fish shell completion"),
328            ];
329
330            let mut result = CompletionResult::new();
331            for (shell, description) in shells {
332                if shell.starts_with(prefix) {
333                    result =
334                        result.add_with_description(shell.to_string(), description.to_string());
335                }
336            }
337
338            Ok(result)
339        })
340        .run(|ctx| {
341            let shell_name = ctx.args().first().ok_or_else(|| {
342                flag_rs::Error::ArgumentParsing(
343                    "shell name required (bash, zsh, or fish)".to_string(),
344                )
345            })?;
346
347            let shell = match shell_name.as_str() {
348                "bash" => Shell::Bash,
349                "zsh" => Shell::Zsh,
350                "fish" => Shell::Fish,
351                _ => {
352                    return Err(flag_rs::Error::ArgumentParsing(format!(
353                        "unsupported shell: {}",
354                        shell_name
355                    )));
356                }
357            };
358
359            // In a real app, you'd get the root command from a shared reference
360            // For this example, we'll recreate it
361            let root = build_kubectl();
362            println!("{}", root.generate_completion(shell));
363
364            Ok(())
365        })
366        .build()
367}
More examples
Hide additional examples
examples/terminal_demo.rs (line 20)
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 31)
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/memory_optimization_demo.rs (lines 133-142)
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 15)
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/enhanced_help_demo.rs (lines 13-14)
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 example(self, example: impl Into<String>) -> Self

Adds an example for this command

Examples are shown in the help output to demonstrate command usage.

§Examples
use flag_rs::CommandBuilder;

let cmd = CommandBuilder::new("deploy")
    .short("Deploy the application")
    .example("deploy --env production")
    .example("deploy --env staging --dry-run")
    .build();
Examples found in repository?
examples/enhanced_help_demo.rs (line 15)
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}
More examples
Hide additional examples
examples/help_formatting_demo.rs (line 14)
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 group_id(self, group_id: impl Into<String>) -> Self

Sets the group ID for this command

Commands with the same group ID will be displayed together in help output.

§Examples
use flag_rs::CommandBuilder;

let app = CommandBuilder::new("kubectl")
    .subcommand(
        CommandBuilder::new("get")
            .short("Display resources")
            .group_id("Basic Commands")
            .build()
    )
    .subcommand(
        CommandBuilder::new("create")
            .short("Create resources")
            .group_id("Basic Commands")
            .build()
    )
    .subcommand(
        CommandBuilder::new("config")
            .short("Modify kubeconfig files")
            .group_id("Settings Commands")
            .build()
    )
    .build();
Examples found in repository?
examples/enhanced_help_demo.rs (line 33)
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}
More examples
Hide additional examples
examples/help_formatting_demo.rs (line 13)
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 subcommand(self, cmd: Command) -> Self

Adds a subcommand to this command

§Examples
use flag_rs::CommandBuilder;

let app = CommandBuilder::new("myapp")
    .subcommand(
        CommandBuilder::new("init")
            .short("Initialize a new project")
            .build()
    )
    .subcommand(
        CommandBuilder::new("build")
            .short("Build the project")
            .build()
    )
    .build();
Examples found in repository?
examples/kubectl.rs (line 18)
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 (lines 34-38)
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/suggestion_demo.rs (lines 7-15)
4fn main() {
5    let app = CommandBuilder::new("suggestion-demo")
6        .short("Demonstrates command suggestions")
7        .subcommand(
8            CommandBuilder::new("start")
9                .short("Start the service")
10                .run(|_| {
11                    println!("Starting service...");
12                    Ok(())
13                })
14                .build(),
15        )
16        .subcommand(
17            CommandBuilder::new("stop")
18                .short("Stop the service")
19                .run(|_| {
20                    println!("Stopping service...");
21                    Ok(())
22                })
23                .build(),
24        )
25        .subcommand(
26            CommandBuilder::new("restart")
27                .short("Restart the service")
28                .run(|_| {
29                    println!("Restarting service...");
30                    Ok(())
31                })
32                .build(),
33        )
34        .subcommand(
35            CommandBuilder::new("status")
36                .short("Show service status")
37                .run(|_| {
38                    println!("Service is running");
39                    Ok(())
40                })
41                .build(),
42        )
43        .subcommand(
44            CommandBuilder::new("config")
45                .short("Manage configuration")
46                .subcommand(
47                    CommandBuilder::new("get")
48                        .short("Get configuration value")
49                        .run(|_| {
50                            println!("Configuration value: enabled");
51                            Ok(())
52                        })
53                        .build(),
54                )
55                .subcommand(
56                    CommandBuilder::new("set")
57                        .short("Set configuration value")
58                        .run(|_| {
59                            println!("Configuration updated");
60                            Ok(())
61                        })
62                        .build(),
63                )
64                .build(),
65        )
66        .build();
67
68    let args: Vec<String> = std::env::args().skip(1).collect();
69
70    // Show what command was attempted
71    if !args.is_empty() {
72        println!("Command attempted: {}\n", args[0]);
73    }
74
75    if let Err(e) = app.execute(args) {
76        eprintln!("Error: {}", e);
77        std::process::exit(1);
78    }
79}
examples/test_completion.rs (lines 28-33)
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/validator_demo.rs (lines 7-17)
4fn main() {
5    let app = CommandBuilder::new("validator-demo")
6        .short("Demonstrates argument validation")
7        .subcommand(
8            CommandBuilder::new("copy")
9                .short("Copy files (requires exactly 2 arguments)")
10                .args(ArgValidator::ExactArgs(2))
11                .run(|ctx| {
12                    let args = ctx.args();
13                    println!("Copying from '{}' to '{}'", args[0], args[1]);
14                    Ok(())
15                })
16                .build(),
17        )
18        .subcommand(
19            CommandBuilder::new("delete")
20                .short("Delete files (requires at least 1 argument)")
21                .args(ArgValidator::MinimumArgs(1))
22                .run(|ctx| {
23                    println!("Deleting {} file(s):", ctx.args().len());
24                    for file in ctx.args() {
25                        println!("  - {}", file);
26                    }
27                    Ok(())
28                })
29                .build(),
30        )
31        .subcommand(
32            CommandBuilder::new("list")
33                .short("List items (accepts 0-3 arguments)")
34                .args(ArgValidator::RangeArgs(0, 3))
35                .run(|ctx| {
36                    if ctx.args().is_empty() {
37                        println!("Listing all items");
38                    } else {
39                        println!("Listing specific items:");
40                        for item in ctx.args() {
41                            println!("  - {}", item);
42                        }
43                    }
44                    Ok(())
45                })
46                .build(),
47        )
48        .subcommand(
49            CommandBuilder::new("action")
50                .short("Perform action (only start/stop/restart allowed)")
51                .args(ArgValidator::OnlyValidArgs(vec![
52                    "start".to_string(),
53                    "stop".to_string(),
54                    "restart".to_string(),
55                ]))
56                .run(|ctx| {
57                    let action = ctx.args().first().map(String::as_str).unwrap_or("start");
58                    println!("Performing action: {}", action);
59                    Ok(())
60                })
61                .build(),
62        )
63        .subcommand(
64            CommandBuilder::new("numbers")
65                .short("Process numbers (custom validator for integers)")
66                .args(ArgValidator::Custom(std::sync::Arc::new(|args| {
67                    if args.is_empty() {
68                        return Err(Error::ArgumentValidation {
69                            message: "at least one number required".to_string(),
70                            expected: "numbers".to_string(),
71                            received: 0,
72                        });
73                    }
74
75                    for (i, arg) in args.iter().enumerate() {
76                        if arg.parse::<i32>().is_err() {
77                            return Err(Error::ArgumentValidation {
78                                message: format!(
79                                    "argument {} ('{}') must be an integer",
80                                    i + 1,
81                                    arg
82                                ),
83                                expected: "integer".to_string(),
84                                received: args.len(),
85                            });
86                        }
87                    }
88                    Ok(())
89                })))
90                .run(|ctx| {
91                    let numbers: Vec<i32> = ctx.args().iter().map(|s| s.parse().unwrap()).collect();
92                    let sum: i32 = numbers.iter().sum();
93                    println!("Sum of {} numbers: {}", numbers.len(), sum);
94                    Ok(())
95                })
96                .build(),
97        )
98        .build();
99
100    let args: Vec<String> = std::env::args().skip(1).collect();
101    if let Err(e) = app.execute(args) {
102        eprintln!("Error: {}", e);
103        std::process::exit(1);
104    }
105}
examples/enhanced_errors_demo.rs (lines 73-81)
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}
Source

pub fn subcommands(self, cmds: Vec<Command>) -> Self

Adds multiple subcommands to this command at once

§Examples
use flag_rs::CommandBuilder;

let cmd = CommandBuilder::new("git")
    .subcommands(vec![
        CommandBuilder::new("add")
            .short("Add file contents to the index")
            .build(),
        CommandBuilder::new("commit")
            .short("Record changes to the repository")
            .build(),
        CommandBuilder::new("push")
            .short("Update remote refs along with associated objects")
            .build(),
    ])
    .build();
Examples found in repository?
examples/builder_api_demo.rs (lines 50-162)
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 flag(self, flag: Flag) -> Self

Adds a flag to this command

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

let cmd = CommandBuilder::new("deploy")
    .flag(
        Flag::new("force")
            .short('f')
            .usage("Force deployment without confirmation")
            .value_type(FlagType::Bool)
    )
    .build();
Examples found in repository?
examples/benchmark.rs (lines 53-58)
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 (lines 22-28)
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 (lines 21-26)
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 (lines 6-11)
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 (lines 10-15)
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 (lines 24-30)
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 flags(self, flags: Vec<Flag>) -> Self

Adds multiple flags to this command at once

§Examples
use flag_rs::{CommandBuilder, Flag};

let cmd = CommandBuilder::new("server")
    .flags(vec![
        Flag::bool("verbose").short('v').usage("Enable verbose output"),
        Flag::bool("quiet").short('q').usage("Suppress output"),
        Flag::int("port").short('p').usage("Port to listen on").default_int(8080),
    ])
    .build();
Examples found in repository?
examples/builder_api_demo.rs (lines 16-48)
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 run<F>(self, f: F) -> Self
where F: Fn(&mut Context) -> Result<()> + Send + Sync + 'static,

Sets the function to run when this command is executed

The run function receives a mutable reference to the Context which provides access to parsed flags and arguments.

§Examples
use flag_rs::CommandBuilder;

let cmd = CommandBuilder::new("greet")
    .run(|ctx| {
        let name = ctx.args().first()
            .map(|s| s.as_str())
            .unwrap_or("World");
        println!("Hello, {}!", name);
        Ok(())
    })
    .build();
Examples found in repository?
examples/kubectl.rs (lines 102-119)
79fn build_get_pods() -> Command {
80    CommandBuilder::new("pods")
81        .aliases(vec!["po", "pod"])
82        .short("List pods")
83        .arg_completion(|ctx, prefix| {
84            // This is the key feature - dynamic completion based on runtime state!
85            let namespace = ctx
86                .flag("namespace")
87                .map(String::as_str)
88                .unwrap_or("default");
89
90            // In real kubectl, this would query the K8s API
91            let pods = get_pods_with_status(namespace);
92            let mut result = CompletionResult::new();
93
94            for (pod_name, status) in pods {
95                if pod_name.starts_with(prefix) {
96                    result = result.add_with_description(pod_name, status);
97                }
98            }
99
100            Ok(result)
101        })
102        .run(|ctx| {
103            let namespace = ctx
104                .flag("namespace")
105                .map(String::as_str)
106                .unwrap_or("default");
107
108            println!("Listing pods in namespace: {namespace}");
109
110            if let Some(pod_name) = ctx.args().first() {
111                println!("Getting specific pod: {pod_name}");
112            } else {
113                for pod in get_pods_in_namespace(namespace) {
114                    println!("pod/{}", pod);
115                }
116            }
117
118            Ok(())
119        })
120        .build()
121}
122
123fn build_get_services() -> Command {
124    CommandBuilder::new("services")
125        .aliases(vec!["svc", "service"])
126        .short("List services")
127        .arg_completion(|ctx, prefix| {
128            let namespace = ctx
129                .flag("namespace")
130                .map(String::as_str)
131                .unwrap_or("default");
132
133            let services = get_services_in_namespace(namespace);
134            Ok(CompletionResult::new()
135                .extend(services.into_iter().filter(|svc| svc.starts_with(prefix))))
136        })
137        .run(|ctx| {
138            let namespace = ctx
139                .flag("namespace")
140                .map(String::as_str)
141                .unwrap_or("default");
142
143            println!("Listing services in namespace: {namespace}");
144            Ok(())
145        })
146        .build()
147}
148
149fn build_get_deployments() -> Command {
150    CommandBuilder::new("deployments")
151        .aliases(vec!["deploy", "deployment"])
152        .short("List deployments")
153        .run(|ctx| {
154            let namespace = ctx
155                .flag("namespace")
156                .map(String::as_str)
157                .unwrap_or("default");
158
159            println!("Listing deployments in namespace: {namespace}");
160            Ok(())
161        })
162        .build()
163}
164
165fn build_describe_command() -> Command {
166    CommandBuilder::new("describe")
167        .short("Show details of a specific resource")
168        .run(|_ctx| {
169            println!("Describe command - add resource type subcommands");
170            Ok(())
171        })
172        .build()
173}
174
175fn build_delete_command() -> Command {
176    CommandBuilder::new("delete")
177        .short("Delete resources")
178        .run(|_ctx| {
179            println!("Delete command - add resource type subcommands");
180            Ok(())
181        })
182        .build()
183}
184
185// Mock functions that would normally query the Kubernetes API
186fn get_namespaces_with_descriptions() -> Vec<(String, String)> {
187    vec![
188        (
189            "default".to_string(),
190            "Default namespace for user workloads".to_string(),
191        ),
192        (
193            "kube-system".to_string(),
194            "Kubernetes system components".to_string(),
195        ),
196        (
197            "kube-public".to_string(),
198            "Public resources accessible to all users".to_string(),
199        ),
200        (
201            "development".to_string(),
202            "Development environment".to_string(),
203        ),
204        (
205            "staging".to_string(),
206            "Staging environment for pre-production testing".to_string(),
207        ),
208        (
209            "production".to_string(),
210            "Production environment (CAUTION)".to_string(),
211        ),
212    ]
213}
214
215fn get_pods_with_status(namespace: &str) -> Vec<(String, String)> {
216    use std::time::{SystemTime, UNIX_EPOCH};
217
218    // Generate random suffix based on current time
219    let timestamp = SystemTime::now()
220        .duration_since(UNIX_EPOCH)
221        .unwrap()
222        .as_secs();
223
224    // Simple pseudo-random generation
225    let rand1 = ((timestamp * 1_103_515_245 + 12345) / 65536) % 100_000;
226    let rand2 = ((rand1 * 1_103_515_245 + 12345) / 65536) % 100_000;
227    let rand3 = ((rand2 * 1_103_515_245 + 12345) / 65536) % 100_000;
228
229    match namespace {
230        "default" => vec![
231            (
232                format!("nginx-deployment-7fb96c846b-{:05x}", rand1),
233                "Running (2/2 containers)".to_string(),
234            ),
235            (
236                format!("nginx-deployment-7fb96c846b-{:05x}", rand2),
237                "Running (2/2 containers)".to_string(),
238            ),
239            (
240                "redis-master-0".to_string(),
241                "Running (1/1 containers)".to_string(),
242            ),
243            (
244                "redis-slave-0".to_string(),
245                "Running (1/1 containers)".to_string(),
246            ),
247            ("redis-slave-1".to_string(), "Pending".to_string()),
248        ],
249        "kube-system" => vec![
250            (
251                format!("coredns-5d78c9869d-{:05x}", rand1),
252                "Running (1/1 containers)".to_string(),
253            ),
254            (
255                format!("coredns-5d78c9869d-{:05x}", rand2),
256                "Running (1/1 containers)".to_string(),
257            ),
258            ("etcd-minikube".to_string(), "Running".to_string()),
259            ("kube-apiserver-minikube".to_string(), "Running".to_string()),
260            (
261                "kube-controller-manager-minikube".to_string(),
262                "Running".to_string(),
263            ),
264            (format!("kube-proxy-{:05x}", rand3), "Running".to_string()),
265            ("kube-scheduler-minikube".to_string(), "Running".to_string()),
266        ],
267        _ => vec![],
268    }
269}
270
271fn get_pods_in_namespace(namespace: &str) -> Vec<String> {
272    use std::time::{SystemTime, UNIX_EPOCH};
273
274    // Generate random suffix based on current time
275    let timestamp = SystemTime::now()
276        .duration_since(UNIX_EPOCH)
277        .unwrap()
278        .as_secs();
279
280    // Simple pseudo-random generation
281    let rand1 = ((timestamp * 1_103_515_245 + 12345) / 65536) % 100_000;
282    let rand2 = ((rand1 * 1_103_515_245 + 12345) / 65536) % 100_000;
283    let rand3 = ((rand2 * 1_103_515_245 + 12345) / 65536) % 100_000;
284
285    match namespace {
286        "default" => vec![
287            format!("nginx-deployment-7fb96c846b-{:05x}", rand1),
288            format!("nginx-deployment-7fb96c846b-{:05x}", rand2),
289            format!("redis-master-0"),
290            format!("redis-slave-0"),
291            format!("redis-slave-1"),
292        ],
293        "kube-system" => vec![
294            format!("coredns-5d78c9869d-{:05x}", rand1),
295            format!("coredns-5d78c9869d-{:05x}", rand2),
296            format!("etcd-minikube"),
297            format!("kube-apiserver-minikube"),
298            format!("kube-controller-manager-minikube"),
299            format!("kube-proxy-{:05x}", rand3),
300            format!("kube-scheduler-minikube"),
301        ],
302        _ => vec![],
303    }
304}
305
306fn get_services_in_namespace(namespace: &str) -> Vec<String> {
307    match namespace {
308        "default" => vec![
309            "kubernetes".to_string(),
310            "nginx-service".to_string(),
311            "redis-master".to_string(),
312            "redis-slave".to_string(),
313        ],
314        "kube-system" => vec!["kube-dns".to_string()],
315        _ => vec![],
316    }
317}
318
319fn build_completion_command() -> Command {
320    CommandBuilder::new("completion")
321        .short("Generate shell completion scripts")
322        .long("Generate shell completion scripts for kubectl")
323        .arg_completion(|_ctx, prefix| {
324            let shells = vec![
325                ("bash", "Bash shell completion"),
326                ("zsh", "Zsh shell completion"),
327                ("fish", "Fish shell completion"),
328            ];
329
330            let mut result = CompletionResult::new();
331            for (shell, description) in shells {
332                if shell.starts_with(prefix) {
333                    result =
334                        result.add_with_description(shell.to_string(), description.to_string());
335                }
336            }
337
338            Ok(result)
339        })
340        .run(|ctx| {
341            let shell_name = ctx.args().first().ok_or_else(|| {
342                flag_rs::Error::ArgumentParsing(
343                    "shell name required (bash, zsh, or fish)".to_string(),
344                )
345            })?;
346
347            let shell = match shell_name.as_str() {
348                "bash" => Shell::Bash,
349                "zsh" => Shell::Zsh,
350                "fish" => Shell::Fish,
351                _ => {
352                    return Err(flag_rs::Error::ArgumentParsing(format!(
353                        "unsupported shell: {}",
354                        shell_name
355                    )));
356                }
357            };
358
359            // In a real app, you'd get the root command from a shared reference
360            // For this example, we'll recreate it
361            let root = build_kubectl();
362            println!("{}", root.generate_completion(shell));
363
364            Ok(())
365        })
366        .build()
367}
More examples
Hide additional examples
examples/suggestion_demo.rs (lines 10-13)
4fn main() {
5    let app = CommandBuilder::new("suggestion-demo")
6        .short("Demonstrates command suggestions")
7        .subcommand(
8            CommandBuilder::new("start")
9                .short("Start the service")
10                .run(|_| {
11                    println!("Starting service...");
12                    Ok(())
13                })
14                .build(),
15        )
16        .subcommand(
17            CommandBuilder::new("stop")
18                .short("Stop the service")
19                .run(|_| {
20                    println!("Stopping service...");
21                    Ok(())
22                })
23                .build(),
24        )
25        .subcommand(
26            CommandBuilder::new("restart")
27                .short("Restart the service")
28                .run(|_| {
29                    println!("Restarting service...");
30                    Ok(())
31                })
32                .build(),
33        )
34        .subcommand(
35            CommandBuilder::new("status")
36                .short("Show service status")
37                .run(|_| {
38                    println!("Service is running");
39                    Ok(())
40                })
41                .build(),
42        )
43        .subcommand(
44            CommandBuilder::new("config")
45                .short("Manage configuration")
46                .subcommand(
47                    CommandBuilder::new("get")
48                        .short("Get configuration value")
49                        .run(|_| {
50                            println!("Configuration value: enabled");
51                            Ok(())
52                        })
53                        .build(),
54                )
55                .subcommand(
56                    CommandBuilder::new("set")
57                        .short("Set configuration value")
58                        .run(|_| {
59                            println!("Configuration updated");
60                            Ok(())
61                        })
62                        .build(),
63                )
64                .build(),
65        )
66        .build();
67
68    let args: Vec<String> = std::env::args().skip(1).collect();
69
70    // Show what command was attempted
71    if !args.is_empty() {
72        println!("Command attempted: {}\n", args[0]);
73    }
74
75    if let Err(e) = app.execute(args) {
76        eprintln!("Error: {}", e);
77        std::process::exit(1);
78    }
79}
examples/memory_optimization_demo.rs (lines 170-189)
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/validator_demo.rs (lines 11-15)
4fn main() {
5    let app = CommandBuilder::new("validator-demo")
6        .short("Demonstrates argument validation")
7        .subcommand(
8            CommandBuilder::new("copy")
9                .short("Copy files (requires exactly 2 arguments)")
10                .args(ArgValidator::ExactArgs(2))
11                .run(|ctx| {
12                    let args = ctx.args();
13                    println!("Copying from '{}' to '{}'", args[0], args[1]);
14                    Ok(())
15                })
16                .build(),
17        )
18        .subcommand(
19            CommandBuilder::new("delete")
20                .short("Delete files (requires at least 1 argument)")
21                .args(ArgValidator::MinimumArgs(1))
22                .run(|ctx| {
23                    println!("Deleting {} file(s):", ctx.args().len());
24                    for file in ctx.args() {
25                        println!("  - {}", file);
26                    }
27                    Ok(())
28                })
29                .build(),
30        )
31        .subcommand(
32            CommandBuilder::new("list")
33                .short("List items (accepts 0-3 arguments)")
34                .args(ArgValidator::RangeArgs(0, 3))
35                .run(|ctx| {
36                    if ctx.args().is_empty() {
37                        println!("Listing all items");
38                    } else {
39                        println!("Listing specific items:");
40                        for item in ctx.args() {
41                            println!("  - {}", item);
42                        }
43                    }
44                    Ok(())
45                })
46                .build(),
47        )
48        .subcommand(
49            CommandBuilder::new("action")
50                .short("Perform action (only start/stop/restart allowed)")
51                .args(ArgValidator::OnlyValidArgs(vec![
52                    "start".to_string(),
53                    "stop".to_string(),
54                    "restart".to_string(),
55                ]))
56                .run(|ctx| {
57                    let action = ctx.args().first().map(String::as_str).unwrap_or("start");
58                    println!("Performing action: {}", action);
59                    Ok(())
60                })
61                .build(),
62        )
63        .subcommand(
64            CommandBuilder::new("numbers")
65                .short("Process numbers (custom validator for integers)")
66                .args(ArgValidator::Custom(std::sync::Arc::new(|args| {
67                    if args.is_empty() {
68                        return Err(Error::ArgumentValidation {
69                            message: "at least one number required".to_string(),
70                            expected: "numbers".to_string(),
71                            received: 0,
72                        });
73                    }
74
75                    for (i, arg) in args.iter().enumerate() {
76                        if arg.parse::<i32>().is_err() {
77                            return Err(Error::ArgumentValidation {
78                                message: format!(
79                                    "argument {} ('{}') must be an integer",
80                                    i + 1,
81                                    arg
82                                ),
83                                expected: "integer".to_string(),
84                                received: args.len(),
85                            });
86                        }
87                    }
88                    Ok(())
89                })))
90                .run(|ctx| {
91                    let numbers: Vec<i32> = ctx.args().iter().map(|s| s.parse().unwrap()).collect();
92                    let sum: i32 = numbers.iter().sum();
93                    println!("Sum of {} numbers: {}", numbers.len(), sum);
94                    Ok(())
95                })
96                .build(),
97        )
98        .build();
99
100    let args: Vec<String> = std::env::args().skip(1).collect();
101    if let Err(e) = app.execute(args) {
102        eprintln!("Error: {}", e);
103        std::process::exit(1);
104    }
105}
examples/enhanced_errors_demo.rs (lines 76-79)
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/error_handling_demo.rs (lines 20-30)
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 args(self, validator: ArgValidator) -> Self

Sets the argument validator for this command

The validator will be called before the run function to ensure arguments meet the specified constraints.

§Examples
use flag_rs::{CommandBuilder, ArgValidator};

let cmd = CommandBuilder::new("delete")
    .args(ArgValidator::MinimumArgs(1))
    .run(|ctx| {
        for file in ctx.args() {
            println!("Deleting: {}", file);
        }
        Ok(())
    })
    .build();
Examples found in repository?
examples/validator_demo.rs (line 10)
4fn main() {
5    let app = CommandBuilder::new("validator-demo")
6        .short("Demonstrates argument validation")
7        .subcommand(
8            CommandBuilder::new("copy")
9                .short("Copy files (requires exactly 2 arguments)")
10                .args(ArgValidator::ExactArgs(2))
11                .run(|ctx| {
12                    let args = ctx.args();
13                    println!("Copying from '{}' to '{}'", args[0], args[1]);
14                    Ok(())
15                })
16                .build(),
17        )
18        .subcommand(
19            CommandBuilder::new("delete")
20                .short("Delete files (requires at least 1 argument)")
21                .args(ArgValidator::MinimumArgs(1))
22                .run(|ctx| {
23                    println!("Deleting {} file(s):", ctx.args().len());
24                    for file in ctx.args() {
25                        println!("  - {}", file);
26                    }
27                    Ok(())
28                })
29                .build(),
30        )
31        .subcommand(
32            CommandBuilder::new("list")
33                .short("List items (accepts 0-3 arguments)")
34                .args(ArgValidator::RangeArgs(0, 3))
35                .run(|ctx| {
36                    if ctx.args().is_empty() {
37                        println!("Listing all items");
38                    } else {
39                        println!("Listing specific items:");
40                        for item in ctx.args() {
41                            println!("  - {}", item);
42                        }
43                    }
44                    Ok(())
45                })
46                .build(),
47        )
48        .subcommand(
49            CommandBuilder::new("action")
50                .short("Perform action (only start/stop/restart allowed)")
51                .args(ArgValidator::OnlyValidArgs(vec![
52                    "start".to_string(),
53                    "stop".to_string(),
54                    "restart".to_string(),
55                ]))
56                .run(|ctx| {
57                    let action = ctx.args().first().map(String::as_str).unwrap_or("start");
58                    println!("Performing action: {}", action);
59                    Ok(())
60                })
61                .build(),
62        )
63        .subcommand(
64            CommandBuilder::new("numbers")
65                .short("Process numbers (custom validator for integers)")
66                .args(ArgValidator::Custom(std::sync::Arc::new(|args| {
67                    if args.is_empty() {
68                        return Err(Error::ArgumentValidation {
69                            message: "at least one number required".to_string(),
70                            expected: "numbers".to_string(),
71                            received: 0,
72                        });
73                    }
74
75                    for (i, arg) in args.iter().enumerate() {
76                        if arg.parse::<i32>().is_err() {
77                            return Err(Error::ArgumentValidation {
78                                message: format!(
79                                    "argument {} ('{}') must be an integer",
80                                    i + 1,
81                                    arg
82                                ),
83                                expected: "integer".to_string(),
84                                received: args.len(),
85                            });
86                        }
87                    }
88                    Ok(())
89                })))
90                .run(|ctx| {
91                    let numbers: Vec<i32> = ctx.args().iter().map(|s| s.parse().unwrap()).collect();
92                    let sum: i32 = numbers.iter().sum();
93                    println!("Sum of {} numbers: {}", numbers.len(), sum);
94                    Ok(())
95                })
96                .build(),
97        )
98        .build();
99
100    let args: Vec<String> = std::env::args().skip(1).collect();
101    if let Err(e) = app.execute(args) {
102        eprintln!("Error: {}", e);
103        std::process::exit(1);
104    }
105}
More examples
Hide additional examples
examples/error_handling_demo.rs (line 19)
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 persistent_pre_run<F>(self, f: F) -> Self
where F: Fn(&mut Context) -> Result<()> + Send + Sync + 'static,

Sets the persistent pre-run hook for this command

This hook runs before the command and all its subcommands. It’s inherited by all subcommands and runs in parent-to-child order.

§Examples
use flag_rs::CommandBuilder;

let cmd = CommandBuilder::new("app")
    .persistent_pre_run(|ctx| {
        println!("Setting up logging...");
        Ok(())
    })
    .build();
Examples found in repository?
examples/lifecycle_hooks_demo.rs (lines 28-34)
17fn main() {
18    let app = CommandBuilder::new("lifecycle-demo")
19        .short("Demonstrates lifecycle hooks")
20        .long("This example shows how lifecycle hooks execute in the proper order")
21        .flag(
22            Flag::new("verbose")
23                .short('v')
24                .usage("Enable verbose output")
25                .value_type(FlagType::Bool),
26        )
27        // Persistent hooks run for this command and all subcommands
28        .persistent_pre_run(|ctx| {
29            log_hook("Root PersistentPreRun");
30            if ctx.flag("verbose").is_some() {
31                println!("     -> Verbose mode enabled globally");
32            }
33            Ok(())
34        })
35        .persistent_post_run(|ctx| {
36            log_hook("Root PersistentPostRun");
37            if ctx.flag("verbose").is_some() {
38                println!("     -> Cleaning up verbose logging");
39            }
40            Ok(())
41        })
42        .subcommand(
43            CommandBuilder::new("server")
44                .short("Server management commands")
45                .persistent_pre_run(|_ctx| {
46                    log_hook("Server PersistentPreRun");
47                    println!("     -> Initializing server module");
48                    Ok(())
49                })
50                .persistent_post_run(|_ctx| {
51                    log_hook("Server PersistentPostRun");
52                    println!("     -> Cleaning up server module");
53                    Ok(())
54                })
55                .subcommand(
56                    CommandBuilder::new("start")
57                        .short("Start the server")
58                        .flag(
59                            Flag::new("port")
60                                .short('p')
61                                .usage("Port to listen on")
62                                .value_type(FlagType::Int),
63                        )
64                        .pre_run(|ctx| {
65                            log_hook("Start PreRun");
66                            let port = ctx
67                                .flag("port")
68                                .and_then(|s| s.parse::<u16>().ok())
69                                .unwrap_or(8080);
70                            println!("     -> Validating port {}", port);
71                            Ok(())
72                        })
73                        .run(|ctx| {
74                            log_hook("Start Run");
75                            let port = ctx
76                                .flag("port")
77                                .and_then(|s| s.parse::<u16>().ok())
78                                .unwrap_or(8080);
79                            println!("     -> Starting server on port {}", port);
80                            Ok(())
81                        })
82                        .post_run(|_ctx| {
83                            log_hook("Start PostRun");
84                            println!("     -> Server started successfully");
85                            Ok(())
86                        })
87                        .build(),
88                )
89                .subcommand(
90                    CommandBuilder::new("stop")
91                        .short("Stop the server")
92                        .pre_run(|_ctx| {
93                            log_hook("Stop PreRun");
94                            println!("     -> Checking if server is running");
95                            Ok(())
96                        })
97                        .run(|_ctx| {
98                            log_hook("Stop Run");
99                            println!("     -> Stopping server");
100                            Ok(())
101                        })
102                        .post_run(|_ctx| {
103                            log_hook("Stop PostRun");
104                            println!("     -> Server stopped");
105                            Ok(())
106                        })
107                        .build(),
108                )
109                .build(),
110        )
111        .subcommand(
112            CommandBuilder::new("database")
113                .short("Database management commands")
114                .persistent_pre_run(|_ctx| {
115                    log_hook("Database PersistentPreRun");
116                    println!("     -> Connecting to database");
117                    Ok(())
118                })
119                .persistent_post_run(|_ctx| {
120                    log_hook("Database PersistentPostRun");
121                    println!("     -> Closing database connection");
122                    Ok(())
123                })
124                .subcommand(
125                    CommandBuilder::new("migrate")
126                        .short("Run database migrations")
127                        .pre_run(|_ctx| {
128                            log_hook("Migrate PreRun");
129                            println!("     -> Checking migration status");
130                            Ok(())
131                        })
132                        .run(|_ctx| {
133                            log_hook("Migrate Run");
134                            println!("     -> Running migrations");
135                            Ok(())
136                        })
137                        .post_run(|_ctx| {
138                            log_hook("Migrate PostRun");
139                            println!("     -> Migrations completed");
140                            Ok(())
141                        })
142                        .build(),
143                )
144                .build(),
145        )
146        .build();
147
148    println!("=== Lifecycle Hooks Demo ===\n");
149    println!("This demo shows the execution order of lifecycle hooks.");
150    println!("Try these commands to see different hook patterns:\n");
151    println!(
152        "1. {} server start",
153        std::env::args().next().unwrap_or_default()
154    );
155    println!(
156        "2. {} -v server start -p 3000",
157        std::env::args().next().unwrap_or_default()
158    );
159    println!(
160        "3. {} database migrate",
161        std::env::args().next().unwrap_or_default()
162    );
163    println!("\n---\n");
164
165    // Reset counter before execution
166    COUNTER.store(0, Ordering::SeqCst);
167
168    let args: Vec<String> = std::env::args().skip(1).collect();
169    if let Err(e) = app.execute(args) {
170        eprintln!("Error: {}", e);
171        std::process::exit(1);
172    }
173
174    println!("\n=== Hook Execution Summary ===");
175    println!("Total hooks executed: {}", COUNTER.load(Ordering::SeqCst));
176    println!("\nExecution order:");
177    println!("1. Parent PersistentPreRun (root → child)");
178    println!("2. Command PreRun");
179    println!("3. Command Run");
180    println!("4. Command PostRun");
181    println!("5. Parent PersistentPostRun (child → root)");
182}
Source

pub fn pre_run<F>(self, f: F) -> Self
where F: Fn(&mut Context) -> Result<()> + Send + Sync + 'static,

Sets the pre-run hook for this command

This hook runs only for this specific command, after any persistent pre-run hooks but before the main run function.

§Examples
use flag_rs::CommandBuilder;

let cmd = CommandBuilder::new("deploy")
    .pre_run(|ctx| {
        println!("Validating deployment configuration...");
        Ok(())
    })
    .run(|ctx| {
        println!("Deploying application...");
        Ok(())
    })
    .build();
Examples found in repository?
examples/lifecycle_hooks_demo.rs (lines 64-72)
17fn main() {
18    let app = CommandBuilder::new("lifecycle-demo")
19        .short("Demonstrates lifecycle hooks")
20        .long("This example shows how lifecycle hooks execute in the proper order")
21        .flag(
22            Flag::new("verbose")
23                .short('v')
24                .usage("Enable verbose output")
25                .value_type(FlagType::Bool),
26        )
27        // Persistent hooks run for this command and all subcommands
28        .persistent_pre_run(|ctx| {
29            log_hook("Root PersistentPreRun");
30            if ctx.flag("verbose").is_some() {
31                println!("     -> Verbose mode enabled globally");
32            }
33            Ok(())
34        })
35        .persistent_post_run(|ctx| {
36            log_hook("Root PersistentPostRun");
37            if ctx.flag("verbose").is_some() {
38                println!("     -> Cleaning up verbose logging");
39            }
40            Ok(())
41        })
42        .subcommand(
43            CommandBuilder::new("server")
44                .short("Server management commands")
45                .persistent_pre_run(|_ctx| {
46                    log_hook("Server PersistentPreRun");
47                    println!("     -> Initializing server module");
48                    Ok(())
49                })
50                .persistent_post_run(|_ctx| {
51                    log_hook("Server PersistentPostRun");
52                    println!("     -> Cleaning up server module");
53                    Ok(())
54                })
55                .subcommand(
56                    CommandBuilder::new("start")
57                        .short("Start the server")
58                        .flag(
59                            Flag::new("port")
60                                .short('p')
61                                .usage("Port to listen on")
62                                .value_type(FlagType::Int),
63                        )
64                        .pre_run(|ctx| {
65                            log_hook("Start PreRun");
66                            let port = ctx
67                                .flag("port")
68                                .and_then(|s| s.parse::<u16>().ok())
69                                .unwrap_or(8080);
70                            println!("     -> Validating port {}", port);
71                            Ok(())
72                        })
73                        .run(|ctx| {
74                            log_hook("Start Run");
75                            let port = ctx
76                                .flag("port")
77                                .and_then(|s| s.parse::<u16>().ok())
78                                .unwrap_or(8080);
79                            println!("     -> Starting server on port {}", port);
80                            Ok(())
81                        })
82                        .post_run(|_ctx| {
83                            log_hook("Start PostRun");
84                            println!("     -> Server started successfully");
85                            Ok(())
86                        })
87                        .build(),
88                )
89                .subcommand(
90                    CommandBuilder::new("stop")
91                        .short("Stop the server")
92                        .pre_run(|_ctx| {
93                            log_hook("Stop PreRun");
94                            println!("     -> Checking if server is running");
95                            Ok(())
96                        })
97                        .run(|_ctx| {
98                            log_hook("Stop Run");
99                            println!("     -> Stopping server");
100                            Ok(())
101                        })
102                        .post_run(|_ctx| {
103                            log_hook("Stop PostRun");
104                            println!("     -> Server stopped");
105                            Ok(())
106                        })
107                        .build(),
108                )
109                .build(),
110        )
111        .subcommand(
112            CommandBuilder::new("database")
113                .short("Database management commands")
114                .persistent_pre_run(|_ctx| {
115                    log_hook("Database PersistentPreRun");
116                    println!("     -> Connecting to database");
117                    Ok(())
118                })
119                .persistent_post_run(|_ctx| {
120                    log_hook("Database PersistentPostRun");
121                    println!("     -> Closing database connection");
122                    Ok(())
123                })
124                .subcommand(
125                    CommandBuilder::new("migrate")
126                        .short("Run database migrations")
127                        .pre_run(|_ctx| {
128                            log_hook("Migrate PreRun");
129                            println!("     -> Checking migration status");
130                            Ok(())
131                        })
132                        .run(|_ctx| {
133                            log_hook("Migrate Run");
134                            println!("     -> Running migrations");
135                            Ok(())
136                        })
137                        .post_run(|_ctx| {
138                            log_hook("Migrate PostRun");
139                            println!("     -> Migrations completed");
140                            Ok(())
141                        })
142                        .build(),
143                )
144                .build(),
145        )
146        .build();
147
148    println!("=== Lifecycle Hooks Demo ===\n");
149    println!("This demo shows the execution order of lifecycle hooks.");
150    println!("Try these commands to see different hook patterns:\n");
151    println!(
152        "1. {} server start",
153        std::env::args().next().unwrap_or_default()
154    );
155    println!(
156        "2. {} -v server start -p 3000",
157        std::env::args().next().unwrap_or_default()
158    );
159    println!(
160        "3. {} database migrate",
161        std::env::args().next().unwrap_or_default()
162    );
163    println!("\n---\n");
164
165    // Reset counter before execution
166    COUNTER.store(0, Ordering::SeqCst);
167
168    let args: Vec<String> = std::env::args().skip(1).collect();
169    if let Err(e) = app.execute(args) {
170        eprintln!("Error: {}", e);
171        std::process::exit(1);
172    }
173
174    println!("\n=== Hook Execution Summary ===");
175    println!("Total hooks executed: {}", COUNTER.load(Ordering::SeqCst));
176    println!("\nExecution order:");
177    println!("1. Parent PersistentPreRun (root → child)");
178    println!("2. Command PreRun");
179    println!("3. Command Run");
180    println!("4. Command PostRun");
181    println!("5. Parent PersistentPostRun (child → root)");
182}
Source

pub fn post_run<F>(self, f: F) -> Self
where F: Fn(&mut Context) -> Result<()> + Send + Sync + 'static,

Sets the post-run hook for this command

This hook runs only for this specific command, after the main run function but before any persistent post-run hooks.

§Examples
use flag_rs::CommandBuilder;

let cmd = CommandBuilder::new("test")
    .run(|ctx| {
        println!("Running tests...");
        Ok(())
    })
    .post_run(|ctx| {
        println!("Generating test report...");
        Ok(())
    })
    .build();
Examples found in repository?
examples/lifecycle_hooks_demo.rs (lines 82-86)
17fn main() {
18    let app = CommandBuilder::new("lifecycle-demo")
19        .short("Demonstrates lifecycle hooks")
20        .long("This example shows how lifecycle hooks execute in the proper order")
21        .flag(
22            Flag::new("verbose")
23                .short('v')
24                .usage("Enable verbose output")
25                .value_type(FlagType::Bool),
26        )
27        // Persistent hooks run for this command and all subcommands
28        .persistent_pre_run(|ctx| {
29            log_hook("Root PersistentPreRun");
30            if ctx.flag("verbose").is_some() {
31                println!("     -> Verbose mode enabled globally");
32            }
33            Ok(())
34        })
35        .persistent_post_run(|ctx| {
36            log_hook("Root PersistentPostRun");
37            if ctx.flag("verbose").is_some() {
38                println!("     -> Cleaning up verbose logging");
39            }
40            Ok(())
41        })
42        .subcommand(
43            CommandBuilder::new("server")
44                .short("Server management commands")
45                .persistent_pre_run(|_ctx| {
46                    log_hook("Server PersistentPreRun");
47                    println!("     -> Initializing server module");
48                    Ok(())
49                })
50                .persistent_post_run(|_ctx| {
51                    log_hook("Server PersistentPostRun");
52                    println!("     -> Cleaning up server module");
53                    Ok(())
54                })
55                .subcommand(
56                    CommandBuilder::new("start")
57                        .short("Start the server")
58                        .flag(
59                            Flag::new("port")
60                                .short('p')
61                                .usage("Port to listen on")
62                                .value_type(FlagType::Int),
63                        )
64                        .pre_run(|ctx| {
65                            log_hook("Start PreRun");
66                            let port = ctx
67                                .flag("port")
68                                .and_then(|s| s.parse::<u16>().ok())
69                                .unwrap_or(8080);
70                            println!("     -> Validating port {}", port);
71                            Ok(())
72                        })
73                        .run(|ctx| {
74                            log_hook("Start Run");
75                            let port = ctx
76                                .flag("port")
77                                .and_then(|s| s.parse::<u16>().ok())
78                                .unwrap_or(8080);
79                            println!("     -> Starting server on port {}", port);
80                            Ok(())
81                        })
82                        .post_run(|_ctx| {
83                            log_hook("Start PostRun");
84                            println!("     -> Server started successfully");
85                            Ok(())
86                        })
87                        .build(),
88                )
89                .subcommand(
90                    CommandBuilder::new("stop")
91                        .short("Stop the server")
92                        .pre_run(|_ctx| {
93                            log_hook("Stop PreRun");
94                            println!("     -> Checking if server is running");
95                            Ok(())
96                        })
97                        .run(|_ctx| {
98                            log_hook("Stop Run");
99                            println!("     -> Stopping server");
100                            Ok(())
101                        })
102                        .post_run(|_ctx| {
103                            log_hook("Stop PostRun");
104                            println!("     -> Server stopped");
105                            Ok(())
106                        })
107                        .build(),
108                )
109                .build(),
110        )
111        .subcommand(
112            CommandBuilder::new("database")
113                .short("Database management commands")
114                .persistent_pre_run(|_ctx| {
115                    log_hook("Database PersistentPreRun");
116                    println!("     -> Connecting to database");
117                    Ok(())
118                })
119                .persistent_post_run(|_ctx| {
120                    log_hook("Database PersistentPostRun");
121                    println!("     -> Closing database connection");
122                    Ok(())
123                })
124                .subcommand(
125                    CommandBuilder::new("migrate")
126                        .short("Run database migrations")
127                        .pre_run(|_ctx| {
128                            log_hook("Migrate PreRun");
129                            println!("     -> Checking migration status");
130                            Ok(())
131                        })
132                        .run(|_ctx| {
133                            log_hook("Migrate Run");
134                            println!("     -> Running migrations");
135                            Ok(())
136                        })
137                        .post_run(|_ctx| {
138                            log_hook("Migrate PostRun");
139                            println!("     -> Migrations completed");
140                            Ok(())
141                        })
142                        .build(),
143                )
144                .build(),
145        )
146        .build();
147
148    println!("=== Lifecycle Hooks Demo ===\n");
149    println!("This demo shows the execution order of lifecycle hooks.");
150    println!("Try these commands to see different hook patterns:\n");
151    println!(
152        "1. {} server start",
153        std::env::args().next().unwrap_or_default()
154    );
155    println!(
156        "2. {} -v server start -p 3000",
157        std::env::args().next().unwrap_or_default()
158    );
159    println!(
160        "3. {} database migrate",
161        std::env::args().next().unwrap_or_default()
162    );
163    println!("\n---\n");
164
165    // Reset counter before execution
166    COUNTER.store(0, Ordering::SeqCst);
167
168    let args: Vec<String> = std::env::args().skip(1).collect();
169    if let Err(e) = app.execute(args) {
170        eprintln!("Error: {}", e);
171        std::process::exit(1);
172    }
173
174    println!("\n=== Hook Execution Summary ===");
175    println!("Total hooks executed: {}", COUNTER.load(Ordering::SeqCst));
176    println!("\nExecution order:");
177    println!("1. Parent PersistentPreRun (root → child)");
178    println!("2. Command PreRun");
179    println!("3. Command Run");
180    println!("4. Command PostRun");
181    println!("5. Parent PersistentPostRun (child → root)");
182}
Source

pub fn persistent_post_run<F>(self, f: F) -> Self
where F: Fn(&mut Context) -> Result<()> + Send + Sync + 'static,

Sets the persistent post-run hook for this command

This hook runs after the command and all its subcommands. It’s inherited by all subcommands and runs in child-to-parent order.

§Examples
use flag_rs::CommandBuilder;

let cmd = CommandBuilder::new("app")
    .persistent_post_run(|ctx| {
        println!("Cleaning up resources...");
        Ok(())
    })
    .build();
Examples found in repository?
examples/lifecycle_hooks_demo.rs (lines 35-41)
17fn main() {
18    let app = CommandBuilder::new("lifecycle-demo")
19        .short("Demonstrates lifecycle hooks")
20        .long("This example shows how lifecycle hooks execute in the proper order")
21        .flag(
22            Flag::new("verbose")
23                .short('v')
24                .usage("Enable verbose output")
25                .value_type(FlagType::Bool),
26        )
27        // Persistent hooks run for this command and all subcommands
28        .persistent_pre_run(|ctx| {
29            log_hook("Root PersistentPreRun");
30            if ctx.flag("verbose").is_some() {
31                println!("     -> Verbose mode enabled globally");
32            }
33            Ok(())
34        })
35        .persistent_post_run(|ctx| {
36            log_hook("Root PersistentPostRun");
37            if ctx.flag("verbose").is_some() {
38                println!("     -> Cleaning up verbose logging");
39            }
40            Ok(())
41        })
42        .subcommand(
43            CommandBuilder::new("server")
44                .short("Server management commands")
45                .persistent_pre_run(|_ctx| {
46                    log_hook("Server PersistentPreRun");
47                    println!("     -> Initializing server module");
48                    Ok(())
49                })
50                .persistent_post_run(|_ctx| {
51                    log_hook("Server PersistentPostRun");
52                    println!("     -> Cleaning up server module");
53                    Ok(())
54                })
55                .subcommand(
56                    CommandBuilder::new("start")
57                        .short("Start the server")
58                        .flag(
59                            Flag::new("port")
60                                .short('p')
61                                .usage("Port to listen on")
62                                .value_type(FlagType::Int),
63                        )
64                        .pre_run(|ctx| {
65                            log_hook("Start PreRun");
66                            let port = ctx
67                                .flag("port")
68                                .and_then(|s| s.parse::<u16>().ok())
69                                .unwrap_or(8080);
70                            println!("     -> Validating port {}", port);
71                            Ok(())
72                        })
73                        .run(|ctx| {
74                            log_hook("Start Run");
75                            let port = ctx
76                                .flag("port")
77                                .and_then(|s| s.parse::<u16>().ok())
78                                .unwrap_or(8080);
79                            println!("     -> Starting server on port {}", port);
80                            Ok(())
81                        })
82                        .post_run(|_ctx| {
83                            log_hook("Start PostRun");
84                            println!("     -> Server started successfully");
85                            Ok(())
86                        })
87                        .build(),
88                )
89                .subcommand(
90                    CommandBuilder::new("stop")
91                        .short("Stop the server")
92                        .pre_run(|_ctx| {
93                            log_hook("Stop PreRun");
94                            println!("     -> Checking if server is running");
95                            Ok(())
96                        })
97                        .run(|_ctx| {
98                            log_hook("Stop Run");
99                            println!("     -> Stopping server");
100                            Ok(())
101                        })
102                        .post_run(|_ctx| {
103                            log_hook("Stop PostRun");
104                            println!("     -> Server stopped");
105                            Ok(())
106                        })
107                        .build(),
108                )
109                .build(),
110        )
111        .subcommand(
112            CommandBuilder::new("database")
113                .short("Database management commands")
114                .persistent_pre_run(|_ctx| {
115                    log_hook("Database PersistentPreRun");
116                    println!("     -> Connecting to database");
117                    Ok(())
118                })
119                .persistent_post_run(|_ctx| {
120                    log_hook("Database PersistentPostRun");
121                    println!("     -> Closing database connection");
122                    Ok(())
123                })
124                .subcommand(
125                    CommandBuilder::new("migrate")
126                        .short("Run database migrations")
127                        .pre_run(|_ctx| {
128                            log_hook("Migrate PreRun");
129                            println!("     -> Checking migration status");
130                            Ok(())
131                        })
132                        .run(|_ctx| {
133                            log_hook("Migrate Run");
134                            println!("     -> Running migrations");
135                            Ok(())
136                        })
137                        .post_run(|_ctx| {
138                            log_hook("Migrate PostRun");
139                            println!("     -> Migrations completed");
140                            Ok(())
141                        })
142                        .build(),
143                )
144                .build(),
145        )
146        .build();
147
148    println!("=== Lifecycle Hooks Demo ===\n");
149    println!("This demo shows the execution order of lifecycle hooks.");
150    println!("Try these commands to see different hook patterns:\n");
151    println!(
152        "1. {} server start",
153        std::env::args().next().unwrap_or_default()
154    );
155    println!(
156        "2. {} -v server start -p 3000",
157        std::env::args().next().unwrap_or_default()
158    );
159    println!(
160        "3. {} database migrate",
161        std::env::args().next().unwrap_or_default()
162    );
163    println!("\n---\n");
164
165    // Reset counter before execution
166    COUNTER.store(0, Ordering::SeqCst);
167
168    let args: Vec<String> = std::env::args().skip(1).collect();
169    if let Err(e) = app.execute(args) {
170        eprintln!("Error: {}", e);
171        std::process::exit(1);
172    }
173
174    println!("\n=== Hook Execution Summary ===");
175    println!("Total hooks executed: {}", COUNTER.load(Ordering::SeqCst));
176    println!("\nExecution order:");
177    println!("1. Parent PersistentPreRun (root → child)");
178    println!("2. Command PreRun");
179    println!("3. Command Run");
180    println!("4. Command PostRun");
181    println!("5. Parent PersistentPostRun (child → root)");
182}
Source

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

Sets the argument completion function

This function is called when the user presses TAB to complete arguments. It enables dynamic completions based on runtime state.

§Examples
use flag_rs::{CommandBuilder, CompletionResult};

let cmd = CommandBuilder::new("edit")
    .arg_completion(|ctx, prefix| {
        // In a real app, list files from the filesystem
        let files = vec!["main.rs", "lib.rs", "Cargo.toml"];
        Ok(CompletionResult::new().extend(
            files.into_iter()
                .filter(|f| f.starts_with(prefix))
                .map(String::from)
        ))
    })
    .build();
Examples found in repository?
examples/kubectl.rs (lines 83-101)
79fn build_get_pods() -> Command {
80    CommandBuilder::new("pods")
81        .aliases(vec!["po", "pod"])
82        .short("List pods")
83        .arg_completion(|ctx, prefix| {
84            // This is the key feature - dynamic completion based on runtime state!
85            let namespace = ctx
86                .flag("namespace")
87                .map(String::as_str)
88                .unwrap_or("default");
89
90            // In real kubectl, this would query the K8s API
91            let pods = get_pods_with_status(namespace);
92            let mut result = CompletionResult::new();
93
94            for (pod_name, status) in pods {
95                if pod_name.starts_with(prefix) {
96                    result = result.add_with_description(pod_name, status);
97                }
98            }
99
100            Ok(result)
101        })
102        .run(|ctx| {
103            let namespace = ctx
104                .flag("namespace")
105                .map(String::as_str)
106                .unwrap_or("default");
107
108            println!("Listing pods in namespace: {namespace}");
109
110            if let Some(pod_name) = ctx.args().first() {
111                println!("Getting specific pod: {pod_name}");
112            } else {
113                for pod in get_pods_in_namespace(namespace) {
114                    println!("pod/{}", pod);
115                }
116            }
117
118            Ok(())
119        })
120        .build()
121}
122
123fn build_get_services() -> Command {
124    CommandBuilder::new("services")
125        .aliases(vec!["svc", "service"])
126        .short("List services")
127        .arg_completion(|ctx, prefix| {
128            let namespace = ctx
129                .flag("namespace")
130                .map(String::as_str)
131                .unwrap_or("default");
132
133            let services = get_services_in_namespace(namespace);
134            Ok(CompletionResult::new()
135                .extend(services.into_iter().filter(|svc| svc.starts_with(prefix))))
136        })
137        .run(|ctx| {
138            let namespace = ctx
139                .flag("namespace")
140                .map(String::as_str)
141                .unwrap_or("default");
142
143            println!("Listing services in namespace: {namespace}");
144            Ok(())
145        })
146        .build()
147}
148
149fn build_get_deployments() -> Command {
150    CommandBuilder::new("deployments")
151        .aliases(vec!["deploy", "deployment"])
152        .short("List deployments")
153        .run(|ctx| {
154            let namespace = ctx
155                .flag("namespace")
156                .map(String::as_str)
157                .unwrap_or("default");
158
159            println!("Listing deployments in namespace: {namespace}");
160            Ok(())
161        })
162        .build()
163}
164
165fn build_describe_command() -> Command {
166    CommandBuilder::new("describe")
167        .short("Show details of a specific resource")
168        .run(|_ctx| {
169            println!("Describe command - add resource type subcommands");
170            Ok(())
171        })
172        .build()
173}
174
175fn build_delete_command() -> Command {
176    CommandBuilder::new("delete")
177        .short("Delete resources")
178        .run(|_ctx| {
179            println!("Delete command - add resource type subcommands");
180            Ok(())
181        })
182        .build()
183}
184
185// Mock functions that would normally query the Kubernetes API
186fn get_namespaces_with_descriptions() -> Vec<(String, String)> {
187    vec![
188        (
189            "default".to_string(),
190            "Default namespace for user workloads".to_string(),
191        ),
192        (
193            "kube-system".to_string(),
194            "Kubernetes system components".to_string(),
195        ),
196        (
197            "kube-public".to_string(),
198            "Public resources accessible to all users".to_string(),
199        ),
200        (
201            "development".to_string(),
202            "Development environment".to_string(),
203        ),
204        (
205            "staging".to_string(),
206            "Staging environment for pre-production testing".to_string(),
207        ),
208        (
209            "production".to_string(),
210            "Production environment (CAUTION)".to_string(),
211        ),
212    ]
213}
214
215fn get_pods_with_status(namespace: &str) -> Vec<(String, String)> {
216    use std::time::{SystemTime, UNIX_EPOCH};
217
218    // Generate random suffix based on current time
219    let timestamp = SystemTime::now()
220        .duration_since(UNIX_EPOCH)
221        .unwrap()
222        .as_secs();
223
224    // Simple pseudo-random generation
225    let rand1 = ((timestamp * 1_103_515_245 + 12345) / 65536) % 100_000;
226    let rand2 = ((rand1 * 1_103_515_245 + 12345) / 65536) % 100_000;
227    let rand3 = ((rand2 * 1_103_515_245 + 12345) / 65536) % 100_000;
228
229    match namespace {
230        "default" => vec![
231            (
232                format!("nginx-deployment-7fb96c846b-{:05x}", rand1),
233                "Running (2/2 containers)".to_string(),
234            ),
235            (
236                format!("nginx-deployment-7fb96c846b-{:05x}", rand2),
237                "Running (2/2 containers)".to_string(),
238            ),
239            (
240                "redis-master-0".to_string(),
241                "Running (1/1 containers)".to_string(),
242            ),
243            (
244                "redis-slave-0".to_string(),
245                "Running (1/1 containers)".to_string(),
246            ),
247            ("redis-slave-1".to_string(), "Pending".to_string()),
248        ],
249        "kube-system" => vec![
250            (
251                format!("coredns-5d78c9869d-{:05x}", rand1),
252                "Running (1/1 containers)".to_string(),
253            ),
254            (
255                format!("coredns-5d78c9869d-{:05x}", rand2),
256                "Running (1/1 containers)".to_string(),
257            ),
258            ("etcd-minikube".to_string(), "Running".to_string()),
259            ("kube-apiserver-minikube".to_string(), "Running".to_string()),
260            (
261                "kube-controller-manager-minikube".to_string(),
262                "Running".to_string(),
263            ),
264            (format!("kube-proxy-{:05x}", rand3), "Running".to_string()),
265            ("kube-scheduler-minikube".to_string(), "Running".to_string()),
266        ],
267        _ => vec![],
268    }
269}
270
271fn get_pods_in_namespace(namespace: &str) -> Vec<String> {
272    use std::time::{SystemTime, UNIX_EPOCH};
273
274    // Generate random suffix based on current time
275    let timestamp = SystemTime::now()
276        .duration_since(UNIX_EPOCH)
277        .unwrap()
278        .as_secs();
279
280    // Simple pseudo-random generation
281    let rand1 = ((timestamp * 1_103_515_245 + 12345) / 65536) % 100_000;
282    let rand2 = ((rand1 * 1_103_515_245 + 12345) / 65536) % 100_000;
283    let rand3 = ((rand2 * 1_103_515_245 + 12345) / 65536) % 100_000;
284
285    match namespace {
286        "default" => vec![
287            format!("nginx-deployment-7fb96c846b-{:05x}", rand1),
288            format!("nginx-deployment-7fb96c846b-{:05x}", rand2),
289            format!("redis-master-0"),
290            format!("redis-slave-0"),
291            format!("redis-slave-1"),
292        ],
293        "kube-system" => vec![
294            format!("coredns-5d78c9869d-{:05x}", rand1),
295            format!("coredns-5d78c9869d-{:05x}", rand2),
296            format!("etcd-minikube"),
297            format!("kube-apiserver-minikube"),
298            format!("kube-controller-manager-minikube"),
299            format!("kube-proxy-{:05x}", rand3),
300            format!("kube-scheduler-minikube"),
301        ],
302        _ => vec![],
303    }
304}
305
306fn get_services_in_namespace(namespace: &str) -> Vec<String> {
307    match namespace {
308        "default" => vec![
309            "kubernetes".to_string(),
310            "nginx-service".to_string(),
311            "redis-master".to_string(),
312            "redis-slave".to_string(),
313        ],
314        "kube-system" => vec!["kube-dns".to_string()],
315        _ => vec![],
316    }
317}
318
319fn build_completion_command() -> Command {
320    CommandBuilder::new("completion")
321        .short("Generate shell completion scripts")
322        .long("Generate shell completion scripts for kubectl")
323        .arg_completion(|_ctx, prefix| {
324            let shells = vec![
325                ("bash", "Bash shell completion"),
326                ("zsh", "Zsh shell completion"),
327                ("fish", "Fish shell completion"),
328            ];
329
330            let mut result = CompletionResult::new();
331            for (shell, description) in shells {
332                if shell.starts_with(prefix) {
333                    result =
334                        result.add_with_description(shell.to_string(), description.to_string());
335                }
336            }
337
338            Ok(result)
339        })
340        .run(|ctx| {
341            let shell_name = ctx.args().first().ok_or_else(|| {
342                flag_rs::Error::ArgumentParsing(
343                    "shell name required (bash, zsh, or fish)".to_string(),
344                )
345            })?;
346
347            let shell = match shell_name.as_str() {
348                "bash" => Shell::Bash,
349                "zsh" => Shell::Zsh,
350                "fish" => Shell::Fish,
351                _ => {
352                    return Err(flag_rs::Error::ArgumentParsing(format!(
353                        "unsupported shell: {}",
354                        shell_name
355                    )));
356                }
357            };
358
359            // In a real app, you'd get the root command from a shared reference
360            // For this example, we'll recreate it
361            let root = build_kubectl();
362            println!("{}", root.generate_completion(shell));
363
364            Ok(())
365        })
366        .build()
367}
More examples
Hide additional examples
examples/benchmark.rs (lines 204-210)
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}
examples/memory_optimization_demo.rs (lines 57-78)
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/timeout_completion_demo.rs (lines 46-63)
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/cached_completion_demo.rs (lines 59-105)
38fn main() {
39    // Create a shared cache with 10-second TTL
40    let cache = Arc::new(CompletionCache::new(Duration::from_secs(10)));
41
42    let app = CommandBuilder::new("kubectl")
43        .short("Kubernetes command-line tool with cached completions")
44        .flag(
45            Flag::new("namespace")
46                .short('n')
47                .usage("The namespace scope for this CLI request")
48                .value_type(FlagType::String)
49                .default(flag_rs::FlagValue::String("default".to_string())),
50        )
51        .subcommand({
52            let cache_clone = Arc::clone(&cache);
53            CommandBuilder::new("get")
54                .short("Display one or many resources")
55                .subcommand({
56                    let cache_for_pods = Arc::clone(&cache_clone);
57                    CommandBuilder::new("pods")
58                        .short("List pods with cached completion")
59                        .arg_completion(move |ctx, prefix| {
60                            let start = Instant::now();
61
62                            // Generate cache key
63                            let cache_key = CompletionCache::make_key(
64                                &["kubectl".to_string(), "get".to_string(), "pods".to_string()],
65                                prefix,
66                                ctx.flags(),
67                            );
68
69                            // Try to get from cache first
70                            if let Some(cached_result) = cache_for_pods.get(&cache_key) {
71                                eprintln!("✓ Cache hit! Completed in {:?}", start.elapsed());
72                                return Ok(cached_result);
73                            }
74
75                            eprintln!("✗ Cache miss - fetching completions...");
76
77                            // Perform expensive operation
78                            let items = expensive_completion(prefix);
79                            let mut result = CompletionResult::new();
80
81                            for item in items {
82                                result = result.add_with_description(
83                                    item.clone(),
84                                    format!(
85                                        "Pod in namespace {}",
86                                        ctx.flag("namespace").unwrap_or(&"default".to_string())
87                                    ),
88                                );
89                            }
90
91                            // Add contextual help
92                            if prefix.is_empty() {
93                                result =
94                                    result.add_help_text("Tip: Start typing to filter pod names");
95                            }
96
97                            // Cache the result
98                            cache_for_pods.put(cache_key, result.clone());
99
100                            eprintln!(
101                                "✓ Completed in {:?} (cached for future use)",
102                                start.elapsed()
103                            );
104                            Ok(result)
105                        })
106                        .build()
107                })
108                .subcommand({
109                    let cache_for_services = Arc::clone(&cache_clone);
110                    CommandBuilder::new("services")
111                        .short("List services with cached completion")
112                        .arg_completion(move |ctx, prefix| {
113                            let cache_key = CompletionCache::make_key(
114                                &[
115                                    "kubectl".to_string(),
116                                    "get".to_string(),
117                                    "services".to_string(),
118                                ],
119                                prefix,
120                                ctx.flags(),
121                            );
122
123                            if let Some(cached) = cache_for_services.get(&cache_key) {
124                                eprintln!("✓ Using cached service completions");
125                                return Ok(cached);
126                            }
127
128                            // Simulate expensive operation
129                            let services = expensive_completion(prefix);
130                            let result = CompletionResult::new().extend(services);
131
132                            cache_for_services.put(cache_key, result.clone());
133                            Ok(result)
134                        })
135                        .build()
136                })
137                .build()
138        })
139        .build();
140
141    println!("=== Cached Completion Demo ===\n");
142    println!("This demo shows how completion caching improves performance.\n");
143    println!("To test completions with caching:");
144    println!("1. Set up bash completion:");
145    println!(
146        "   source <({} completion bash)",
147        std::env::args().next().unwrap_or_default()
148    );
149    println!();
150    println!("2. Try tab completion multiple times:");
151    println!(
152        "   {} get pods n<TAB>     # First time: ~500ms (cache miss)",
153        std::env::args().next().unwrap_or_default()
154    );
155    println!(
156        "   {} get pods n<TAB>     # Second time: <1ms (cache hit!)",
157        std::env::args().next().unwrap_or_default()
158    );
159    println!();
160    println!("3. Different prefixes have separate cache entries:");
161    println!(
162        "   {} get pods r<TAB>     # Different prefix = cache miss",
163        std::env::args().next().unwrap_or_default()
164    );
165    println!();
166    println!("4. Flags affect the cache key:");
167    println!(
168        "   {} -n prod get pods n<TAB>  # Different namespace = different cache",
169        std::env::args().next().unwrap_or_default()
170    );
171    println!();
172    println!("Note: Cache entries expire after 10 seconds in this demo.\n");
173    println!("---\n");
174
175    let args: Vec<String> = std::env::args().skip(1).collect();
176
177    // Handle completion requests
178    if std::env::var("KUBECTL_COMPLETE").is_ok() {
179        // When testing completions, show cache status
180        eprintln!("Cache size: {} entries", cache.size());
181    }
182
183    if let Err(e) = app.execute(args) {
184        eprintln!("{}", e);
185        std::process::exit(1);
186    }
187}
examples/active_help_demo.rs (lines 30-85)
8fn main() {
9    let app = CommandBuilder::new("active-help-demo")
10        .short("Demonstrates ActiveHelp system")
11        .long("This example shows how ActiveHelp provides contextual hints during tab completion")
12        .flag(
13            Flag::new("namespace")
14                .short('n')
15                .usage("Kubernetes namespace")
16                .value_type(FlagType::String),
17        )
18        .flag(
19            Flag::new("output")
20                .short('o')
21                .usage("Output format")
22                .value_type(FlagType::String),
23        )
24        .subcommand(
25            CommandBuilder::new("get")
26                .short("Get resources")
27                .subcommand(
28                    CommandBuilder::new("pods")
29                        .short("Get pods")
30                        .arg_completion(|ctx, prefix| {
31                            let mut result = CompletionResult::new();
32
33                            // Add contextual help based on current state
34                            if ctx.flag("namespace").is_none() {
35                                result = result.add_help_text(
36                                    "Tip: Use -n <namespace> to list pods from a specific namespace",
37                                );
38                            }
39
40                            if ctx.flag("output").is_none() {
41                                result = result.add_conditional_help(
42                                    "Use -o json for machine-readable output",
43                                    |_| true, // Always show this tip
44                                );
45                            }
46
47                            // Simulate pod completions
48                            let namespace = ctx
49                                .flag("namespace")
50                                .map(String::as_str)
51                                .unwrap_or("default");
52
53                            let pods = match namespace {
54                                "default" => vec![
55                                    ("nginx-abc123", "Running"),
56                                    ("redis-def456", "Running"),
57                                    ("postgres-ghi789", "CrashLoopBackOff"),
58                                ],
59                                "kube-system" => vec![
60                                    ("coredns-xyz789", "Running"),
61                                    ("kube-proxy-abc123", "Running"),
62                                    ("etcd-master", "Running"),
63                                ],
64                                _ => vec![],
65                            };
66
67                            // Add pods with status descriptions
68                            for (pod, status) in &pods {
69                                if pod.starts_with(prefix) {
70                                    result = result.add_with_description(
71                                        *pod,
72                                        format!("Status: {status}"),
73                                    );
74                                }
75                            }
76
77                            // Add help if there's a problematic pod
78                            if pods.iter().any(|(_, status)| status == &"CrashLoopBackOff") {
79                                result = result.add_help_text(
80                                    "Warning: Some pods are in CrashLoopBackOff state. Use 'describe' to investigate.",
81                                );
82                            }
83
84                            Ok(result)
85                        })
86                        .run(|ctx| {
87                            let namespace = ctx
88                                .flag("namespace")
89                                .map(String::as_str)
90                                .unwrap_or("default");
91                            let output = ctx.flag("output").map(String::as_str).unwrap_or("table");
92
93                            println!("Getting pods from namespace: {namespace}");
94                            println!("Output format: {output}");
95
96                            if let Some(pod) = ctx.args().first() {
97                                println!("Getting specific pod: {pod}");
98                            } else {
99                                println!("Listing all pods");
100                            }
101                            Ok(())
102                        })
103                        .build(),
104                )
105                .subcommand(
106                    CommandBuilder::new("services")
107                        .short("Get services")
108                        .arg_completion(|_ctx, _prefix| {
109                            let mut result = CompletionResult::new()
110                                .add_with_description("nginx-service", "Type: LoadBalancer")
111                                .add_with_description("redis-service", "Type: ClusterIP")
112                                .add_with_description("postgres-service", "Type: NodePort");
113
114                            // Add conditional help based on flags
115                            result = result.add_conditional_help(
116                                "Tip: Use -o wide to see more details about services",
117                                |ctx| {
118                                    ctx.flag("output")
119                                        .map(|o| o != "wide")
120                                        .unwrap_or(true)
121                                },
122                            );
123
124                            Ok(result)
125                        })
126                        .build(),
127                )
128                .build(),
129        )
130        .subcommand(
131            CommandBuilder::new("create")
132                .short("Create resources")
133                .flag(
134                    Flag::new("file")
135                        .short('f')
136                        .usage("Filename to use to create the resource")
137                        .value_type(FlagType::String)
138                        .required(),
139                )
140                .flag_completion("file", |_ctx, prefix| {
141                    let mut result = CompletionResult::new();
142
143                    // Simulate file completions
144                    let files = vec![
145                        ("deployment.yaml", "Deployment configuration"),
146                        ("service.yaml", "Service configuration"),
147                        ("configmap.yaml", "ConfigMap configuration"),
148                        ("secret.yaml", "Secret configuration"),
149                        ("pod.yaml", "Pod configuration"),
150                    ];
151
152                    for (file, desc) in files {
153                        if file.starts_with(prefix) {
154                            result = result.add_with_description(file, desc);
155                        }
156                    }
157
158                    // Add contextual help
159                    result = result.add_help_text(
160                        "Files should be valid Kubernetes manifests in YAML or JSON format",
161                    );
162
163                    if std::path::Path::new(prefix)
164                        .extension()
165                        .is_some_and(|ext| ext.eq_ignore_ascii_case("json"))
166                    {
167                        result = result.add_help_text(
168                            "Note: JSON format is supported but YAML is more common in Kubernetes",
169                        );
170                    }
171
172                    Ok(result)
173                })
174                .run(|ctx| {
175                    let file = ctx.flag("file").expect("File is required");
176                    println!("Creating resources from file: {file}");
177                    Ok(())
178                })
179                .build(),
180        )
181        .subcommand(
182            CommandBuilder::new("debug")
183                .short("Debug and troubleshoot resources")
184                .arg_completion(|_ctx, _prefix| {
185                    Ok(CompletionResult::new()
186                        .add_with_description("pod/nginx-abc123", "Debug a specific pod")
187                        .add_with_description("node/worker-1", "Debug a node")
188                        .add_with_description("deployment/nginx", "Debug a deployment")
189                        .add_help_text("Debug creates an interactive debugging session")
190                        .add_help_text("Common debugging commands: kubectl logs, kubectl exec, kubectl describe")
191                        .add_conditional_help(
192                            "Tip: Use 'kubectl logs -f' to follow log output in real-time",
193                            |ctx| ctx.args().is_empty(),
194                        ))
195                })
196                .build(),
197        )
198        .build();
199
200    let args: Vec<String> = std::env::args().skip(1).collect();
201    if let Err(e) = app.execute(args) {
202        eprintln!("Error: {e}");
203        std::process::exit(1);
204    }
205}
Source

pub fn flag_completion<F>(self, flag_name: impl Into<String>, f: F) -> Self
where F: Fn(&Context, &str) -> Result<CompletionResult> + Send + Sync + 'static,

Sets the completion function for a specific flag

§Examples
use flag_rs::{CommandBuilder, CompletionResult, Flag, FlagType};

let cmd = CommandBuilder::new("connect")
    .flag(
        Flag::new("server")
            .usage("Server to connect to")
            .value_type(FlagType::String)
    )
    .flag_completion("server", |ctx, prefix| {
        // In a real app, discover available servers
        let servers = vec!["prod-1", "prod-2", "staging", "dev"];
        Ok(CompletionResult::new().extend(
            servers.into_iter()
                .filter(|s| s.starts_with(prefix))
                .map(String::from)
        ))
    })
    .build();
Examples found in repository?
examples/kubectl.rs (lines 29-41)
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/test_completion.rs (lines 12-27)
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/active_help_demo.rs (lines 140-173)
8fn main() {
9    let app = CommandBuilder::new("active-help-demo")
10        .short("Demonstrates ActiveHelp system")
11        .long("This example shows how ActiveHelp provides contextual hints during tab completion")
12        .flag(
13            Flag::new("namespace")
14                .short('n')
15                .usage("Kubernetes namespace")
16                .value_type(FlagType::String),
17        )
18        .flag(
19            Flag::new("output")
20                .short('o')
21                .usage("Output format")
22                .value_type(FlagType::String),
23        )
24        .subcommand(
25            CommandBuilder::new("get")
26                .short("Get resources")
27                .subcommand(
28                    CommandBuilder::new("pods")
29                        .short("Get pods")
30                        .arg_completion(|ctx, prefix| {
31                            let mut result = CompletionResult::new();
32
33                            // Add contextual help based on current state
34                            if ctx.flag("namespace").is_none() {
35                                result = result.add_help_text(
36                                    "Tip: Use -n <namespace> to list pods from a specific namespace",
37                                );
38                            }
39
40                            if ctx.flag("output").is_none() {
41                                result = result.add_conditional_help(
42                                    "Use -o json for machine-readable output",
43                                    |_| true, // Always show this tip
44                                );
45                            }
46
47                            // Simulate pod completions
48                            let namespace = ctx
49                                .flag("namespace")
50                                .map(String::as_str)
51                                .unwrap_or("default");
52
53                            let pods = match namespace {
54                                "default" => vec![
55                                    ("nginx-abc123", "Running"),
56                                    ("redis-def456", "Running"),
57                                    ("postgres-ghi789", "CrashLoopBackOff"),
58                                ],
59                                "kube-system" => vec![
60                                    ("coredns-xyz789", "Running"),
61                                    ("kube-proxy-abc123", "Running"),
62                                    ("etcd-master", "Running"),
63                                ],
64                                _ => vec![],
65                            };
66
67                            // Add pods with status descriptions
68                            for (pod, status) in &pods {
69                                if pod.starts_with(prefix) {
70                                    result = result.add_with_description(
71                                        *pod,
72                                        format!("Status: {status}"),
73                                    );
74                                }
75                            }
76
77                            // Add help if there's a problematic pod
78                            if pods.iter().any(|(_, status)| status == &"CrashLoopBackOff") {
79                                result = result.add_help_text(
80                                    "Warning: Some pods are in CrashLoopBackOff state. Use 'describe' to investigate.",
81                                );
82                            }
83
84                            Ok(result)
85                        })
86                        .run(|ctx| {
87                            let namespace = ctx
88                                .flag("namespace")
89                                .map(String::as_str)
90                                .unwrap_or("default");
91                            let output = ctx.flag("output").map(String::as_str).unwrap_or("table");
92
93                            println!("Getting pods from namespace: {namespace}");
94                            println!("Output format: {output}");
95
96                            if let Some(pod) = ctx.args().first() {
97                                println!("Getting specific pod: {pod}");
98                            } else {
99                                println!("Listing all pods");
100                            }
101                            Ok(())
102                        })
103                        .build(),
104                )
105                .subcommand(
106                    CommandBuilder::new("services")
107                        .short("Get services")
108                        .arg_completion(|_ctx, _prefix| {
109                            let mut result = CompletionResult::new()
110                                .add_with_description("nginx-service", "Type: LoadBalancer")
111                                .add_with_description("redis-service", "Type: ClusterIP")
112                                .add_with_description("postgres-service", "Type: NodePort");
113
114                            // Add conditional help based on flags
115                            result = result.add_conditional_help(
116                                "Tip: Use -o wide to see more details about services",
117                                |ctx| {
118                                    ctx.flag("output")
119                                        .map(|o| o != "wide")
120                                        .unwrap_or(true)
121                                },
122                            );
123
124                            Ok(result)
125                        })
126                        .build(),
127                )
128                .build(),
129        )
130        .subcommand(
131            CommandBuilder::new("create")
132                .short("Create resources")
133                .flag(
134                    Flag::new("file")
135                        .short('f')
136                        .usage("Filename to use to create the resource")
137                        .value_type(FlagType::String)
138                        .required(),
139                )
140                .flag_completion("file", |_ctx, prefix| {
141                    let mut result = CompletionResult::new();
142
143                    // Simulate file completions
144                    let files = vec![
145                        ("deployment.yaml", "Deployment configuration"),
146                        ("service.yaml", "Service configuration"),
147                        ("configmap.yaml", "ConfigMap configuration"),
148                        ("secret.yaml", "Secret configuration"),
149                        ("pod.yaml", "Pod configuration"),
150                    ];
151
152                    for (file, desc) in files {
153                        if file.starts_with(prefix) {
154                            result = result.add_with_description(file, desc);
155                        }
156                    }
157
158                    // Add contextual help
159                    result = result.add_help_text(
160                        "Files should be valid Kubernetes manifests in YAML or JSON format",
161                    );
162
163                    if std::path::Path::new(prefix)
164                        .extension()
165                        .is_some_and(|ext| ext.eq_ignore_ascii_case("json"))
166                    {
167                        result = result.add_help_text(
168                            "Note: JSON format is supported but YAML is more common in Kubernetes",
169                        );
170                    }
171
172                    Ok(result)
173                })
174                .run(|ctx| {
175                    let file = ctx.flag("file").expect("File is required");
176                    println!("Creating resources from file: {file}");
177                    Ok(())
178                })
179                .build(),
180        )
181        .subcommand(
182            CommandBuilder::new("debug")
183                .short("Debug and troubleshoot resources")
184                .arg_completion(|_ctx, _prefix| {
185                    Ok(CompletionResult::new()
186                        .add_with_description("pod/nginx-abc123", "Debug a specific pod")
187                        .add_with_description("node/worker-1", "Debug a node")
188                        .add_with_description("deployment/nginx", "Debug a deployment")
189                        .add_help_text("Debug creates an interactive debugging session")
190                        .add_help_text("Common debugging commands: kubectl logs, kubectl exec, kubectl describe")
191                        .add_conditional_help(
192                            "Tip: Use 'kubectl logs -f' to follow log output in real-time",
193                            |ctx| ctx.args().is_empty(),
194                        ))
195                })
196                .build(),
197        )
198        .build();
199
200    let args: Vec<String> = std::env::args().skip(1).collect();
201    if let Err(e) = app.execute(args) {
202        eprintln!("Error: {e}");
203        std::process::exit(1);
204    }
205}
Source

pub fn suggestions(self, enabled: bool) -> Self

Enables or disables command suggestions

When enabled, the framework will suggest similar commands when a user types an unknown command.

§Examples
use flag_rs::CommandBuilder;

let cmd = CommandBuilder::new("myapp")
    .suggestions(true)  // Enable suggestions (default)
    .build();
Source

pub fn suggestion_distance(self, distance: usize) -> Self

Sets the maximum Levenshtein distance for suggestions

Commands within this distance will be suggested as alternatives. Default is 2.

§Examples
use flag_rs::CommandBuilder;

let cmd = CommandBuilder::new("myapp")
    .suggestion_distance(3)  // Allow more distant suggestions
    .build();
Source

pub fn build(self) -> Command

Builds and returns the completed Command

Examples found in repository?
examples/benchmark.rs (line 60)
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 42)
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}
78
79fn build_get_pods() -> Command {
80    CommandBuilder::new("pods")
81        .aliases(vec!["po", "pod"])
82        .short("List pods")
83        .arg_completion(|ctx, prefix| {
84            // This is the key feature - dynamic completion based on runtime state!
85            let namespace = ctx
86                .flag("namespace")
87                .map(String::as_str)
88                .unwrap_or("default");
89
90            // In real kubectl, this would query the K8s API
91            let pods = get_pods_with_status(namespace);
92            let mut result = CompletionResult::new();
93
94            for (pod_name, status) in pods {
95                if pod_name.starts_with(prefix) {
96                    result = result.add_with_description(pod_name, status);
97                }
98            }
99
100            Ok(result)
101        })
102        .run(|ctx| {
103            let namespace = ctx
104                .flag("namespace")
105                .map(String::as_str)
106                .unwrap_or("default");
107
108            println!("Listing pods in namespace: {namespace}");
109
110            if let Some(pod_name) = ctx.args().first() {
111                println!("Getting specific pod: {pod_name}");
112            } else {
113                for pod in get_pods_in_namespace(namespace) {
114                    println!("pod/{}", pod);
115                }
116            }
117
118            Ok(())
119        })
120        .build()
121}
122
123fn build_get_services() -> Command {
124    CommandBuilder::new("services")
125        .aliases(vec!["svc", "service"])
126        .short("List services")
127        .arg_completion(|ctx, prefix| {
128            let namespace = ctx
129                .flag("namespace")
130                .map(String::as_str)
131                .unwrap_or("default");
132
133            let services = get_services_in_namespace(namespace);
134            Ok(CompletionResult::new()
135                .extend(services.into_iter().filter(|svc| svc.starts_with(prefix))))
136        })
137        .run(|ctx| {
138            let namespace = ctx
139                .flag("namespace")
140                .map(String::as_str)
141                .unwrap_or("default");
142
143            println!("Listing services in namespace: {namespace}");
144            Ok(())
145        })
146        .build()
147}
148
149fn build_get_deployments() -> Command {
150    CommandBuilder::new("deployments")
151        .aliases(vec!["deploy", "deployment"])
152        .short("List deployments")
153        .run(|ctx| {
154            let namespace = ctx
155                .flag("namespace")
156                .map(String::as_str)
157                .unwrap_or("default");
158
159            println!("Listing deployments in namespace: {namespace}");
160            Ok(())
161        })
162        .build()
163}
164
165fn build_describe_command() -> Command {
166    CommandBuilder::new("describe")
167        .short("Show details of a specific resource")
168        .run(|_ctx| {
169            println!("Describe command - add resource type subcommands");
170            Ok(())
171        })
172        .build()
173}
174
175fn build_delete_command() -> Command {
176    CommandBuilder::new("delete")
177        .short("Delete resources")
178        .run(|_ctx| {
179            println!("Delete command - add resource type subcommands");
180            Ok(())
181        })
182        .build()
183}
184
185// Mock functions that would normally query the Kubernetes API
186fn get_namespaces_with_descriptions() -> Vec<(String, String)> {
187    vec![
188        (
189            "default".to_string(),
190            "Default namespace for user workloads".to_string(),
191        ),
192        (
193            "kube-system".to_string(),
194            "Kubernetes system components".to_string(),
195        ),
196        (
197            "kube-public".to_string(),
198            "Public resources accessible to all users".to_string(),
199        ),
200        (
201            "development".to_string(),
202            "Development environment".to_string(),
203        ),
204        (
205            "staging".to_string(),
206            "Staging environment for pre-production testing".to_string(),
207        ),
208        (
209            "production".to_string(),
210            "Production environment (CAUTION)".to_string(),
211        ),
212    ]
213}
214
215fn get_pods_with_status(namespace: &str) -> Vec<(String, String)> {
216    use std::time::{SystemTime, UNIX_EPOCH};
217
218    // Generate random suffix based on current time
219    let timestamp = SystemTime::now()
220        .duration_since(UNIX_EPOCH)
221        .unwrap()
222        .as_secs();
223
224    // Simple pseudo-random generation
225    let rand1 = ((timestamp * 1_103_515_245 + 12345) / 65536) % 100_000;
226    let rand2 = ((rand1 * 1_103_515_245 + 12345) / 65536) % 100_000;
227    let rand3 = ((rand2 * 1_103_515_245 + 12345) / 65536) % 100_000;
228
229    match namespace {
230        "default" => vec![
231            (
232                format!("nginx-deployment-7fb96c846b-{:05x}", rand1),
233                "Running (2/2 containers)".to_string(),
234            ),
235            (
236                format!("nginx-deployment-7fb96c846b-{:05x}", rand2),
237                "Running (2/2 containers)".to_string(),
238            ),
239            (
240                "redis-master-0".to_string(),
241                "Running (1/1 containers)".to_string(),
242            ),
243            (
244                "redis-slave-0".to_string(),
245                "Running (1/1 containers)".to_string(),
246            ),
247            ("redis-slave-1".to_string(), "Pending".to_string()),
248        ],
249        "kube-system" => vec![
250            (
251                format!("coredns-5d78c9869d-{:05x}", rand1),
252                "Running (1/1 containers)".to_string(),
253            ),
254            (
255                format!("coredns-5d78c9869d-{:05x}", rand2),
256                "Running (1/1 containers)".to_string(),
257            ),
258            ("etcd-minikube".to_string(), "Running".to_string()),
259            ("kube-apiserver-minikube".to_string(), "Running".to_string()),
260            (
261                "kube-controller-manager-minikube".to_string(),
262                "Running".to_string(),
263            ),
264            (format!("kube-proxy-{:05x}", rand3), "Running".to_string()),
265            ("kube-scheduler-minikube".to_string(), "Running".to_string()),
266        ],
267        _ => vec![],
268    }
269}
270
271fn get_pods_in_namespace(namespace: &str) -> Vec<String> {
272    use std::time::{SystemTime, UNIX_EPOCH};
273
274    // Generate random suffix based on current time
275    let timestamp = SystemTime::now()
276        .duration_since(UNIX_EPOCH)
277        .unwrap()
278        .as_secs();
279
280    // Simple pseudo-random generation
281    let rand1 = ((timestamp * 1_103_515_245 + 12345) / 65536) % 100_000;
282    let rand2 = ((rand1 * 1_103_515_245 + 12345) / 65536) % 100_000;
283    let rand3 = ((rand2 * 1_103_515_245 + 12345) / 65536) % 100_000;
284
285    match namespace {
286        "default" => vec![
287            format!("nginx-deployment-7fb96c846b-{:05x}", rand1),
288            format!("nginx-deployment-7fb96c846b-{:05x}", rand2),
289            format!("redis-master-0"),
290            format!("redis-slave-0"),
291            format!("redis-slave-1"),
292        ],
293        "kube-system" => vec![
294            format!("coredns-5d78c9869d-{:05x}", rand1),
295            format!("coredns-5d78c9869d-{:05x}", rand2),
296            format!("etcd-minikube"),
297            format!("kube-apiserver-minikube"),
298            format!("kube-controller-manager-minikube"),
299            format!("kube-proxy-{:05x}", rand3),
300            format!("kube-scheduler-minikube"),
301        ],
302        _ => vec![],
303    }
304}
305
306fn get_services_in_namespace(namespace: &str) -> Vec<String> {
307    match namespace {
308        "default" => vec![
309            "kubernetes".to_string(),
310            "nginx-service".to_string(),
311            "redis-master".to_string(),
312            "redis-slave".to_string(),
313        ],
314        "kube-system" => vec!["kube-dns".to_string()],
315        _ => vec![],
316    }
317}
318
319fn build_completion_command() -> Command {
320    CommandBuilder::new("completion")
321        .short("Generate shell completion scripts")
322        .long("Generate shell completion scripts for kubectl")
323        .arg_completion(|_ctx, prefix| {
324            let shells = vec![
325                ("bash", "Bash shell completion"),
326                ("zsh", "Zsh shell completion"),
327                ("fish", "Fish shell completion"),
328            ];
329
330            let mut result = CompletionResult::new();
331            for (shell, description) in shells {
332                if shell.starts_with(prefix) {
333                    result =
334                        result.add_with_description(shell.to_string(), description.to_string());
335                }
336            }
337
338            Ok(result)
339        })
340        .run(|ctx| {
341            let shell_name = ctx.args().first().ok_or_else(|| {
342                flag_rs::Error::ArgumentParsing(
343                    "shell name required (bash, zsh, or fish)".to_string(),
344                )
345            })?;
346
347            let shell = match shell_name.as_str() {
348                "bash" => Shell::Bash,
349                "zsh" => Shell::Zsh,
350                "fish" => Shell::Fish,
351                _ => {
352                    return Err(flag_rs::Error::ArgumentParsing(format!(
353                        "unsupported shell: {}",
354                        shell_name
355                    )));
356                }
357            };
358
359            // In a real app, you'd get the root command from a shared reference
360            // For this example, we'll recreate it
361            let root = build_kubectl();
362            println!("{}", root.generate_completion(shell));
363
364            Ok(())
365        })
366        .build()
367}
examples/terminal_demo.rs (line 37)
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/suggestion_demo.rs (line 14)
4fn main() {
5    let app = CommandBuilder::new("suggestion-demo")
6        .short("Demonstrates command suggestions")
7        .subcommand(
8            CommandBuilder::new("start")
9                .short("Start the service")
10                .run(|_| {
11                    println!("Starting service...");
12                    Ok(())
13                })
14                .build(),
15        )
16        .subcommand(
17            CommandBuilder::new("stop")
18                .short("Stop the service")
19                .run(|_| {
20                    println!("Stopping service...");
21                    Ok(())
22                })
23                .build(),
24        )
25        .subcommand(
26            CommandBuilder::new("restart")
27                .short("Restart the service")
28                .run(|_| {
29                    println!("Restarting service...");
30                    Ok(())
31                })
32                .build(),
33        )
34        .subcommand(
35            CommandBuilder::new("status")
36                .short("Show service status")
37                .run(|_| {
38                    println!("Service is running");
39                    Ok(())
40                })
41                .build(),
42        )
43        .subcommand(
44            CommandBuilder::new("config")
45                .short("Manage configuration")
46                .subcommand(
47                    CommandBuilder::new("get")
48                        .short("Get configuration value")
49                        .run(|_| {
50                            println!("Configuration value: enabled");
51                            Ok(())
52                        })
53                        .build(),
54                )
55                .subcommand(
56                    CommandBuilder::new("set")
57                        .short("Set configuration value")
58                        .run(|_| {
59                            println!("Configuration updated");
60                            Ok(())
61                        })
62                        .build(),
63                )
64                .build(),
65        )
66        .build();
67
68    let args: Vec<String> = std::env::args().skip(1).collect();
69
70    // Show what command was attempted
71    if !args.is_empty() {
72        println!("Command attempted: {}\n", args[0]);
73    }
74
75    if let Err(e) = app.execute(args) {
76        eprintln!("Error: {}", e);
77        std::process::exit(1);
78    }
79}
examples/test_completion.rs (line 32)
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/validator_demo.rs (line 16)
4fn main() {
5    let app = CommandBuilder::new("validator-demo")
6        .short("Demonstrates argument validation")
7        .subcommand(
8            CommandBuilder::new("copy")
9                .short("Copy files (requires exactly 2 arguments)")
10                .args(ArgValidator::ExactArgs(2))
11                .run(|ctx| {
12                    let args = ctx.args();
13                    println!("Copying from '{}' to '{}'", args[0], args[1]);
14                    Ok(())
15                })
16                .build(),
17        )
18        .subcommand(
19            CommandBuilder::new("delete")
20                .short("Delete files (requires at least 1 argument)")
21                .args(ArgValidator::MinimumArgs(1))
22                .run(|ctx| {
23                    println!("Deleting {} file(s):", ctx.args().len());
24                    for file in ctx.args() {
25                        println!("  - {}", file);
26                    }
27                    Ok(())
28                })
29                .build(),
30        )
31        .subcommand(
32            CommandBuilder::new("list")
33                .short("List items (accepts 0-3 arguments)")
34                .args(ArgValidator::RangeArgs(0, 3))
35                .run(|ctx| {
36                    if ctx.args().is_empty() {
37                        println!("Listing all items");
38                    } else {
39                        println!("Listing specific items:");
40                        for item in ctx.args() {
41                            println!("  - {}", item);
42                        }
43                    }
44                    Ok(())
45                })
46                .build(),
47        )
48        .subcommand(
49            CommandBuilder::new("action")
50                .short("Perform action (only start/stop/restart allowed)")
51                .args(ArgValidator::OnlyValidArgs(vec![
52                    "start".to_string(),
53                    "stop".to_string(),
54                    "restart".to_string(),
55                ]))
56                .run(|ctx| {
57                    let action = ctx.args().first().map(String::as_str).unwrap_or("start");
58                    println!("Performing action: {}", action);
59                    Ok(())
60                })
61                .build(),
62        )
63        .subcommand(
64            CommandBuilder::new("numbers")
65                .short("Process numbers (custom validator for integers)")
66                .args(ArgValidator::Custom(std::sync::Arc::new(|args| {
67                    if args.is_empty() {
68                        return Err(Error::ArgumentValidation {
69                            message: "at least one number required".to_string(),
70                            expected: "numbers".to_string(),
71                            received: 0,
72                        });
73                    }
74
75                    for (i, arg) in args.iter().enumerate() {
76                        if arg.parse::<i32>().is_err() {
77                            return Err(Error::ArgumentValidation {
78                                message: format!(
79                                    "argument {} ('{}') must be an integer",
80                                    i + 1,
81                                    arg
82                                ),
83                                expected: "integer".to_string(),
84                                received: args.len(),
85                            });
86                        }
87                    }
88                    Ok(())
89                })))
90                .run(|ctx| {
91                    let numbers: Vec<i32> = ctx.args().iter().map(|s| s.parse().unwrap()).collect();
92                    let sum: i32 = numbers.iter().sum();
93                    println!("Sum of {} numbers: {}", numbers.len(), sum);
94                    Ok(())
95                })
96                .build(),
97        )
98        .build();
99
100    let args: Vec<String> = std::env::args().skip(1).collect();
101    if let Err(e) = app.execute(args) {
102        eprintln!("Error: {}", e);
103        std::process::exit(1);
104    }
105}

Auto Trait Implementations§

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> 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, 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.