diff --git a/src/components/record_table.rs b/src/components/record_table.rs
index ebdf1ba..dea2800 100644
--- a/src/components/record_table.rs
+++ b/src/components/record_table.rs
@@ -26,7 +26,7 @@ pub struct RecordTableComponent {
impl RecordTableComponent {
pub fn new(key_config: KeyConfig) -> Self {
Self {
- filter: TableFilterComponent::default(),
+ filter: TableFilterComponent::new(key_config.clone()),
table: TableComponent::new(key_config.clone()),
focus: Focus::Table,
key_config,
@@ -61,11 +61,11 @@ impl DrawableComponent for RecordTableComponent {
.constraints(vec![Constraint::Length(3), Constraint::Length(5)])
.split(area);
- self.filter
- .draw(f, layout[0], focused && matches!(self.focus, Focus::Filter))?;
-
self.table
.draw(f, layout[1], focused && matches!(self.focus, Focus::Table))?;
+
+ self.filter
+ .draw(f, layout[0], focused && matches!(self.focus, Focus::Filter))?;
Ok(())
}
}
diff --git a/src/components/table_filter.rs b/src/components/table_filter.rs
index 001038c..7b88e1f 100644
--- a/src/components/table_filter.rs
+++ b/src/components/table_filter.rs
@@ -1,5 +1,9 @@
-use super::{compute_character_width, Component, DrawableComponent, EventState};
+use super::{
+ compute_character_width, CompletionComponent, Component, DrawableComponent, EventState,
+ MovableComponent,
+};
use crate::components::command::CommandInfo;
+use crate::config::KeyConfig;
use crate::event::Key;
use anyhow::Result;
use database_tree::Table;
@@ -14,24 +18,26 @@ use tui::{
use unicode_width::UnicodeWidthStr;
pub struct TableFilterComponent {
+ key_config: KeyConfig,
pub table: Option
,
pub input: Vec,
input_idx: usize,
input_cursor_position: u16,
+ completion: CompletionComponent,
}
-impl Default for TableFilterComponent {
- fn default() -> Self {
+impl TableFilterComponent {
+ pub fn new(key_config: KeyConfig) -> Self {
Self {
+ key_config: key_config.clone(),
table: None,
input: Vec::new(),
input_idx: 0,
input_cursor_position: 0,
+ completion: CompletionComponent::new(key_config, ""),
}
}
-}
-impl TableFilterComponent {
pub fn input_str(&self) -> String {
self.input.iter().collect()
}
@@ -42,6 +48,21 @@ impl TableFilterComponent {
self.input_idx = 0;
self.input_cursor_position = 0;
}
+
+ fn update_completion(&mut self) {
+ let input = &self
+ .input
+ .iter()
+ .enumerate()
+ .filter(|(i, _)| i <= &self.input_idx)
+ .map(|(_, i)| i)
+ .collect::()
+ .split(" ")
+ .map(|i| i.to_string())
+ .collect::>();
+ self.completion
+ .update(input.last().unwrap_or(&String::new()));
+ }
}
impl DrawableComponent for TableFilterComponent {
@@ -69,6 +90,23 @@ impl DrawableComponent for TableFilterComponent {
})
.block(Block::default().borders(Borders::ALL));
f.render_widget(query, area);
+
+ if focused {
+ self.completion.draw(
+ f,
+ area,
+ false,
+ (self
+ .table
+ .as_ref()
+ .map_or(String::new(), |table| table.name.to_string())
+ .width() as u16
+ + 2)
+ .saturating_add(self.input_cursor_position),
+ 0,
+ )?;
+ };
+
if focused {
f.set_cursor(
(area.x
@@ -91,21 +129,40 @@ impl Component for TableFilterComponent {
fn event(&mut self, key: Key) -> Result {
let input_str: String = self.input.iter().collect();
+
+ // apply comletion candidates
+ if key == self.key_config.enter {
+ if let Some(candidate) = self.completion.string_to_be_completed() {
+ let mut input = self.input.iter().collect::();
+ input.insert_str(self.input_idx, candidate.as_str());
+ self.input = input.chars().collect();
+ self.input_idx += candidate.len();
+ self.input_cursor_position += candidate
+ .chars()
+ .map(|c| compute_character_width(c))
+ .sum::();
+ self.update_completion();
+ return Ok(EventState::Consumed);
+ }
+ }
+
match key {
Key::Char(c) => {
self.input.insert(self.input_idx, c);
self.input_idx += 1;
self.input_cursor_position += compute_character_width(c);
+ self.update_completion();
- return Ok(EventState::Consumed);
+ Ok(EventState::Consumed)
}
Key::Delete | Key::Backspace => {
if input_str.width() > 0 && !self.input.is_empty() && self.input_idx > 0 {
let last_c = self.input.remove(self.input_idx - 1);
self.input_idx -= 1;
self.input_cursor_position -= compute_character_width(last_c);
+ self.update_completion();
}
- return Ok(EventState::Consumed);
+ Ok(EventState::Consumed)
}
Key::Left => {
if !self.input.is_empty() && self.input_idx > 0 {
@@ -114,14 +171,14 @@ impl Component for TableFilterComponent {
.input_cursor_position
.saturating_sub(compute_character_width(self.input[self.input_idx]));
}
- return Ok(EventState::Consumed);
+ Ok(EventState::Consumed)
}
Key::Ctrl('a') => {
if !self.input.is_empty() && self.input_idx > 0 {
self.input_idx = 0;
self.input_cursor_position = 0
}
- return Ok(EventState::Consumed);
+ Ok(EventState::Consumed)
}
Key::Right => {
if self.input_idx < self.input.len() {
@@ -129,17 +186,16 @@ impl Component for TableFilterComponent {
self.input_idx += 1;
self.input_cursor_position += compute_character_width(next_c);
}
- return Ok(EventState::Consumed);
+ Ok(EventState::Consumed)
}
Key::Ctrl('e') => {
if self.input_idx < self.input.len() {
self.input_idx = self.input.len();
self.input_cursor_position = self.input_str().width() as u16;
}
- return Ok(EventState::Consumed);
+ Ok(EventState::Consumed)
}
- _ => (),
+ key => self.completion.event(key),
}
- Ok(EventState::NotConsumed)
}
}