Skip to main content

#
clap/
_concepts.rs

    1//! ## CLI Concepts
    2//!
    3//! Note: this will be speaking towards the general case.
    4//!
    5//! ### Environmental context
    6//!
    7//! When you run a command line application, it is inside a terminal emulator, or terminal.
    8//! This handles integration with the rest of your system including user input,
    9//! rendering, etc.
    10//!
    11//! The terminal will run inside of itself an interactive shell.
    12//! The shell is responsible for showing the prompt, receiving input including the command you are writing,
    13//! letting that command take over until completion, and then repeating.
    14//! This is called a read-eval-print loop, or REPL.
    15//! Typically the shell will take the command you typed and split it into separate arguments,
    16//! including handling of quoting, escaping, and globbing.
    17//! The parsing and evaluation of the command is shell specific.
    18//! The shell will then determine which application to run and then pass the full command-line as
    19//! individual arguments to your program.
    20//! These arguments are exposed in Rust as [`std::env::args_os`].
    21//!
    22//! Windows is an exception in Shell behavior in that the command is passed as an individual
    23//! string, verbatim, and the application must split the arguments.
    24//! [`std::env::args_os`] will handle the splitting for you but will not handle globs.
    25//!
    26//! Takeaways:
    27//! - Your application will only see quotes that have been escaped within the shell
    28//!   - e.g. to receive `message="hello world"`, you may need to type `'message="hello world"'` or `message=\"hello world\"`
    29//! - If your applications needs to parse a string into arguments,
    30//!   you will need to pick a syntax and do it yourself
    31//!   - POSIX's shell syntax is a common choice and available in packages like [shlex](https://docs.rs/shlex)
    32//!   - See also our [REPL cookbook entry][crate::_cookbook::repl]
    33//! - On Windows, you will need to handle globbing yourself if desired
    34//!   - [`wild`](https://docs.rs/wild) can help with that
    35//!
    36//! ### Argument Parsing
    37//!
    38//! The first argument of [`std::env::args_os`] is the [`Command::bin_name`]
    39//! which is usually limited to affecting [`Command::render_usage`].
    40//! [`Command::no_binary_name`] and [`Command::multicall`] exist for rare cases when this assumption is not valid.
    41//!
    42//! Command-lines are a context-sensitive grammar,
    43//! meaning the interpretation of an argument is based on the arguments that came before.
    44//! Arguments come in one of several flavors:
    45//! - Values
    46//! - Flags
    47//! - Subcommands
    48//!
    49//! When examining the next argument,
    50//! 1. If it starts with a `--`,
    51//!    then that is a long Flag and all remaining text up to a `=` or the end is
    52//!    matched to a [`Arg::long`], [`Command::long_flag`], or alias.
    53//!    - Everything after the `=` is taken as a Value and parsing a new argument is examined.
    54//!    - If no `=` is present, then Values will be taken according to [`Arg::num_args`]
    55//!    - We generally call a Flag that takes a Value an Option
    56//! 2. If it starts with a `-`,
    57//!    then that is a sequence of short Flags where each character is matched against a [`Arg::short`], [`Command::short_flag`] or
    58//!    alias until `=`, the end, or a short Flag takes Values (see [`Arg::num_args`])
    59//! 3. If its a `--`, that is an escape and all future arguments are considered to be a Value, even if
    60//!    they start with `--` or `-`
    61//! 4. If it matches a [`Command::name`],
    62//!    then the argument is a subcommand
    63//! 5. If there is an [`Arg`] at the next [`Arg::index`],
    64//!    then the argument is considered a Positional argument
    65//!
    66//! When a subcommand matches,
    67//! all further arguments are parsed by that [`Command`].
    68//!
    69//! There are many settings that tweak this behavior, including:
    70//! - [`Arg::last`]: a positional that can only come after `--`
    71//! - [`Arg::trailing_var_arg`]: all further arguments are captured as additional Values
    72//! - [`Arg::allow_hyphen_values`] and [`Arg::allow_negative_numbers`]: assumes arguments
    73//!   starting with `-` are Values and not Flags.
    74//! - [`Command::subcommand_precedence_over_arg`]: when an [`Arg::num_args`] takes Values,
    75//!   stop if one matches a subCommand
    76//! - [`Command::allow_missing_positional`]: in limited cases a [`Arg::index`] may be skipped
    77//! - [`Command::allow_external_subcommands`]: treat any unknown argument as a subcommand, capturing
    78//!   all remaining arguments.
    79//!
    80//! Takeaways
    81//! - Values that start with a `-` either need to be escaped by the user with `--`
    82//!   (if a positional),
    83//!   or you need to set [`Arg::allow_hyphen_values`] or [`Arg::allow_negative_numbers`]
    84//! - [`Arg::num_args`],
    85//!   [`ArgAction::Append`] (on a positional),
    86//!   [`Arg::trailing_var_arg`],
    87//!   and [`Command::allow_external_subcommands`]
    88//!   all affect the parser in similar but slightly different ways and which to use depends on your
    89//!   application
    90//!
    91//! ### Value Parsing
    92//!
    93//! When reacting to a Flag (no Value),
    94//! [`Arg::default_missing_values`] will be applied.
    95//!
    96//! The Value will be split by [`Arg::value_delimiter`].
    97//!
    98//! The Value will then be stored according to its [`ArgAction`].
    99//! For most [`ArgAction`]s,
    100//! the Value will be parsed according to [`ValueParser`]
    101//! and stored in the [`ArgMatches`].
    102
    103#![allow(unused_imports)]
    104use clap_builder::Arg;
    105use clap_builder::ArgAction;
    106use clap_builder::ArgMatches;
    107use clap_builder::Command;
    108use clap_builder::builder::ValueParser;