diff options
Diffstat (limited to 'lib/etc/libimaginteraction')
-rw-r--r-- | lib/etc/libimaginteraction/Cargo.toml | 30 | ||||
l--------- | lib/etc/libimaginteraction/README.md | 1 | ||||
-rw-r--r-- | lib/etc/libimaginteraction/src/ask.rs | 350 | ||||
-rw-r--r-- | lib/etc/libimaginteraction/src/error.rs | 39 | ||||
-rw-r--r-- | lib/etc/libimaginteraction/src/filter.rs | 20 | ||||
-rw-r--r-- | lib/etc/libimaginteraction/src/lib.rs | 53 | ||||
-rw-r--r-- | lib/etc/libimaginteraction/src/readline.rs | 129 | ||||
-rw-r--r-- | lib/etc/libimaginteraction/src/result.rs | 24 | ||||
-rw-r--r-- | lib/etc/libimaginteraction/src/ui.rs | 83 |
9 files changed, 729 insertions, 0 deletions
diff --git a/lib/etc/libimaginteraction/Cargo.toml b/lib/etc/libimaginteraction/Cargo.toml new file mode 100644 index 00000000..6ed38c94 --- /dev/null +++ b/lib/etc/libimaginteraction/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "libimaginteraction" +version = "0.4.0" +authors = ["Matthias Beyer <mail@beyermatthias.de>"] + +description = "Library for the imag core distribution" + +keywords = ["imag", "PIM", "personal", "information", "management"] +readme = "../README.md" +license = "LGPL-2.1" + +documentation = "https://matthiasbeyer.github.io/imag/imag_documentation/index.html" +repository = "https://github.com/matthiasbeyer/imag" +homepage = "http://imag-pim.org" + +[dependencies] +ansi_term = "0.9.*" +clap = ">=2.17" +interactor = "0.1" +lazy_static = "0.2.*" +log = "0.3" +regex = "0.2" +toml = "^0.4" +spinner = "0.4" +rustyline = "1.0" + +libimagstore = { version = "0.4.0", path = "../../../lib/core/libimagstore" } +libimagerror = { version = "0.4.0", path = "../../../lib/core/libimagerror" } +libimagutil = { version = "0.4.0", path = "../../../lib/etc/libimagutil" } +libimagentryfilter = { version = "0.4.0", path = "../../../lib/entry/libimagentryfilter" } diff --git a/lib/etc/libimaginteraction/README.md b/lib/etc/libimaginteraction/README.md new file mode 120000 index 00000000..e7d18f69 --- /dev/null +++ b/lib/etc/libimaginteraction/README.md @@ -0,0 +1 @@ +../doc/src/05100-lib-interaction.md
\ No newline at end of file diff --git a/lib/etc/libimaginteraction/src/ask.rs b/lib/etc/libimaginteraction/src/ask.rs new file mode 100644 index 00000000..2a393d0e --- /dev/null +++ b/lib/etc/libimaginteraction/src/ask.rs @@ -0,0 +1,350 @@ +// +// imag - the personal information management suite for the commandline +// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; version +// 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// + +// functions to ask the user for data, with crate:spinner + +use std::io::stdin; +use std::io::BufRead; +use std::io::BufReader; +use std::result::Result as RResult; + +use error::InteractionError; +use error::InteractionErrorKind; +use result::Result; + +use regex::Regex; +use ansi_term::Colour::*; +use interactor::*; + +/// Ask the user for a Yes/No answer. Optionally provide a default value. If none is provided, this +/// keeps loop{}ing +pub fn ask_bool(s: &str, default: Option<bool>) -> bool { + ask_bool_(s, default, &mut BufReader::new(stdin())) +} + +fn ask_bool_<R: BufRead>(s: &str, default: Option<bool>, input: &mut R) -> bool { + lazy_static! { + static ref R_YES: Regex = Regex::new(r"^[Yy](\n?)$").unwrap(); + static ref R_NO: Regex = Regex::new(r"^[Nn](\n?)$").unwrap(); + } + + loop { + ask_question(s, false); + if match default { Some(s) => s, _ => true } { + println!(" [Yn]: "); + } else { + println!(" [yN]: "); + } + + let mut s = String::new(); + let _ = input.read_line(&mut s); + + if R_YES.is_match(&s[..]) { + return true + } else if R_NO.is_match(&s[..]) { + return false + } else if default.is_some() { + return default.unwrap(); + } + // else again... + } +} + +/// Ask the user for an unsigned number. Optionally provide a default value. If none is provided, +/// this keeps loop{}ing +pub fn ask_uint(s: &str, default: Option<u64>) -> u64 { + ask_uint_(s, default, &mut BufReader::new(stdin())) +} + +fn ask_uint_<R: BufRead>(s: &str, default: Option<u64>, input: &mut R) -> u64 { + use std::str::FromStr; + + loop { + ask_question(s, false); + + let mut s = String::new(); + let _ = input.read_line(&mut s); + + let u : RResult<u64, _> = FromStr::from_str(&s[..]); + match u { + Ok(u) => { return u; }, + Err(_) => { + if default.is_some() { + return default.unwrap(); + } // else keep looping + } + } + } +} + +/// Ask the user for a String. +/// +/// If `permit_empty` is set to false, the default value will be returned if the user inserts an +/// empty string. +/// +/// If the `permit_empty` value is true, the `default` value is never returned. +/// +/// If the `permit_multiline` is set to true, the `prompt` will be displayed before each input line. +/// +/// If the `eof` parameter is `None`, the input ends as soon as there is an empty line input from +/// the user. If the parameter is `Some(text)`, the input ends if the input line is equal to `text`. +pub fn ask_string(s: &str, + default: Option<String>, + permit_empty: bool, + permit_multiline: bool, + eof: Option<&str>, + prompt: &str) + -> String +{ + ask_string_(s, + default, + permit_empty, + permit_multiline, + eof, + prompt, + &mut BufReader::new(stdin())) +} + +fn ask_string_<R: BufRead>(s: &str, + default: Option<String>, + permit_empty: bool, + permit_multiline: bool, + eof: Option<&str>, + prompt: &str, + input: &mut R) + -> String +{ + let mut v = vec![]; + loop { + ask_question(s, true); + print!("{}", prompt); + + let mut s = String::new(); + let _ = input.read_line(&mut s); + + if permit_multiline { + if permit_multiline && eof.map_or(false, |e| e == s) { + return v.join("\n"); + } + + if permit_empty || !v.is_empty() { + v.push(s); + } + print!("{}", prompt); + } else if s.is_empty() && permit_empty { + return s; + } else if s.is_empty() && !permit_empty { + if default.is_some() { + return default.unwrap(); + } else { + continue; + } + } else { + return s; + } + } +} + +pub fn ask_select_from_list(list: &[&str]) -> Result<String> { + pick_from_list(default_menu_cmd().as_mut(), list, "Selection: ") + .map_err(|e| InteractionError::new(InteractionErrorKind::Unknown, Some(Box::new(e)))) +} + +/// Helper function to print a imag question string. The `question` argument may not contain a +/// trailing questionmark. +/// +/// The `nl` parameter can be used to configure whether a newline character should be printed +pub fn ask_question(question: &str, nl: bool) { + if nl { + println!("[imag]: {}?", Yellow.paint(question)); + } else { + print!("[imag]: {}?", Yellow.paint(question)); + } +} + +#[cfg(test)] +mod test { + use std::io::BufReader; + + use super::ask_bool_; + use super::ask_uint_; + + #[test] + fn test_ask_bool_nodefault_yes() { + let question = "Is this true"; + let default = None; + let answers = "\n\n\n\n\ny"; + + assert!(ask_bool_(question, default, &mut BufReader::new(answers.as_bytes()))); + } + + #[test] + fn test_ask_bool_nodefault_yes_nl() { + let question = "Is this true"; + let default = None; + let answers = "\n\n\n\n\ny\n"; + + assert!(ask_bool_(question, default, &mut BufReader::new(answers.as_bytes()))); + } + + #[test] + fn test_ask_bool_nodefault_no() { + let question = "Is this true"; + let default = None; + let answers = "n"; + + assert!(false == ask_bool_(question, default, &mut BufReader::new(answers.as_bytes()))); + } + + #[test] + fn test_ask_bool_nodefault_no_nl() { + let question = "Is this true"; + let default = None; + let answers = "n\n"; + + assert!(false == ask_bool_(question, default, &mut BufReader::new(answers.as_bytes()))); + } + + #[test] + fn test_ask_bool_default_no() { + let question = "Is this true"; + let default = Some(false); + let answers = "n"; + + assert!(false == ask_bool_(question, default, &mut BufReader::new(answers.as_bytes()))); + } + + #[test] + fn test_ask_bool_default_no_nl() { + let question = "Is this true"; + let default = Some(false); + let answers = "n\n"; + + assert!(false == ask_bool_(question, default, &mut BufReader::new(answers.as_bytes()))); + } + + #[test] + fn test_ask_bool_default_yes() { + let question = "Is this true"; + let default = Some(true); + let answers = "y"; + + assert!(true == ask_bool_(question, default, &mut BufReader::new(answers.as_bytes()))); + } + + #[test] + fn test_ask_bool_default_yes_nl() { + let question = "Is this true"; + let default = Some(true); + let answers = "y\n"; + + assert!(true == ask_bool_(question, default, &mut BufReader::new(answers.as_bytes()))); + } + + #[test] + fn test_ask_bool_default_yes_answer_no() { + let question = "Is this true"; + let default = Some(true); + let answers = "n"; + + assert!(false == ask_bool_(question, default, &mut BufReader::new(answers.as_bytes()))); + } + + #[test] + fn test_ask_bool_default_no_answer_yes() { + let question = "Is this true"; + let default = Some(false); + let answers = "y"; + + assert!(true == ask_bool_(question, default, &mut BufReader::new(answers.as_bytes()))); + } + + #[test] + fn test_ask_bool_default_no_without_answer() { + let question = "Is this true"; + let default = Some(false); + let answers = "\n"; + + assert!(false == ask_bool_(question, default, &mut BufReader::new(answers.as_bytes()))); + } + + #[test] + fn test_ask_bool_default_yes_without_answer() { + let question = "Is this true"; + let default = Some(true); + let answers = "\n"; + + assert!(true == ask_bool_(question, default, &mut BufReader::new(answers.as_bytes()))); + } + + #[test] + fn test_ask_uint_nodefault() { + let question = "Is this 1"; + let default = None; + let answers = "1"; + + assert!(1 == ask_uint_(question, default, &mut BufReader::new(answers.as_bytes()))); + } + + #[test] + fn test_ask_uint_default() { + let question = "Is this 1"; + let default = Some(1); + let answers = "1"; + + assert!(1 == ask_uint_(question, default, &mut BufReader::new(answers.as_bytes()))); + } + + #[test] + fn test_ask_uint_default_2_input_1() { + let question = "Is this 1"; + let default = Some(2); + let answers = "1"; + + assert!(1 == ask_uint_(question, default, &mut BufReader::new(answers.as_bytes()))); + } + + #[test] + fn test_ask_uint_default_2_noinput() { + let question = "Is this 1"; + let default = Some(2); + let answers = "\n"; + + assert!(2 == ask_uint_(question, default, &mut BufReader::new(answers.as_bytes()))); + } + + #[test] + fn test_ask_uint_default_2_several_noinput() { + let question = "Is this 1"; + let default = Some(2); + let answers = "\n\n\n\n"; + + assert!(2 == ask_uint_(question, default, &mut BufReader::new(answers.as_bytes()))); + } + + #[test] + fn test_ask_uint_default_2_wrong_input() { + let question = "Is this 1"; + let default = Some(2); + let answers = "\n\n\nasfb\nsakjf\naskjf\n-2"; + + assert!(2 == ask_uint_(question, default, &mut BufReader::new(answers.as_bytes()))); + } + +} diff --git a/lib/etc/libimaginteraction/src/error.rs b/lib/etc/libimaginteraction/src/error.rs new file mode 100644 index 00000000..1a4be7df --- /dev/null +++ b/lib/etc/libimaginteraction/src/error.rs @@ -0,0 +1,39 @@ +// +// imag - the personal information management suite for the commandline +// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; version +// 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// + +generate_error_module!( + generate_error_types!(InteractionError, InteractionErrorKind, + Unknown => "Unknown Error", + CLIError => "Error on commandline", + IdMissingError => "Commandline: ID missing", + StoreIdParsingError => "Error while parsing StoreId", + IdSelectingError => "Error while selecting id", + ConfigError => "Configuration error", + ConfigMissingError => "Configuration missing", + ConfigTypeError => "Config Type Error", + NoConfigError => "No configuration", + ReadlineHistoryFileCreationError => "Could not create history file for readline", + ReadlineError => "Readline error" + ); +); + +pub use self::error::InteractionError; +pub use self::error::InteractionErrorKind; +pub use self::error::MapErrInto; + diff --git a/lib/etc/libimaginteraction/src/filter.rs b/lib/etc/libimaginteraction/src/filter.rs new file mode 100644 index 00000000..5869a529 --- /dev/null +++ b/lib/etc/libimaginteraction/src/filter.rs @@ -0,0 +1,20 @@ +// +// imag - the personal information management suite for the commandline +// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; version +// 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// + +// A filter which uses crate:interactor to filter entries diff --git a/lib/etc/libimaginteraction/src/lib.rs b/lib/etc/libimaginteraction/src/lib.rs new file mode 100644 index 00000000..67c61cf4 --- /dev/null +++ b/lib/etc/libimaginteraction/src/lib.rs @@ -0,0 +1,53 @@ +// +// imag - the personal information management suite for the commandline +// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; version +// 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// + +#![deny( + non_camel_case_types, + non_snake_case, + path_statements, + trivial_numeric_casts, + unstable_features, + unused_allocation, + unused_import_braces, + unused_imports, + unused_mut, + unused_qualifications, + while_true, +)] + +extern crate spinner; +extern crate interactor; +extern crate ansi_term; +#[macro_use] extern crate lazy_static; +extern crate regex; +extern crate clap; +extern crate toml; +extern crate rustyline; + +extern crate libimagentryfilter; +extern crate libimagstore; +extern crate libimagutil; +#[macro_use] extern crate libimagerror; + +pub mod ask; +pub mod error; +pub mod filter; +pub mod result; +pub mod ui; + diff --git a/lib/etc/libimaginteraction/src/readline.rs b/lib/etc/libimaginteraction/src/readline.rs new file mode 100644 index 00000000..7b998dd0 --- /dev/null +++ b/lib/etc/libimaginteraction/src/readline.rs @@ -0,0 +1,129 @@ +// +// imag - the personal information management suite for the commandline +// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; version +// 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// + +use error::InteractionErrorKind as IEK; +use error::MapErrInto; + +use toml::Value; + +use rustyline::{Config, Editor}; + +pub struct Readline { + editor: Editor, + history_file: PathBuf, + prompt: String, +} + +impl Readline { + + pub fn new(rt: &Runtime) -> Result<Readline> { + let cfg = try!(rt.config().ok_or(IEK::NoConfigError)); + + let c = cfg.config(); + let histfile = try!(c.lookup("ui.cli.readline_history_file").ok_or(IEK::ConfigError)); + let histsize = try!(c.lookup("ui.cli.readline_history_size").ok_or(IEK::ConfigError)); + let histigndups = try!(c.lookup("ui.cli.readline_history_ignore_dups").ok_or(IEK::ConfigError)); + let histignspace = try!(c.lookup("ui.cli.readline_history_ignore_space").ok_or(IEK::ConfigError)); + let prompt = try!(c.lookup("ui.cli.readline_prompt").ok_or(IEK::ConfigError)); + + let histfile = try!(match histfile { + Value::String(s) => PathBuf::from(s), + _ => Err(IEK::ConfigTypeError.into_error()) + .map_err_into(IEK::ConfigError) + .map_err_into(IEK::ReadlineError) + }); + + let histsize = try!(match histsize { + Value::Integer(i) => i, + _ => Err(IEK::ConfigTypeError.into_error()) + .map_err_into(IEK::ConfigError) + .map_err_into(IEK::ReadlineError) + }); + + let histigndups = try!(match histigndups { + Value::Boolean(b) => b, + _ => Err(IEK::ConfigTypeError.into_error()) + .map_err_into(IEK::ConfigError) + .map_err_into(IEK::ReadlineError) + }); + + let histignspace = try!(match histignspace { + Value::Boolean(b) => b, + _ => Err(IEK::ConfigTypeError.into_error()) + .map_err_into(IEK::ConfigError) + .map_err_into(IEK::ReadlineError) + }); + + let prompt = try!(match prompt { + Value::String(s) => s, + _ => Err(IEK::ConfigTypeError.into_error()) + .map_err_into(IEK::ConfigError) + .map_err_into(IEK::ReadlineError) + }); + + let config = Config::builder(). + .max_history_size(histsize) + .history_ignore_dups(histigndups) + .history_ignore_space(histignspace) + .build(); + + let mut editor = Editor::new(config); + + if !histfile.exists() { + let _ = try!(File::create(histfile.clone()) + .map_err_into(IEK::ReadlineHistoryFileCreationError)); + } + + let _ = try!(editor.load_history(&histfile).map_err_into(ReadlineError)); + + Ok(Readline { + editor: editor, + history_file: histfile, + prompt: prompt, + }) + } + + pub fn read_line(&mut self) -> Result<Option<String>> { + use rustyline::ReadlineError; + use libimagutil::warn_result::*; + + match self.editor.readline(&self.prompt) { + Ok(line) => { + self.editor.add_history_line(&line); + self.editor + .save_history(&self.history_file) + .map_warn_err_str(|e| format!("Could not save history file {} -> {:?}", + self.history_file.display(), e)); + return line; + }, + Err(ReadlineError::Interrupted) => { + info!("CTRL-C"); + Ok(None) + }, + Err(ReadlineError::Eof) => { + info!("CTRL-D"); + Ok(None) + }, + Err(err) => Err(err).map_err_into(ReadlineError), + + } + } + +} + diff --git a/lib/etc/libimaginteraction/src/result.rs b/lib/etc/libimaginteraction/src/result.rs new file mode 100644 index 00000000..8eeaf47b --- /dev/null +++ b/lib/etc/libimaginteraction/src/result.rs @@ -0,0 +1,24 @@ +// +// imag - the personal information management suite for the commandline +// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; version +// 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// + +use std::result::Result as RResult; + +use error::InteractionError; + +pub type Result<T> = RResult<T, InteractionError>; diff --git a/lib/etc/libimaginteraction/src/ui.rs b/lib/etc/libimaginteraction/src/ui.rs new file mode 100644 index 00000000..49c4619d --- /dev/null +++ b/lib/etc/libimaginteraction/src/ui.rs @@ -0,0 +1,83 @@ +// +// imag - the personal information management suite for the commandline +// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; version +// 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// + +use std::path::PathBuf; + +use clap::{Arg, ArgMatches}; + +use libimagstore::storeid::StoreId; +use libimagerror::into::IntoError; + +use result::Result; +use error::MapErrInto; +use error::InteractionErrorKind as IEK; + +pub fn id_argument<'a, 'b>() -> Arg<'a, 'b> { + Arg::with_name(id_argument_name()) + .short(id_argument_short()) + .long(id_argument_long()) + .takes_value(true) + .multiple(true) + .help("Specify the Store-Id") +} + +pub fn id_argument_name() -> &'static str { + "id-argument" +} + +pub fn id_argument_short() -> &'static str { + "i" +} + +pub fn id_argument_long() -> &'static str { + "id" +} + +pub fn get_id(matches: &ArgMatches) -> Result<Vec<StoreId>> { + matches + .values_of(id_argument_name()) + .ok_or(IEK::IdMissingError.into_error()) + .map_err_into(IEK::CLIError) + .and_then(|vals| { + vals.into_iter() + .fold(Ok(vec![]), |acc, elem| { + acc.and_then(|mut v| { + let elem = StoreId::new_baseless(PathBuf::from(String::from(elem))); + let elem = try!(elem.map_err_into(IEK::StoreIdParsingError)); + v.push(elem); + Ok(v) + }) + }) + }) +} + +pub fn get_or_select_id(matches: &ArgMatches, store_path: &PathBuf) -> Result<Vec<StoreId>> { + use interactor::{pick_file, default_menu_cmd}; + + match get_id(matches).map_err_into(IEK::IdSelectingError) { + Ok(v) => Ok(v), + Err(_) => { + let path = store_path.clone(); + let p = try!(pick_file(default_menu_cmd, path).map_err_into(IEK::IdSelectingError)); + let id = try!(StoreId::new_baseless(p).map_err_into(IEK::StoreIdParsingError)); + Ok(vec![id]) + }, + } +} + |