Command

Struct Command 

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

Represents a command in the CLI application

Commands can have:

  • Subcommands for nested command structures
  • Flags that modify behavior
  • A run function that executes the command logic
  • Dynamic completion functions for arguments and flags
  • Help text and aliases

§Examples

use flag_rs::{Command, CommandBuilder, Context};

// Using the builder pattern (recommended)
let cmd = CommandBuilder::new("serve")
    .short("Start the web server")
    .run(|ctx| {
        println!("Server starting...");
        Ok(())
    })
    .build();

// Direct construction
let mut cmd = Command::new("serve");

Implementations§

Source§

impl Command

Source

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

Creates a new command with the given name

§Examples
use flag_rs::Command;

let cmd = Command::new("myapp");
Source

pub fn name(&self) -> &str

Returns the command name

Source

pub fn short(&self) -> &str

Returns the short description

Source

pub fn long(&self) -> &str

Returns the long description

Source

pub fn subcommands(&self) -> &HashMap<String, Self>

Returns a reference to all subcommands

Examples found in repository?
examples/memory_optimization_demo.rs (line 118)
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}
Source

pub fn flags(&self) -> &HashMap<String, Flag>

Returns a reference to all flags

Examples found in repository?
examples/memory_optimization_demo.rs (line 126)
125fn count_flags(cmd: &flag_rs::Command) -> usize {
126    cmd.flags().len() + cmd.subcommands().values().map(count_flags).sum::<usize>()
127}
Source

pub fn find_subcommand(&self, name: &str) -> Option<&Self>

Finds a subcommand by name or alias

§Examples
let mut root = Command::new("app");
let sub = CommandBuilder::new("server")
    .aliases(vec!["serve", "s"])
    .build();
root.add_command(sub);

assert!(root.find_subcommand("server").is_some());
assert!(root.find_subcommand("serve").is_some());
assert!(root.find_subcommand("s").is_some());
Examples found in repository?
examples/benchmark.rs (line 175)
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}
Source

pub fn find_subcommand_mut(&mut self, name: &str) -> Option<&mut Self>

Finds a mutable reference to a subcommand by name or alias

Source

pub fn add_command(&mut self, cmd: Self)

Adds a subcommand to this command

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

let mut root = Command::new("myapp");
let serve = CommandBuilder::new("serve")
    .short("Start the server")
    .build();

root.add_command(serve);
Examples found in repository?
examples/benchmark.rs (lines 85-90)
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/memory_optimization_demo.rs (line 111)
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 execute(&self, args: Vec<String>) -> Result<()>

Executes the command with the given arguments

This is the main entry point for running your CLI application. It handles:

  • Shell completion requests
  • Flag parsing
  • Subcommand routing
  • Execution of the appropriate run function
§Examples
use flag_rs::CommandBuilder;

let app = CommandBuilder::new("myapp")
    .run(|ctx| {
        println!("Hello from myapp!");
        Ok(())
    })
    .build();

// In main():
// let args: Vec<String> = std::env::args().skip(1).collect();
// if let Err(e) = app.execute(args) {
//     eprintln!("Error: {}", e);
//     std::process::exit(1);
// }
Examples found in repository?
examples/kubectl.rs (line 8)
4fn main() {
5    let app = build_kubectl();
6
7    let args: Vec<String> = env::args().skip(1).collect();
8    if let Err(e) = app.execute(args) {
9        eprintln!("Error: {e:?}");
10        std::process::exit(1);
11    }
12}
More examples
Hide additional examples
examples/benchmark.rs (line 133)
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}
examples/suggestion_demo.rs (line 75)
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 73)
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 (line 217)
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 (line 101)
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 execute_with_context(&self, ctx: &mut Context) -> Result<()>

Executes the command with an existing context

This method is useful when you need to provide pre-configured context or when implementing custom command routing.

Source

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

Sets the argument completion function for this command

The completion function is called when the user presses TAB to complete command arguments. It receives the current context and the prefix to complete.

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

let mut cmd = Command::new("get");
cmd.set_arg_completion(|ctx, prefix| {
    let items = vec!["users", "posts", "comments"];
    Ok(CompletionResult::new().extend(
        items.into_iter()
            .filter(|i| i.starts_with(prefix))
            .map(String::from)
    ))
});
Source

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

Sets the completion function for a specific flag

This allows dynamic completion of flag values based on runtime state.

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

let mut cmd = Command::new("deploy");
cmd.set_flag_completion("environment", |ctx, prefix| {
    let envs = vec!["dev", "staging", "production"];
    Ok(CompletionResult::new().extend(
        envs.into_iter()
            .filter(|e| e.starts_with(prefix))
            .map(String::from)
    ))
});
Source

pub fn get_completions( &self, ctx: &Context, to_complete: &str, completing_flag: Option<&str>, ) -> Result<CompletionResult>

Gets completion suggestions for the current context

This method is primarily used internally by the shell completion system.

Examples found in repository?
examples/benchmark.rs (line 217)
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}
Source

pub fn print_help(&self)

Prints the help message for this command

The help message includes:

  • Command description
  • Usage information
  • Available subcommands
  • Local and global flags

Help text is automatically colored when outputting to a TTY.

Examples found in repository?
examples/terminal_demo.rs (line 42)
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}
Source

pub fn handle_completion_request(&self, args: &[String]) -> Result<Vec<String>>

Handles shell completion requests

This method is called when the shell requests completions via the environment variable (e.g., MYAPP_COMPLETE=bash).

Examples found in repository?
examples/test_completion.rs (line 51)
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}
Source§

impl Command

Source

pub fn generate_completion(&self, shell: Shell) -> String

Generates a completion script for the specified shell

The generated script should be saved to the appropriate location for your shell to load it automatically.

§Arguments
  • shell - The shell to generate completions for
§Returns

A string containing the shell completion script

§Shell-specific installation
§Bash

Save to /etc/bash_completion.d/myapp or source from .bashrc:

myapp completion bash > ~/.myapp-completion.bash
echo "source ~/.myapp-completion.bash" >> ~/.bashrc
§Zsh

Save to a directory in your $fpath:

myapp completion zsh > ~/.zsh/completions/_myapp
§Fish

Save to Fish’s completion directory:

myapp completion fish > ~/.config/fish/completions/myapp.fish
Examples found in repository?
examples/kubectl.rs (line 362)
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}

Trait Implementations§

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.