My handy Rust CLI

A week or two ago I started on creating a rust program that would accomplish two things:

  1. Improve my understanding of the package management system for Rust. More specifically, I wanted to understand how to organize modules a little bit better
  2. Create something that I could use to create challenges for myself using an automated and randomized method

I worked on it for a while and then get hung up on the specifics for parsing command line arguments. The approaches I thought about either seemed way too complicated, or were way too hacky to really be proud of writing them. I let the project for a sit for a little bit.

After some time, I realized that I could probably just outsource the parsing logic. Given that I was, at the time, the furthest from the first person ever needing to parse command line arguments, there had to be a library for it.

I was indeed correct and found clap. This library turned my project from a headache into a neat little organized oasis. More on that later. First, I’m gonna describe how the program works.

How the program works

The utility will look at a set of text files that you give it and create a set of challenges. For example, you could have some text files that describe pixel art challenges you can try.


Draw a house
Draw a mountain
Draw a bear


at 128x64 pixels
at 256x128 pixels
at 64x64 pixels


with Midnight Ablaze Palette
with Oil 6 Palette
with Apollo Palette
with Spanish sunset palette

With these files in the root directory, you can run something like this:

cargo run -- -f theme.txt size.txt palette.txt -c 5

This will…

  1. Look through the listed files indicated by -f
  2. Print out the challenges’ details in the order they were listed, randomly picking an entry in each file. This will be done five times, as indicated by the -c 5 argument. --count can also be used instead.

One example output could be the following:

Draw a house at 64x64 pixels with Midnight Ablaze Palette 
Draw a mountain at 256x128 pixels with Oil 6 Palette
Draw a house at 128x64 pixels with Apollo Palette
Draw a bear at 128x64 pixels with Midnight Ablaze Palette
Draw a mountain at 256x128 pixels with Midnight Ablaze Palette

Now I have 5 challenges for pixel art I can work with! This is great for generating ideas, especially if you fill a text file with a million different ideas, then also fill another text file with a million other ideas to combine with it.

This could also be good for quizzing yourself, learning a new language, inspiration, you name it.

Anyway, so on the topic of my code being a neat organized oasis, Here is the parser and how it is used by my main program:

Parser & friends

use clap::Parser;

#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
pub struct Args {
    #[arg(short, long, num_args = 1.., required = true)]
    pub files: Vec<String>,

    #[arg(short, long, default_value_t = String::from(" "))]
    pub separator: String,

    #[arg(short, long, default_value_t = 1)]
    pub count: i32

use chalgen::{file_processor, cli};
use clap::Parser;

fn main() {
    let args = cli::Args::parse();

The code above does the following:

  1. Define the command line arguments for the library to look for and what characteristics they should have (
  2. Pass configuration that was gathered from command line arguments to the program doing the actual work (

To provide some context for, the following keywords are important:

  1. short: the flag can be represented by the first letter of the property name. e.g. files can be referred to as -f when calling the command line utility
  2. long: Effectively the same sort of option as short, except the flag is able to be represented by its full name. e.g. count can be represented as --count when calling the command line utility
  3. default_value_t: Essentially, this is what the flag will be set to if it is not mentioned when calling the command line utility
  4. num_args: How many arguments that are expected from the flag. In this case, I use it once with files and the number of arguments is represented by 1.. which essentially means “at least 1.” I specify it like this to provide the user the ability to provide any number of files they want
  5. required: The flag must be used. In this case, the files flag is required

All of the restrictions and allowances defined above are automatically enforced by the clap library. This is a huge weight off my back and allowed me to focus on the actual program (AKA the file_processor::output_challenges(args) part of the code that I don’t show.

Anyway, that’s about it. Here is the repository for the curious! Stay safe and make good choices.