|
@@ -127,16 +127,16 @@ impl<AE: ActionEnum> ActionPrompt<AE> {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-pub struct SelectPrompt<'l, T: ?Sized + std::fmt::Display> {
|
|
|
|
|
|
+pub struct SelectPrompt<'l, T: std::fmt::Display> {
|
|
prompt: &'l str,
|
|
prompt: &'l str,
|
|
height: usize,
|
|
height: usize,
|
|
- items: Vec<(String, &'l T)>,
|
|
|
|
- filtered_items: Vec<(String, &'l T)>,
|
|
|
|
|
|
+ items: Vec<(String, T)>,
|
|
|
|
+ filtered_items: Vec<usize>,
|
|
alphabetize: bool,
|
|
alphabetize: bool,
|
|
input: String,
|
|
input: String,
|
|
}
|
|
}
|
|
|
|
|
|
-impl<'l, T: ?Sized + std::fmt::Display> SelectPrompt<'l, T> {
|
|
|
|
|
|
+impl<'l, T: std::fmt::Display> SelectPrompt<'l, T> {
|
|
pub fn new(prompt: &'l str) -> Self {
|
|
pub fn new(prompt: &'l str) -> Self {
|
|
Self {
|
|
Self {
|
|
prompt,
|
|
prompt,
|
|
@@ -148,7 +148,7 @@ impl<'l, T: ?Sized + std::fmt::Display> SelectPrompt<'l, T> {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- pub fn with_items(mut self, items: impl IntoIterator<Item = &'l T>) -> Self {
|
|
|
|
|
|
+ pub fn with_items(mut self, items: impl IntoIterator<Item = T>) -> Self {
|
|
for item in items {
|
|
for item in items {
|
|
self.items.push((item.to_string(), item));
|
|
self.items.push((item.to_string(), item));
|
|
}
|
|
}
|
|
@@ -186,9 +186,9 @@ impl<'l, T: ?Sized + std::fmt::Display> SelectPrompt<'l, T> {
|
|
|
|
|
|
fn refilter(&mut self) {
|
|
fn refilter(&mut self) {
|
|
self.filtered_items.clear();
|
|
self.filtered_items.clear();
|
|
- for item in &self.items {
|
|
|
|
|
|
+ for (idx,item) in self.items.iter().enumerate() {
|
|
if item.0.starts_with(&self.input) {
|
|
if item.0.starts_with(&self.input) {
|
|
- self.filtered_items.push(item.clone());
|
|
|
|
|
|
+ self.filtered_items.push(idx);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -238,8 +238,8 @@ impl<'l, T: ?Sized + std::fmt::Display> SelectPrompt<'l, T> {
|
|
let mut rwidth = width as usize;
|
|
let mut rwidth = width as usize;
|
|
|
|
|
|
'gencols: {
|
|
'gencols: {
|
|
- for item in self.filtered_items.iter() {
|
|
|
|
- col.push(item.0.as_str());
|
|
|
|
|
|
+ for idx in self.filtered_items.iter() {
|
|
|
|
+ col.push(self.items[*idx].0.as_str());
|
|
if col.len() == rows.len() {
|
|
if col.len() == rows.len() {
|
|
let Some(rval) = Self::append_column(rwidth, &mut rows, &mut col) else { break 'gencols };
|
|
let Some(rval) = Self::append_column(rwidth, &mut rows, &mut col) else { break 'gencols };
|
|
rwidth = rval;
|
|
rwidth = rval;
|
|
@@ -261,7 +261,7 @@ impl<'l, T: ?Sized + std::fmt::Display> SelectPrompt<'l, T> {
|
|
Ok(())
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
|
|
- fn input_loop(&mut self, stdout: &mut std::io::Stdout, cancellable: bool) -> Result<Option<&'l T>, AskError> {
|
|
|
|
|
|
+ fn input_loop(&mut self, stdout: &mut std::io::Stdout, cancellable: bool) -> Result<Option<T>, AskError> {
|
|
let mut keys = std::io::stdin().keys();
|
|
let mut keys = std::io::stdin().keys();
|
|
let mut raw = stdout.into_raw_mode()?;
|
|
let mut raw = stdout.into_raw_mode()?;
|
|
self.refilter();
|
|
self.refilter();
|
|
@@ -284,7 +284,7 @@ impl<'l, T: ?Sized + std::fmt::Display> SelectPrompt<'l, T> {
|
|
termion::event::Key::Char('\r') | termion::event::Key::Char('\n') => {
|
|
termion::event::Key::Char('\r') | termion::event::Key::Char('\n') => {
|
|
self.refilter();
|
|
self.refilter();
|
|
if self.filtered_items.len() == 1 {
|
|
if self.filtered_items.len() == 1 {
|
|
- return Ok(Some(self.filtered_items[0].1))
|
|
|
|
|
|
+ return Ok(Some(self.items.swap_remove(self.filtered_items[0]).1))
|
|
}
|
|
}
|
|
},
|
|
},
|
|
termion::event::Key::Ctrl('u') => {
|
|
termion::event::Key::Ctrl('u') => {
|
|
@@ -293,13 +293,16 @@ impl<'l, T: ?Sized + std::fmt::Display> SelectPrompt<'l, T> {
|
|
},
|
|
},
|
|
termion::event::Key::Char('\t') => {
|
|
termion::event::Key::Char('\t') => {
|
|
self.refilter();
|
|
self.refilter();
|
|
- // see if we can extend the input unambiguously
|
|
|
|
- let min_len = self.filtered_items.iter().map(|v| v.0.len()).min().unwrap_or(self.input.len());
|
|
|
|
- for prefix_len in (self.input.len()+1)..=min_len {
|
|
|
|
- if self.filtered_items.iter().all(|v| v.0.starts_with(&self.filtered_items[0].0[0..prefix_len])) {
|
|
|
|
- self.input.clear();
|
|
|
|
- self.input.push_str(&self.filtered_items[0].0[0..prefix_len]);
|
|
|
|
- } else { break }
|
|
|
|
|
|
+ if !self.filtered_items.is_empty() {
|
|
|
|
+ // see if we can extend the input unambiguously
|
|
|
|
+ let min_len = self.filtered_items.iter().map(|v| self.items[*v].0.len()).min().unwrap_or(self.input.len());
|
|
|
|
+ for prefix_len in (self.input.len()+1)..=min_len {
|
|
|
|
+ let tomatch = &self.items[self.filtered_items[0]].0[0..prefix_len];
|
|
|
|
+ if self.filtered_items.iter().all(|v| self.items[*v].0.starts_with(tomatch)) {
|
|
|
|
+ self.input.clear();
|
|
|
|
+ self.input.push_str(tomatch);
|
|
|
|
+ } else { break }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
},
|
|
},
|
|
termion::event::Key::Char(ch) => {
|
|
termion::event::Key::Char(ch) => {
|
|
@@ -313,7 +316,7 @@ impl<'l, T: ?Sized + std::fmt::Display> SelectPrompt<'l, T> {
|
|
Ok(None)
|
|
Ok(None)
|
|
}
|
|
}
|
|
|
|
|
|
- pub fn run(mut self) -> Result<&'l T, AskError> {
|
|
|
|
|
|
+ pub fn run(mut self) -> Result<T, AskError> {
|
|
let mut stdout = std::io::stdout();
|
|
let mut stdout = std::io::stdout();
|
|
self.setup(&mut stdout)?;
|
|
self.setup(&mut stdout)?;
|
|
|
|
|
|
@@ -322,7 +325,7 @@ impl<'l, T: ?Sized + std::fmt::Display> SelectPrompt<'l, T> {
|
|
r
|
|
r
|
|
}
|
|
}
|
|
|
|
|
|
- pub fn run_cancellable(mut self) -> Result<Option<&'l T>, AskError> {
|
|
|
|
|
|
+ pub fn run_cancellable(mut self) -> Result<Option<T>, AskError> {
|
|
let mut stdout = std::io::stdout();
|
|
let mut stdout = std::io::stdout();
|
|
self.setup(&mut stdout)?;
|
|
self.setup(&mut stdout)?;
|
|
|
|
|