Skip to content

An experimental derive-based argument parser specifically for uutils

License

Notifications You must be signed in to change notification settings

uutils/uutils-args

Repository files navigation

uutils-args

Argument parsing for the uutils coreutils project.

It is designed to be flexible, while providing default behaviour that aligns with GNU coreutils.

Features

  • A derive macro for declarative argument definition.
  • Automatic help generation.
  • Positional and optional arguments.
  • Automatically parsing values into Rust types.
  • Define a custom exit code on errors.
  • Automatically accept unambiguous abbreviations of long options.
  • Handles invalid UTF-8 gracefully.

When you should not use this library

The goal of this library is to make it easy to build applications that mimic the behaviour of the GNU coreutils. There are other applications that have similar behaviour, which are C application that use getopt and getopt_long. If you want to mimic that behaviour exactly, this is the library for you. If you want to write basically anything else, you should probably pick another argument parser (for example: clap).

Getting Started

Parsing with this library consists of two "phases". In the first phase, the arguments are mapped to an iterator of an enum implementing [Arguments]. The second phase is mapping these arguments onto a struct implementing [Options]. By defining your arguments this way, there is a clear divide between the public API and the internal representation of the settings of your app.

For more information on these traits, see their respective documentation:

  • [Arguments]
  • [Options]

Below is a minimal example of a full CLI application using this library.

use uutils_args::{Arguments, Options};

#[derive(Arguments)]
enum Arg {
    // The doc strings below will be part of the `--help` text
    // First we define a simple flag:
    /// Transform input text to uppercase
    #[arg("-c", "--caps")]
    Caps,

    // This option takes a value:
    /// Add exclamation marks to output
    #[arg("-e N", "--exclaim=N")]
    ExclamationMarks(u8),
}

#[derive(Default)]
struct Settings {
    caps: bool,
    exclamation_marks: u8,
    text: String,
}

// To implement `Options`, we only need to provide the `apply` method.
// The `parse` method will be automatically generated.
impl Options<Arg> for Settings {
    fn apply(&mut self, arg: Arg) {
        match arg {
            Arg::Caps => self.caps = true,
            Arg::ExclamationMarks(n) => self.exclamation_marks += n,
        }
    }
}

fn run(args: &[&str]) -> String {
    let (s, operands) = Settings::default().parse(args).unwrap();
    let text = operands.iter().map(|s| s.to_string_lossy()).collect::<Vec<_>>().join(" ");
    let mut output = if s.caps {
        text.to_uppercase()
    } else {
        text
    };
    for i in 0..s.exclamation_marks {
        output.push('!');
    }
    output
}

// The first argument is the binary name. In this example it's ignored.
assert_eq!(run(&["shout", "hello"]), "hello");
assert_eq!(run(&["shout", "-e3", "hello"]), "hello!!!");
assert_eq!(run(&["shout", "-e", "3", "hello"]), "hello!!!");
assert_eq!(run(&["shout", "--caps", "hello"]), "HELLO");
assert_eq!(run(&["shout", "-e3", "-c", "hello"]), "HELLO!!!");
assert_eq!(run(&["shout", "-e3", "-c", "hello", "world"]), "HELLO WORLD!!!");

Value parsing

To make it easier to implement [Arguments] and [Options], there is the [Value] trait, which allows for easy parsing from OsStr to any type implementing [Value]. This crate also provides a derive macro for this trait.

Examples

The following files contain examples of commands defined with uutils_args:

About

An experimental derive-based argument parser specifically for uutils

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published