Fast Paced intro to your First Standout Based Command

This is a terse and direct how to for more experienced developers or at least the ones in a hurry. It skimps rationale, design and other useful bits you can read from the longer form version

Prerequisites

A cli app, that uses clap for arg parsing. A command fucntion that is pure logic, that is , returns the result, and does not print to stdout or format output.

For this guide's purpose we'll use a ficticious "list" command of our todo list manager

The Core: A pure function logic handler

The logic handler: receives parsed cli args, and returns a serializable data structure:

#![allow(unused)]
fn main() {
    pub fn list(matches: &ArgMatches, _ctx: &CommandContext) -> HandlerResult<TodoResult> {}
}

Making it oustanding

1. The File System

Create a templates/list.jinja and styles/default.css:

    src/
        ├── handlers.rs         # where list it
        ├── templates/          # standout will match templates name against rel. paths from temp root, here
            ├── list.jinja      # the template to render list, name matched against the command name
        ├── styles/             #  likewise for themes, this sets a theme called "default"
            ├── default.css     # the default style for the command, filename will be the theme name

2. Define your styles

    .done {
        text-decoration: line-through;
        color: gray;
    }
    .pending {
        font-weight: bold;
        color: white;
    }
    .index {
        color: yellow;
    }

3. Write your template

    {% if message %}
        [message]{{ message }} [/message]
    {% endif %}
    {% for todo in todos %}
        [index]{{ loop.index }}.[/index] [{{ todo.status }}]{{ todo.title }}[/{{ todo.status }}]
    {% endfor %}

4. Putting it all together

Configure the app:

#![allow(unused)]
fn main() {
    let app = App::builder()
        .templates(embed_templates!("src/templates"))    //  Sets the root template path, hot relead for dev, embeded in release
        .styles(embed_styles!("src/styles"))                       //  Likewise the styles root
        .default_theme("default")                                       // Use styles/default.css or default.yaml
        .commands(Commands::dispatch_config())          // Register handlers from derive macro
    .build()?;
}

Connect your logic to a command name and template :

#![allow(unused)]
fn main() {
    #[dispatch(handlers = handlers)]
    pub enum Commands {
          ...
          list,
    }
}

And finally, run in main, the autodispatcher:

#![allow(unused)]
fn main() {
    match app.run(Cli::command(), std::env::args()) {
        // If you've got other commands on vanilla manual dispatch, call it for unported commands
        RunResult::NoMatch(matches) => legacy_dispatch(matches),  // Your existing handler
    }
}