unicode-cli 0.1.0

Unicode character lookup and inspection tool.
Documentation
use clap::{App, AppSettings, Arg, SubCommand, ArgMatches};
use unic_ucd::*;
use unicode_cli::*;
use regex::RegexBuilder;
use log::*;

fn main() {
    let matches = App::new(env!("CARGO_PKG_NAME"))
        .setting(AppSettings::SubcommandRequiredElseHelp)
        .setting(AppSettings::InferSubcommands)
        .version(env!("CARGO_PKG_VERSION"))
        .author(env!("CARGO_PKG_AUTHORS"))
        .about(env!("CARGO_PKG_DESCRIPTION"))
        .arg(
            Arg::with_name("verbose")
                .short("v")
                .multiple(true)
                .help("Output more information."),
        )
        .subcommand(
            SubCommand::with_name("compose")
                .alias("c")
                .about("Compose a string from unicode codepoins.")
                .arg(
                    Arg::with_name("NAME")
                        .required(true)
                        .multiple(true)
                        .help("Name of a unicode codepoint"),
                ),
        )
        .subcommand(
            SubCommand::with_name("inspect")
                .about("Inspect a unicode string.")
                .arg(
                    Arg::with_name("STRING")
                        .required(true)
                        .help("String containing unicode data."),
                )
                .arg(
                    Arg::with_name("long")
                        .multiple(true)
                        .short("l")
                        .long("long")
                        .help("Output more detail."),
                ),
        )
        .subcommand(
            SubCommand::with_name("info")
                .about("Print information about a unicode character.")
                .arg(
                    Arg::with_name("CHARACTER")
                        .required(true)
                        .help("Unicode character."),
                ),
        )
        .subcommand(
            SubCommand::with_name("search")
                .about("Search for unicode characters by name or properties.")
                .arg(
                    Arg::with_name("REGEX")
                        .required(true)
                        .help("Unicode character."),
                )
                .arg(
                    Arg::with_name("long")
                        .multiple(true)
                        .short("l")
                        .long("long")
                        .help("Output more detail."),
                ),
        )
        .subcommand(
            SubCommand::with_name("list")
                .alias("ls")
                .about("List unicode characters")
                .arg(
                    Arg::with_name("long")
                        .short("l")
                        .long("long")
                        .help("Print details for each character."),
                )
                .arg(
                    Arg::with_name("all")
                        .short("a")
                        .long("all")
                        .help("Print all characters."),
                )
                .arg(
                    Arg::with_name("BLOCK")
                        .help("Which block to display."),
                ),
        )
        .get_matches();

    stderrlog::new()
	.module(module_path!())
	.quiet(matches.is_present("quiet"))
	.timestamp(stderrlog::Timestamp::Second)
	.verbosity(matches.occurrences_of("verbose") as usize)
	.init()
	.unwrap();

    match matches.subcommand() {
        ("compose", Some(args)) => compose(args),
        ("inspect", Some(args)) => inspect(args),
        ("info", Some(args)) => info(args),
        ("list", Some(args)) => list(args),
        ("search", Some(args)) => search(args),
        _ => unreachable!(),
    }
}

fn compose(args: &ArgMatches) {
    let mut composed = String::new();

    if let Some(values) = args.values_of("NAME") {
        for name in values {
            if let Some(point) = parse_scalar_value(name) {
                composed.push(point);
            } else {
                println!("{} is not a name of a unicode code point.", name);
            }
        }
    } else {
        println!("can't extract values of NAME");
    }

    println!("{}", composed);
}

fn inspect(args: &ArgMatches) {
    let composed = args.value_of("STRING").unwrap();
    let charinfo = CharInfo::new(args.occurrences_of("long") as usize + 2);

    for chr in composed.chars() {
        charinfo.display(chr);
    }
}

fn info(args: &ArgMatches) {
    let charinfo = CharInfo::new(9);
    let composed = args.value_of("CHARACTER").unwrap();

    if let Some(c) = parse_scalar_value(composed) {
        charinfo.display(c);
    } else {
        println!("error: can't parse {}.", composed);
    }
}

fn list(args: &ArgMatches) {
    if let Some(block) = args.value_of("BLOCK") {
        if let Some(block) = BlockIter::default().find(|b| b.name == block) {
            println!("{}", block.name);

            for c in block.range {
                print!("{}", c);
            }

            println!("");
        } else {
            println!("error: can't find block {}", block);
        }
    } else {
        for block in BlockIter::default() {
            println!("{}", block.name);
        }
    }
}

fn search(args: &ArgMatches) {
    let regex = args.value_of("REGEX").unwrap();
    let regex = RegexBuilder::new(regex)
        .case_insensitive(true)
        .build()
        .unwrap();

    let res = unicode_cli::search(&regex);
    let charinfo = CharInfo::new(args.occurrences_of("long") as usize);

    for c in res.iter() {
        charinfo.display(*c);
    }
}