CLI Flags (std.flags)
The std.flags module provides ergonomic, type-safe command-line argument parsing with automatic help generation.
nic
import std.flags;Quick Start
nic
import std.flags.parser(FlagParser);
import std.args(Args);
fn main(argc: i32, argv: **char) -> i32 {
let args = Args.from_main(argc, argv);
defer args.deinit();
let parser = FlagParser.for_program("myapp", "A sample application");
defer release parser;
parser
.flag_bool("verbose", "v", "Enable verbose output")
.flag_i32("count", "c", "Number of iterations", 1)
.flag_string("output", "o", "Output file", "out.txt")
.positional_required("input", "Input file");
match parser.parse(args) {
Ok(flags) => {
let verbose = flags.get_bool("verbose");
let count = flags.get_i32("count");
let output = flags.get_string("output");
match flags.get_positional(0) {
Some(input) => {
if verbose {
printf("Processing %s -> %s (%d times)\n",
input.as_str(), output.as_str(), count);
}
},
None => {},
}
release flags;
},
Err(e) => {
printf("Error: %s\n", e.as_str());
parser.print_help();
release e;
return 1;
}
}
return 0;
}Creating a Parser
FlagParser.for_program
Create a new parser with program name and description:
nic
let parser = FlagParser.for_program("mytool", "A helpful description");
defer release parser;Defining Flags
All flag methods return *Self for method chaining.
Boolean Flags
nic
parser.flag_bool("verbose", "v", "Enable verbose output");
parser.flag_bool("debug", "d", "Enable debug mode");
parser.flag_bool("help", "h", "Show help message");Usage: -v, --verbose, -vd (combined)
Integer Flags
nic
// i32 with default value
parser.flag_i32("count", "c", "Number of items", 10);
// i64 with default value
parser.flag_i64("size", "s", "Size in bytes", 1024);Usage: -c 5, --count 5, --count=5
String Flags
nic
parser.flag_string("output", "o", "Output file path", "output.txt");
parser.flag_string("format", "f", "Output format", "json");Usage: -o file.txt, --output file.txt, --output=file.txt
String List Flags
Flags that can be specified multiple times:
nic
parser.string_list("include", "I", "Include paths");Usage: -I./src -I./lib, --include ./src --include ./lib
Positional Arguments
Optional Positional
nic
parser.positional("config", "Configuration file");Required Positional
nic
parser.positional_required("input", "Input file to process");Multiple positionals are collected in order:
nic
parser
.positional_required("source", "Source file")
.positional_required("dest", "Destination file")
.positional("extra", "Optional extra file");Subcommands
Create git-style subcommands:
nic
let parser = FlagParser.for_program("git", "Version control");
// Define 'clone' subcommand
let clone = parser.subcommand("clone", "Clone a repository");
clone
.flag_string("branch", "b", "Branch to clone", "main")
.flag_bool("shallow", "", "Shallow clone")
.positional_required("url", "Repository URL");
// Define 'commit' subcommand
let commit = parser.subcommand("commit", "Record changes");
commit
.flag_string("message", "m", "Commit message", "")
.flag_bool("all", "a", "Commit all changed files");
match parser.parse(args) {
Ok(flags) => {
match flags.get_subcommand() {
Some(cmd) => {
if cmd.equals("clone") {
let url = flags.get_positional(0);
let branch = flags.get_string("branch");
// Handle clone...
} else if cmd.equals("commit") {
let message = flags.get_string("message");
// Handle commit...
}
},
None => {
parser.print_help();
},
}
release flags;
},
Err(e) => {
printf("Error: %s\n", e.as_str());
release e;
}
}Parsing Results
ParsedFlags Methods
nic
// Boolean flags (default: false)
let verbose = flags.get_bool("verbose");
// Integer flags
let count = flags.get_i32("count");
let size = flags.get_i64("size");
// String flags
let output = flags.get_string("output"); // Returns *String
// String lists
let includes = flags.get_string_list("include"); // Returns *Vec[*String]
// Positional arguments
match flags.get_positional(0) {
Some(arg) => println("First arg: " + arg.as_str()),
None => println("No positional args"),
}
let positional_count = flags.positional_count();
// Subcommand (if any)
match flags.get_subcommand() {
Some(cmd) => println("Subcommand: " + cmd.as_str()),
None => println("No subcommand"),
}Help Generation
Automatic Help
Call print_help() to display formatted help:
nic
parser.print_help();Output:
myapp - A sample application
USAGE:
myapp [OPTIONS] <input>
ARGUMENTS:
<input> Input file (required)
OPTIONS:
-v, --verbose Enable verbose output
-c, --count <num> Number of iterations
-o, --output <value> Output fileCustom Help Flag
nic
if args.contains("-h") || args.contains("--help") {
parser.print_help();
return 0;
}Flag Formats
The parser supports multiple formats:
| Format | Example | Description |
|---|---|---|
| Short | -v | Single character flag |
| Long | --verbose | Full name flag |
| Combined short | -vvv | Multiple short flags |
| Value (space) | -c 5 | Value after space |
| Value (equals) | --count=5 | Value after equals |
| Value (attached) | -c5 | Value immediately after short |
| End of flags | -- | Treat rest as positionals |
Complete Example
nic
import std.flags.parser(FlagParser);
import std.flags.result(ParsedFlags);
import std.args(Args);
fn main(argc: i32, argv: **char) -> i32 {
let args = Args.from_main(argc, argv);
defer args.deinit();
let parser = FlagParser.for_program("compiler", "The Nic compiler");
defer release parser;
// Global options
parser
.flag_bool("verbose", "v", "Verbose output")
.flag_bool("help", "h", "Show help")
.flag_string("output", "o", "Output file", "a.out")
.string_list("include", "I", "Include directories");
// Build subcommand
let build = parser.subcommand("build", "Build the project");
build
.flag_bool("release", "r", "Release build")
.flag_i32("jobs", "j", "Parallel jobs", 4);
// Run subcommand
let run = parser.subcommand("run", "Build and run");
run
.positional("file", "File to run");
// Parse
match parser.parse(args) {
Ok(flags) => {
if flags.get_bool("help") {
parser.print_help();
release flags;
return 0;
}
match flags.get_subcommand() {
Some(cmd) => {
if cmd.equals("build") {
let release_build = flags.get_bool("release");
let jobs = flags.get_i32("jobs");
printf("Building with %d jobs (release=%d)\n",
jobs, release_build as i32);
} else if cmd.equals("run") {
match flags.get_positional(0) {
Some(file) => {
printf("Running %s\n", file.as_str());
},
None => {
println("No file specified");
},
}
}
},
None => {
parser.print_help();
},
}
release flags;
},
Err(e) => {
printf("Error: %s\n", e.as_str());
parser.print_help();
release e;
return 1;
}
}
return 0;
}API Reference
FlagParser Class
nic
pub class FlagParser {
/// Create a new parser for a program
pub for_program(name: string, desc: string) -> *FlagParser;
/// Add a boolean flag
pub flag_bool(self, name: string, short: string, help: string) -> *Self;
/// Add an i32 flag with default value
pub flag_i32(self, name: string, short: string, help: string, default: i32) -> *Self;
/// Add an i64 flag with default value
pub flag_i64(self, name: string, short: string, help: string, default: i64) -> *Self;
/// Add a string flag with default value
pub flag_string(self, name: string, short: string, help: string, default: string) -> *Self;
/// Add a string list flag (can be repeated)
pub string_list(self, name: string, short: string, help: string) -> *Self;
/// Add an optional positional argument
pub positional(self, name: string, help: string) -> *Self;
/// Add a required positional argument
pub positional_required(self, name: string, help: string) -> *Self;
/// Add a subcommand
pub subcommand(self, name: string, desc: string) -> *FlagParser;
/// Parse arguments
pub parse(self, args: *Args) -> Result[*ParsedFlags, *String];
/// Print help to stdout
pub print_help(self) -> unit;
/// Generate help text as a String
pub help_string(self) -> *String;
}ParsedFlags Class
nic
pub class ParsedFlags {
/// Get a boolean flag value
pub get_bool(self, name: string) -> bool;
/// Get an i32 flag value
pub get_i32(self, name: string) -> i32;
/// Get an i64 flag value
pub get_i64(self, name: string) -> i64;
/// Get a string flag value
pub get_string(self, name: string) -> *String;
/// Get a string list flag value
pub get_string_list(self, name: string) -> *Vec[*String];
/// Get a positional argument by index
pub get_positional(self, index: u64) -> Option[*String];
/// Get number of positional arguments
pub positional_count(self) -> u64;
/// Get the subcommand name (if any)
pub get_subcommand(self) -> Option[*String];
}See Also
- Arguments (std.args) - Low-level argument access
- Parsing (std.parse) - String parsing utilities