use error::{GrafenCliError, Result, UIErrorKind, UIResult};
use grafen::coord::Coord;
use grafen::describe::{describe_list_short, describe_list, Describe};
use dialoguer::{Input, Select};
use std::str::FromStr;
pub type MenuResult = Result<Option<String>>;
pub fn get_value_from_user<T: FromStr>(description: &str) -> UIResult<T> {
Input::new(description)
.interact()?
.trim()
.parse::<T>()
.map_err(|_| UIErrorKind::from("could not parse a value"))
}
pub fn get_position_from_user(default: Option<&str>) -> UIResult<Coord> {
let mut input = Input::new("Position (x y z nm)");
if let Some(string) = default {
input.default(&string);
}
Coord::from_str(&input.interact()?).map_err(|err| UIErrorKind::from(&err))
}
macro_rules! create_menu {
(
@pre: $topmatter:tt;
$( $command:ident, $text:expr => $closure:block ),+
) => {
#[derive(Clone, Copy, Debug)]
enum _ScopedMenu { $( $command ),* }
let (commands, item_texts) = create_menu_items![
$( (_ScopedMenu::$command, $text) ),*
];
loop {
$topmatter
let command = select_command(item_texts, commands)?;
let result: MenuResult = match command { $( _ScopedMenu::$command => $closure ),* };
match result {
Ok(Some(msg)) => eprintln!("{}", msg),
Ok(None) => (),
Err(msg) => eprintln!("{}", msg),
}
eprintln!("");
}
}
}
macro_rules! create_menu_items {
(
$(($command:path, $text:expr)),+
) => {
(
&[
$( $command ),*
],
&[
$( $text ),*
]
)
}
}
pub fn select_command<T: Copy>(item_texts: &[&str], commands: &[T]) -> UIResult<T> {
let index = Select::new()
.default(0)
.items(&item_texts[..])
.interact()?;
Ok(commands[index])
}
pub fn select_item<'a, T: Describe>(items: &'a [T], header: Option<&str>) -> UIResult<&'a T> {
if let Some(h) = header {
eprintln!("{}:", h);
}
select_item_index(items, 0).map(|index| &items[index])
}
pub fn select_item_index<T: Describe>(items: &[T], default: usize) -> UIResult<usize> {
let item_texts: Vec<_> = items.iter().map(|item| item.describe_short()).collect();
select_string(&item_texts, default)
}
fn select_string(items: &[String], default: usize) -> UIResult<usize> {
let mut select = Select::new();
for item in items {
select.item(&item);
}
select.item("(Return)");
let index = select.default(default).interact()?;
if index < items.len() {
Ok(index)
} else {
Err(UIErrorKind::Abort)
}
}
pub fn remove_items<T: Describe>(item_list: &mut Vec<T>) -> Result<()> {
let mut last_index = 0;
loop {
match select_item_index(&item_list, last_index) {
Ok(index) => {
item_list.remove(index);
last_index = index;
},
Err(UIErrorKind::Abort) => {
return Ok(());
},
Err(err) => {
return Err(GrafenCliError::from(err));
},
}
}
}
pub fn reorder_list<T: Describe>(item_list: &mut Vec<T>) -> Result<()> {
let mut last_index = 0;
loop {
let mut item_texts: Vec<_> = item_list.iter().map(|item| item.describe_short()).collect();
match select_string(&item_texts, last_index) {
Ok(i) => {
item_texts[i].insert_str(0, " *");
match select_string(&item_texts, i) {
Ok(j) => {
item_list.swap(i, j);
last_index = j;
},
Err(UIErrorKind::Abort) => {
last_index = 0;
},
Err(err) => {
return Err(GrafenCliError::from(err));
},
}
},
Err(UIErrorKind::Abort) => {
return Ok(());
},
Err(err) => {
return Err(GrafenCliError::from(err));
},
}
}
}
pub fn print_description<T: Describe>(object: &T) {
eprintln!("{}", object.describe());
}
pub fn print_list_description_short<T: Describe>(description: &str, list: &[T]) {
eprintln!("{}", describe_list_short(description, list));
}
pub fn print_list_description<T: Describe>(description: &str, list: &[T]) {
eprintln!("{}", describe_list(description, list));
}
#[derive(Clone, Copy, Debug)]
pub enum YesOrNo {
Yes,
No,
}