gcd-cli 0.2.1

gcd-cli tools for managing and using GCD. GCD stands for GitChangeDirectory, as it primary goal is to quickly change between git project folders.
Documentation
use console::Key::*;
use std::{io, sync::{Arc, atomic::{AtomicBool, Ordering}}};

use clap::{crate_authors, crate_version, App, Arg};

use gcd_cli::config::Config;
use gcd_cli::db::Database;
use gcd_cli::inputhandler::InputHandler;
use gcd_cli::outputhandler::OutputHandler;
use gcd_cli::scriptfile::ScriptFile;
use gcd_cli::constants::*;

fn main() -> io::Result<()> {
    let running = Arc::new(AtomicBool::new(true));
    let r = running.clone();

    ctrlc::set_handler( move || {
        r.store(false, Ordering::SeqCst);
    }).expect("Error setting Ctrl-C handler");

    let config = Config::new();
    let default_projects_dir = config.projects_dir();
    let default_script_file = config.script_file();
    let default_database_file = config.database_file();

    let matches = App::new("gcd-select")
        .version(&crate_version!()[..])
        .author(crate_authors!())
        .about("Select a project.")
        .arg(
            Arg::with_name(PROJECTS_DIR)
                .short("p")
                .long(PROJECTS_DIR)
                .env(PROJECTS_DIR)
                .value_name(PROJECTS_DIR_VALUE_NAME)
                .default_value(&default_projects_dir)
                .help(PROJECTS_DIR_HELP)
                .required(false)
                .takes_value(true),
        )
        .arg(
            Arg::with_name(SCRIPT_FILE)
                .short("s")
                .long(SCRIPT_FILE)
                .env(SCRIPT_FILE)
                .value_name(SCRIPT_FILE_VALUE_NAME)
                .default_value(&default_script_file)
                .help(SCRIPT_FILE_HELP)
                .required(false)
                .takes_value(true),
        )
        .arg(
            Arg::with_name(DATABASE_FILE)
                .short("d")
                .long(DATABASE_FILE)
                .env(DATABASE_FILE)
                .value_name(DATABASE_FILE_VALUE_NAME)
                .default_value(&default_database_file)
                .help(DATABASE_FILE_HELP)
                .required(false)
                .takes_value(true),
        )
        .arg(
            Arg::with_name(EXEC_COMMAND)
                .long(EXEC_COMMAND)
                .value_name(EXEC_COMMAND_VALUE_NAME)
                .help(EXEC_COMMAND_HELP)
                .required(false)
                .takes_value(true)
                .multiple(true)
                .value_delimiter(" ")
                .value_terminator(";"),
        )
        .arg(Arg::with_name(FIND).help(FIND_HELP))
        .get_matches();

    let script_file = matches
        .value_of(SCRIPT_FILE)
        .unwrap_or(&default_script_file)
        .to_string();
    let database_file = matches
        .value_of(DATABASE_FILE)
        .unwrap_or(&default_database_file)
        .to_string();
    let projects_dir = matches
        .value_of(PROJECTS_DIR)
        .unwrap_or(&default_projects_dir)
        .to_string();
    let param = matches.value_of(FIND).unwrap_or("");
    let mut input = InputHandler::new(&param);
    let mut output = OutputHandler::new(projects_dir);
    let scriptfile = ScriptFile::new(script_file);
    let database = Database::new(database_file);

    println!("");

    if param.len() != 0 {
        let count = output.show_results(database.find(input.line.clone()))?;
        if count == 1 {
            if let Some(result) = output.get_selected() {
                if let Some(command) = matches.values_of(EXEC_COMMAND) {
                    scriptfile
                        .write_cd_and_exec(result, command.map(|c| c.to_string()).collect())?;
                } else {
                    scriptfile.write_cd_only(result)?;
                }
                return Ok(());
            }
        }
    } else {
        let _ = output.show_results(database.find(".*".to_string()));
    }
    while running.load(Ordering::SeqCst) {
        match input.read_key()? {
            Enter => {
                if let Some(result) = output.get_selected() {
                    database.increment(result.clone());
                    if let Some(command) = matches.values_of(EXEC_COMMAND) {
                        scriptfile
                            .write_cd_and_exec(result, command.map(|c| c.to_string()).collect())?;
                    } else {
                        scriptfile.write_cd_only(result)?;
                    }
                }
                break;
            }
            ArrowUp => {
                output.up()?;
            }
            ArrowDown => {
                output.down()?;
            }
            Escape => {
                break;
            }
            _ => {
                output.show_results(database.find(input.line.clone()))?;
            }
        }
    }
    output.clear_results()?;
    Ok(())
}