use std::fs;
use std::path::PathBuf;
use crate::collection::Collection;
use crate::error::{HenError, HenErrorKind, HenResult};
use dialoguer::Select;
pub fn request_prompt(collection: &Collection) -> usize {
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();
selection
}
pub fn collection_prompt(directory: PathBuf) -> HenResult<Collection> {
let collection_files = scan_directory(directory.clone())?;
if collection_files.is_empty() {
return Err(
HenError::new(HenErrorKind::Prompt, "No collections found in directory")
.with_detail(format!("Directory: {}", directory.display())),
);
}
let mut collections = collection_files
.into_iter()
.map(|path| {
let name = path
.file_stem()
.unwrap_or_default()
.to_str()
.unwrap_or_default()
.to_string();
(name, path)
})
.collect::<Vec<(String, PathBuf)>>();
collections.sort_by(|a, b| a.0.cmp(&b.0));
let names = collections
.iter()
.map(|(name, _)| name.clone())
.collect::<Vec<String>>();
let selection = Select::new()
.with_prompt("Select a collection.")
.items(&names)
.default(0)
.interact()
.map_err(|err| {
HenError::new(HenErrorKind::Prompt, "Collection selection cancelled")
.with_detail(err.to_string())
})?;
let (_, path) = collections.get(selection).ok_or_else(|| {
HenError::new(
HenErrorKind::Prompt,
"Selected collection index is out of range",
)
})?;
Collection::new(path.clone())
}
pub fn scan_directory(directory: PathBuf) -> HenResult<Vec<PathBuf>> {
log::debug!("Scanning directory: {:?}", directory);
let entries = fs::read_dir(&directory).map_err(|err| {
HenError::new(
HenErrorKind::Io,
format!("Failed to read directory {}", directory.display()),
)
.with_detail(err.to_string())
})?;
let mut files = Vec::new();
for entry in entries {
let entry = entry.map_err(|err| {
HenError::new(HenErrorKind::Io, "Failed to read directory entry")
.with_detail(err.to_string())
})?;
let path = entry.path();
if path.is_file()
&& path.extension().unwrap_or(std::ffi::OsStr::new("")) == std::ffi::OsStr::new("hen")
&& !path
.file_name()
.and_then(|name| name.to_str())
.unwrap_or_default()
.starts_with('.')
{
files.push(path);
}
}
Ok(files)
}