|
|
|
@ -63,6 +63,70 @@ impl TableFilterComponent {
|
|
|
|
|
self.completion
|
|
|
|
|
.update(input.last().unwrap_or(&String::new()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn complete(&mut self) -> anyhow::Result<EventState> {
|
|
|
|
|
if let Some(candidate) = self.completion.selected_candidate() {
|
|
|
|
|
let mut input = Vec::new();
|
|
|
|
|
let first = self
|
|
|
|
|
.input
|
|
|
|
|
.iter()
|
|
|
|
|
.enumerate()
|
|
|
|
|
.filter(|(i, _)| i < &self.input_idx.saturating_sub(self.completion.word().len()))
|
|
|
|
|
.map(|(_, c)| c.to_string())
|
|
|
|
|
.collect::<Vec<String>>();
|
|
|
|
|
let last = self
|
|
|
|
|
.input
|
|
|
|
|
.iter()
|
|
|
|
|
.enumerate()
|
|
|
|
|
.filter(|(i, _)| i >= &self.input_idx)
|
|
|
|
|
.map(|(_, c)| c.to_string())
|
|
|
|
|
.collect::<Vec<String>>();
|
|
|
|
|
|
|
|
|
|
let is_last_word = last.first().map_or(false, |c| c == &" ".to_string());
|
|
|
|
|
|
|
|
|
|
let middle = if is_last_word {
|
|
|
|
|
candidate
|
|
|
|
|
.chars()
|
|
|
|
|
.map(|c| c.to_string())
|
|
|
|
|
.collect::<Vec<String>>()
|
|
|
|
|
} else {
|
|
|
|
|
let mut c = candidate
|
|
|
|
|
.chars()
|
|
|
|
|
.map(|c| c.to_string())
|
|
|
|
|
.collect::<Vec<String>>();
|
|
|
|
|
c.push(" ".to_string());
|
|
|
|
|
c
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
input.extend(first);
|
|
|
|
|
input.extend(middle.clone());
|
|
|
|
|
input.extend(last);
|
|
|
|
|
|
|
|
|
|
self.input = input.join("").chars().collect();
|
|
|
|
|
self.input_idx += &middle.len();
|
|
|
|
|
if is_last_word {
|
|
|
|
|
self.input_idx += 1;
|
|
|
|
|
}
|
|
|
|
|
self.input_idx -= self.completion.word().len();
|
|
|
|
|
self.input_cursor_position += middle
|
|
|
|
|
.join("")
|
|
|
|
|
.chars()
|
|
|
|
|
.map(compute_character_width)
|
|
|
|
|
.sum::<u16>();
|
|
|
|
|
if is_last_word {
|
|
|
|
|
self.input_cursor_position += " ".to_string().width() as u16
|
|
|
|
|
}
|
|
|
|
|
self.input_cursor_position -= self
|
|
|
|
|
.completion
|
|
|
|
|
.word()
|
|
|
|
|
.chars()
|
|
|
|
|
.map(compute_character_width)
|
|
|
|
|
.sum::<u16>();
|
|
|
|
|
self.update_completion();
|
|
|
|
|
return Ok(EventState::Consumed);
|
|
|
|
|
}
|
|
|
|
|
Ok(EventState::NotConsumed)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl DrawableComponent for TableFilterComponent {
|
|
|
|
@ -132,69 +196,7 @@ impl Component for TableFilterComponent {
|
|
|
|
|
|
|
|
|
|
// apply comletion candidates
|
|
|
|
|
if key == self.key_config.enter {
|
|
|
|
|
if let Some(candidate) = self.completion.selected_candidate() {
|
|
|
|
|
let mut input = Vec::new();
|
|
|
|
|
|
|
|
|
|
let first = self
|
|
|
|
|
.input
|
|
|
|
|
.iter()
|
|
|
|
|
.enumerate()
|
|
|
|
|
.filter(|(i, _)| {
|
|
|
|
|
i < &self.input_idx.saturating_sub(self.completion.word().len())
|
|
|
|
|
})
|
|
|
|
|
.map(|(_, c)| c.to_string())
|
|
|
|
|
.collect::<Vec<String>>();
|
|
|
|
|
|
|
|
|
|
let last = self
|
|
|
|
|
.input
|
|
|
|
|
.iter()
|
|
|
|
|
.enumerate()
|
|
|
|
|
.filter(|(i, _)| i >= &self.input_idx)
|
|
|
|
|
.map(|(_, c)| c.to_string())
|
|
|
|
|
.collect::<Vec<String>>();
|
|
|
|
|
|
|
|
|
|
let is_last_word = last.first().map_or(false, |c| c == &" ".to_string());
|
|
|
|
|
let middle = if is_last_word {
|
|
|
|
|
candidate
|
|
|
|
|
.chars()
|
|
|
|
|
.map(|c| c.to_string())
|
|
|
|
|
.collect::<Vec<String>>()
|
|
|
|
|
} else {
|
|
|
|
|
let mut c = candidate
|
|
|
|
|
.chars()
|
|
|
|
|
.map(|c| c.to_string())
|
|
|
|
|
.collect::<Vec<String>>();
|
|
|
|
|
c.push(" ".to_string());
|
|
|
|
|
c
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
input.extend(first);
|
|
|
|
|
input.extend(middle.clone());
|
|
|
|
|
input.extend(last);
|
|
|
|
|
|
|
|
|
|
self.input = input.join("").chars().collect();
|
|
|
|
|
self.input_idx += &middle.len();
|
|
|
|
|
if is_last_word {
|
|
|
|
|
self.input_idx += 1;
|
|
|
|
|
}
|
|
|
|
|
self.input_idx -= self.completion.word().len();
|
|
|
|
|
self.input_cursor_position += middle
|
|
|
|
|
.join("")
|
|
|
|
|
.chars()
|
|
|
|
|
.map(compute_character_width)
|
|
|
|
|
.sum::<u16>();
|
|
|
|
|
if is_last_word {
|
|
|
|
|
self.input_cursor_position += " ".to_string().width() as u16
|
|
|
|
|
}
|
|
|
|
|
self.input_cursor_position -= self
|
|
|
|
|
.completion
|
|
|
|
|
.word()
|
|
|
|
|
.chars()
|
|
|
|
|
.map(compute_character_width)
|
|
|
|
|
.sum::<u16>();
|
|
|
|
|
self.update_completion();
|
|
|
|
|
return Ok(EventState::Consumed);
|
|
|
|
|
}
|
|
|
|
|
self.complete()?;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self.completion.selected_candidate();
|
|
|
|
@ -259,9 +261,13 @@ impl Component for TableFilterComponent {
|
|
|
|
|
mod test {
|
|
|
|
|
use super::{KeyConfig, TableFilterComponent};
|
|
|
|
|
|
|
|
|
|
fn test_update_completion() {
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_complete() {
|
|
|
|
|
let mut filter = TableFilterComponent::new(KeyConfig::default());
|
|
|
|
|
filter.input_idx = 3;
|
|
|
|
|
filter.input = vec!['a', 'b', ' ', 'c', 'd', 'e', 'f', 'g']
|
|
|
|
|
filter.input = vec!['a', 'b', ' ', 'c', 'd', 'e', 'f', 'g'];
|
|
|
|
|
filter.completion.state.select(Some(0));
|
|
|
|
|
assert!(filter.complete().is_ok());
|
|
|
|
|
assert_eq!(filter.input, vec!['a', 'b', ' ', 'c', 'd', 'e', 'f', 'g']);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|