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

View File

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