Getting started

Cmdr is a library for writing simple interactive command line applications. Instead of trying to explain what I mean by that, let's just write one.

Start a new project;

> cargo new my_cli_app

Add a dependency to cmdr to Cargo.toml;

[dependencies]
cmdr = "0.3.11"

and enter the following code in src/main.rs

use cmdr::*;

/// Example scope that implements two commands, greet and quit
struct GreeterScope {}

#[cmdr]
impl GreeterScope {
    /// Cmdr command to greet someone. Takes one parameter and prints a greeting
    #[cmd]
    fn greet(&self, args: &[String]) -> CommandResult {
        println!("Hello {}", args[0]);
        Ok(Action::Done)
    }

    /// Cmdr command to quit the application by returning CommandResult::Quit
    #[cmd]
    fn quit(&self, _args: &[String]) -> CommandResult {
        println!("Quitting");
        Ok(Action::Done)
    }
}

/// Main function that creates the scope and starts a command loop for it
fn main() cmdr::Result<()> {
    cmd_loop(&mut GreeterScope {})?;
    Ok(())
}

If you run this code with

> cargo run

It will present you with a command prompt > and a blinking cursor. Typing

> help

will tell you what commands are available. You can greet someone by typing greet followed by the name of the person you'd like to extend a greeting to. You can exit the application by typing quit.

The code is pretty straight forward. We define a type to keep the state for our application. Cmdr calls this the scope and it is used to keep the state during execution of this part of the application. You can have multiple scopes during the lifetime of the application if you want.

The scope can be any type you define.

A type can be made into a scope by decorating an impl block on it with the #[cmdr] macro. This will implement the Scope trait for this type so it can be run. The '#[cmdr]' macro works similarly to derive macro's on structs and enums. But because it works on methods implemented on a type it should be used to decorate an impl block instead of the main type.

Commands can be defined on a scope by implementing methods in the scope's impl block. And decorating them with #[cmd]. These methods need to take a reference or mutable reference to self and a reference to a String slice. And they need to return a CommandResult. Just like the greet command in our example;


#![allow(unused)]
fn main() {
#[cmd]`
fn greet_method(&self, args: &[String]) -> CommandResult {
}

The arguments to the command will be passed as Strings in the args string slice so they can be parsed by the command. The command can specify one of a set of things to happen after the command by returning different CommandResults. Usually this will be ``CommandResult::OkBut thequit command for example tells cmdr to quit the application by returningCommandResult::Quit`

Now all that is left for us to do is to start our GreeterScope and start handling commands. We can do this in the main function;

fn main() {
    cmd_loop(&mut GreeterScope {});
}