Add multi selection

This commit is contained in:
Ferran Basora 2019-12-13 22:02:29 +01:00
parent 8ae9fa9137
commit 741a5bd927
2 changed files with 53 additions and 16 deletions

View File

@ -64,6 +64,12 @@ fn app_args<'a>() -> clap::ArgMatches<'a> {
.long("select-bg-color") .long("select-bg-color")
.default_value("black"), .default_value("black"),
) )
.arg(
Arg::with_name("multi")
.help("Enable multi-selection")
.long("multi")
.short("m"),
)
.arg( .arg(
Arg::with_name("reverse") Arg::with_name("reverse")
.help("Reverse the order for assigned hints") .help("Reverse the order for assigned hints")
@ -105,6 +111,7 @@ fn main() {
let format = args.value_of("format").unwrap(); let format = args.value_of("format").unwrap();
let alphabet = args.value_of("alphabet").unwrap(); let alphabet = args.value_of("alphabet").unwrap();
let position = args.value_of("position").unwrap(); let position = args.value_of("position").unwrap();
let multi = args.is_present("multi");
let reverse = args.is_present("reverse"); let reverse = args.is_present("reverse");
let unique = args.is_present("unique"); let unique = args.is_present("unique");
let contrast = args.is_present("contrast"); let contrast = args.is_present("contrast");
@ -136,6 +143,7 @@ fn main() {
let selected = { let selected = {
let mut viewbox = view::View::new( let mut viewbox = view::View::new(
&mut state, &mut state,
multi,
reverse, reverse,
unique, unique,
contrast, contrast,
@ -151,19 +159,21 @@ fn main() {
viewbox.present() viewbox.present()
}; };
if let Some((text, upcase)) = selected { if !selected.is_empty() {
for (text, upcase) in selected.iter() {
let mut output = format.to_string(); let mut output = format.to_string();
let upcase_value = if upcase { let upcase_value = if *upcase { "true" } else { "false" };
"true"
} else {
"false"
};
output = str::replace(&output, "%U", upcase_value); output = str::replace(&output, "%U", upcase_value);
output = str::replace(&output, "%H", text.as_str()); output = str::replace(&output, "%H", text.as_str());
if multi {
println!("{}", output);
} else {
print!("{}", output); print!("{}", output);
}
}
} else { } else {
::std::process::exit(1); ::std::process::exit(1);
} }

View File

@ -7,6 +7,7 @@ use std::default::Default;
pub struct View<'a> { pub struct View<'a> {
state: &'a mut state::State<'a>, state: &'a mut state::State<'a>,
skip: usize, skip: usize,
multi: bool,
reverse: bool, reverse: bool,
unique: bool, unique: bool,
contrast: bool, contrast: bool,
@ -22,6 +23,7 @@ pub struct View<'a> {
impl<'a> View<'a> { impl<'a> View<'a> {
pub fn new( pub fn new(
state: &'a mut state::State<'a>, state: &'a mut state::State<'a>,
multi: bool,
reverse: bool, reverse: bool,
unique: bool, unique: bool,
contrast: bool, contrast: bool,
@ -36,6 +38,7 @@ impl<'a> View<'a> {
View { View {
state: state, state: state,
skip: 0, skip: 0,
multi: multi,
reverse: reverse, reverse: reverse,
unique: unique, unique: unique,
contrast: contrast, contrast: contrast,
@ -71,7 +74,7 @@ impl<'a> View<'a> {
text text
} }
pub fn present(&mut self) -> Option<(String, bool)> { pub fn present(&mut self) -> Vec<(String, bool)> {
let mut rustbox = match RustBox::init(Default::default()) { let mut rustbox = match RustBox::init(Default::default()) {
Result::Ok(v) => v, Result::Ok(v) => v,
Result::Err(e) => panic!("{}", e), Result::Err(e) => panic!("{}", e),
@ -88,6 +91,7 @@ impl<'a> View<'a> {
.unwrap() .unwrap()
.clone(); .clone();
let mut selected; let mut selected;
let mut chosen = vec![];
self.skip = if self.reverse { matches.len() - 1 } else { 0 }; self.skip = if self.reverse { matches.len() - 1 } else { 0 };
@ -167,10 +171,20 @@ impl<'a> View<'a> {
match rustbox.poll_event(false) { match rustbox.poll_event(false) {
Ok(rustbox::Event::KeyEvent(key)) => match key { Ok(rustbox::Event::KeyEvent(key)) => match key {
Key::Esc => { Key::Esc => {
if self.multi && !typed_hint.is_empty() {
typed_hint.clear();
} else {
break; break;
} }
}
Key::Enter => match matches.iter().enumerate().find(|&h| h.0 == self.skip) { Key::Enter => match matches.iter().enumerate().find(|&h| h.0 == self.skip) {
Some(hm) => return Some((hm.1.text.to_string(), false)), Some(hm) => {
chosen.push((hm.1.text.to_string(), false));
if !self.multi {
return chosen;
}
}
_ => panic!("Match not found?"), _ => panic!("Match not found?"),
}, },
Key::Up => { Key::Up => {
@ -186,6 +200,10 @@ impl<'a> View<'a> {
self.next(matches.len() - 1); self.next(matches.len() - 1);
} }
Key::Char(ch) => { Key::Char(ch) => {
if ch == ' ' && self.multi {
return chosen;
}
let key = ch.to_string(); let key = ch.to_string();
let lower_key = key.to_lowercase(); let lower_key = key.to_lowercase();
@ -195,9 +213,17 @@ impl<'a> View<'a> {
.iter() .iter()
.find(|mat| mat.hint == Some(typed_hint.clone())) .find(|mat| mat.hint == Some(typed_hint.clone()))
{ {
Some(mat) => return Some((mat.text.to_string(), key != lower_key)), Some(mat) => {
chosen.push((mat.text.to_string(), key != lower_key));
if self.multi {
typed_hint.clear();
} else {
return chosen;
}
}
None => { None => {
if typed_hint.len() >= longest_hint.len() { if !self.multi && typed_hint.len() >= longest_hint.len() {
break; break;
} }
} }
@ -210,7 +236,7 @@ impl<'a> View<'a> {
} }
} }
None chosen
} }
} }
@ -230,6 +256,7 @@ mod tests {
let mut view = View { let mut view = View {
state: &mut state, state: &mut state,
skip: 0, skip: 0,
multi: false,
reverse: false, reverse: false,
unique: false, unique: false,
contrast: false, contrast: false,