hen 0.8.0

Run API collections from the command line.
use std::path::PathBuf;
use std::{collections::HashMap, fs};

use crate::parser;
use crate::{collection::Collection, request::Request};
use dialoguer::Select;

/// Prompt the user to select a request from a collection
pub fn request_prompt(collection: Collection) -> Request {
    let selections = collection
        .requests
        .iter()
        .enumerate()
        .map(|(index, req)| format!("{}. {}", index, req.description))
        .collect::<Vec<String>>();

    let selection = Select::new()
        .with_prompt("Select a request.")
        .items(&selections)
        .default(0)
        .interact()
        .unwrap();

    collection.requests[selection].clone()
}

pub fn collection_prompt(
    directory: PathBuf,
) -> Result<Collection, pest::error::Error<parser::Rule>> {
    let collection_files = scan_directory(directory);

    if collection_files.is_empty() {
        return Err(pest::error::Error::new_from_span(
            pest::error::ErrorVariant::CustomError {
                message: "No collections found in directory.".into(),
            },
            pest::Span::new("".into(), 0, 0).unwrap(),
        ));
    }

    // create a map of collection names to file paths
    // i.e., {"collection_name": "/path/to/collection_name.hen"}
    let collections = collection_files
        .into_iter()
        .map(|path| {
            let name = path.file_stem().unwrap().to_str().unwrap().to_string();
            (name, path)
        })
        .collect::<HashMap<String, PathBuf>>();

    // prompt the user to select a collection
    let selection = Select::new()
        .with_prompt("Select a collection.")
        .items(&collections.keys().collect::<Vec<&String>>())
        .default(0)
        .interact()
        .unwrap();

    // read the selected collection file
    Collection::new(collections.values().nth(selection).unwrap().clone())
}

// scan a directory for collection files
pub fn scan_directory(directory: PathBuf) -> Vec<PathBuf> {
    log::debug!("Scanning directory: {:?}", directory);

    let mut files = Vec::new();

    for entry in fs::read_dir(directory).unwrap() {
        let entry = entry.unwrap();
        let path = entry.path();

        if path.is_file()
            && path.extension().unwrap_or(std::ffi::OsStr::new("")) == std::ffi::OsStr::new("hen")
            && !path.file_name().unwrap().to_str().unwrap().starts_with(".")
        {
            files.push(path);
        }
    }

    files
}