fix and enhance databases filter

pull/24/head
Takayuki Maeda 3 years ago
parent 401c390800
commit 0aa2b24ffc

@ -116,20 +116,22 @@ impl App {
Ok(())
}
pub async fn event(&mut self, key: Key) -> anyhow::Result<()> {
pub async fn event(&mut self, key: Key) -> anyhow::Result<EventState> {
if let Key::Esc = key {
if self.error.error.is_some() {
self.error.error = None;
return Ok(());
return Ok(EventState::Consumed);
}
}
if self.components_event(key).await?.is_consumed() {
return Ok(());
return Ok(EventState::Consumed);
};
self.move_focus(key);
Ok(())
if self.move_focus(key)?.is_consumed() {
return Ok(EventState::Consumed);
};
Ok(EventState::NotConsumed)
}
pub async fn components_event(&mut self, key: Key) -> anyhow::Result<EventState> {
@ -267,7 +269,6 @@ impl App {
}
}
};
return Ok(EventState::NotConsumed);
}
Tab::Structure => {
if self.structure_table.event(key)?.is_consumed() {
@ -279,7 +280,6 @@ impl App {
self.clipboard.store(text)
}
};
return Ok(EventState::Consumed);
}
};
}
@ -287,29 +287,36 @@ impl App {
Ok(EventState::NotConsumed)
}
pub fn move_focus(&mut self, key: Key) -> anyhow::Result<()> {
pub fn move_focus(&mut self, key: Key) -> anyhow::Result<EventState> {
if let Key::Char('c') = key {
self.focus = Focus::ConnectionList;
return Ok(());
return Ok(EventState::Consumed);
}
if self.tab.event(key)?.is_consumed() {
return Ok(());
return Ok(EventState::Consumed);
}
match self.focus {
Focus::ConnectionList => {
if let Key::Enter = key {
self.focus = Focus::DabataseList
self.focus = Focus::DabataseList;
return Ok(EventState::Consumed);
}
}
Focus::DabataseList => match key {
Key::Right if self.databases.tree_focused() => self.focus = Focus::Table,
Key::Right if self.databases.tree_focused() => {
self.focus = Focus::Table;
return Ok(EventState::Consumed);
}
_ => (),
},
Focus::Table => match key {
Key::Left => self.focus = Focus::DabataseList,
Key::Left => {
self.focus = Focus::DabataseList;
return Ok(EventState::Consumed);
}
_ => (),
},
}
Ok(())
Ok(EventState::NotConsumed)
}
}

@ -1,4 +1,7 @@
use super::{utils::scroll_vertical::VerticalScroll, Component, DrawableComponent, EventState};
use super::{
compute_character_width, utils::scroll_vertical::VerticalScroll, Component, DrawableComponent,
EventState,
};
use crate::components::RecordTableComponent;
use crate::event::Key;
use crate::ui::common_nav;
@ -33,8 +36,9 @@ pub struct DatabasesComponent {
pub tree: DatabaseTree,
pub filterd_tree: Option<DatabaseTree>,
pub scroll: VerticalScroll,
pub input: String,
pub input_cursor_x: u16,
pub input: Vec<char>,
pub input_idx: usize,
pub input_cursor_position: u16,
pub record_table: RecordTableComponent,
pub focus_block: FocusBlock,
}
@ -45,18 +49,23 @@ impl DatabasesComponent {
tree: DatabaseTree::default(),
filterd_tree: None,
scroll: VerticalScroll::new(),
input: String::new(),
input_cursor_x: 0,
input: Vec::new(),
input_idx: 0,
input_cursor_position: 0,
record_table: RecordTableComponent::default(),
focus_block: FocusBlock::Tree,
}
}
pub fn input_str(&self) -> String {
self.input.iter().collect()
}
pub fn update(&mut self, list: &[Database]) -> Result<()> {
self.tree = DatabaseTree::new(list, &BTreeSet::new())?;
self.filterd_tree = None;
self.input = String::new();
self.input_cursor_x = 0;
self.input = Vec::new();
self.input_idx = 0;
Ok(())
}
@ -68,18 +77,6 @@ impl DatabasesComponent {
self.filterd_tree.as_ref().unwrap_or(&self.tree)
}
pub fn increment_input_cursor_x(&mut self) {
if self.input_cursor_x > 0 {
self.input_cursor_x -= 1;
}
}
pub fn decrement_input_cursor_x(&mut self) {
if self.input_cursor_x < self.input.width() as u16 {
self.input_cursor_x += 1;
}
}
fn tree_item_to_span(item: DatabaseTreeItem, selected: bool, width: u16) -> Span<'static> {
let name = item.kind().name();
let indent = item.info().indent();
@ -161,7 +158,7 @@ impl DatabasesComponent {
if self.input.is_empty() && matches!(self.focus_block, FocusBlock::Tree) {
"Filter tables".to_string()
} else {
self.input.clone()
self.input_str()
},
w = area.width as usize
),
@ -190,10 +187,7 @@ impl DatabasesComponent {
);
self.scroll.draw(f, area);
if let FocusBlock::Filter = self.focus_block {
f.set_cursor(
area.x + self.input.width() as u16 + 1 - self.input_cursor_x,
area.y + 1,
)
f.set_cursor(area.x + self.input_cursor_position + 1, area.y + 1)
}
}
}
@ -212,6 +206,7 @@ impl DrawableComponent for DatabasesComponent {
impl Component for DatabasesComponent {
fn event(&mut self, key: Key) -> Result<EventState> {
let input_str: String = self.input.iter().collect();
if tree_nav(
if let Some(tree) = self.filterd_tree.as_mut() {
tree
@ -228,41 +223,58 @@ impl Component for DatabasesComponent {
return Ok(EventState::Consumed);
}
Key::Char(c) if matches!(self.focus_block, FocusBlock::Filter) => {
self.input.insert(
self.input
.width()
.saturating_sub(self.input_cursor_x as usize),
c,
);
self.filterd_tree = Some(self.tree.filter(self.input.clone()));
self.input.insert(self.input_idx, c);
self.input_idx += 1;
self.input_cursor_position += compute_character_width(c);
self.filterd_tree = Some(self.tree.filter(self.input_str()));
return Ok(EventState::Consumed);
}
Key::Delete | Key::Backspace if matches!(self.focus_block, FocusBlock::Filter) => {
if !self.input.is_empty() {
if self.input_cursor_x == 0 {
self.input.pop();
} else if self.input.width() - self.input_cursor_x as usize > 0 {
self.input.remove(
self.input
.width()
.saturating_sub(self.input_cursor_x as usize)
.saturating_sub(1),
);
if input_str.width() > 0 {
if !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.filterd_tree = if self.input.is_empty() {
None
} else {
Some(self.tree.filter(self.input.clone()))
Some(self.tree.filter(self.input_str()))
};
return Ok(EventState::Consumed);
}
}
Key::Left if matches!(self.focus_block, FocusBlock::Filter) => {
self.decrement_input_cursor_x();
if !self.input.is_empty() && self.input_idx > 0 {
self.input_idx -= 1;
self.input_cursor_position = self
.input_cursor_position
.saturating_sub(compute_character_width(self.input[self.input_idx]));
}
return 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);
}
Key::Right if matches!(self.focus_block, FocusBlock::Filter) => {
self.increment_input_cursor_x();
if self.input_idx < self.input.len() {
let next_c = self.input[self.input_idx];
self.input_idx += 1;
self.input_cursor_position += compute_character_width(next_c);
}
return 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);
}
Key::Enter if matches!(self.focus_block, FocusBlock::Filter) => {

@ -23,7 +23,9 @@ pub use table_value::TableValueComponent;
use anyhow::Result;
use async_trait::async_trait;
use std::convert::TryInto;
use tui::{backend::Backend, layout::Rect, Frame};
use unicode_width::UnicodeWidthChar;
#[derive(Copy, Clone)]
pub enum ScrollType {
@ -97,3 +99,7 @@ pub trait Component {
}
}
}
fn compute_character_width(c: char) -> u16 {
UnicodeWidthChar::width(c).unwrap().try_into().unwrap()
}

@ -276,7 +276,7 @@ impl Component for TableComponent {
self.select_entire_row = true;
return Ok(EventState::Consumed);
}
Key::Shift('G') | Key::Shift('g') => {
Key::Char('G') => {
self.scroll_bottom();
return Ok(EventState::Consumed);
}

@ -1,7 +1,6 @@
use super::{Component, DrawableComponent, EventState};
use super::{compute_character_width, Component, DrawableComponent, EventState};
use crate::event::Key;
use anyhow::Result;
use std::convert::TryInto;
use tui::{
backend::Backend,
layout::Rect,
@ -10,7 +9,7 @@ use tui::{
widgets::{Block, Borders, Paragraph},
Frame,
};
use unicode_width::{UnicodeWidthChar, UnicodeWidthStr};
use unicode_width::UnicodeWidthStr;
pub struct TableFilterComponent {
pub table: Option<String>,
@ -31,18 +30,6 @@ impl Default for TableFilterComponent {
}
impl TableFilterComponent {
pub fn increment_input_idx(&mut self) {
if self.input_idx > 0 {
self.input_idx -= 1;
}
}
pub fn decrement_input_idx(&mut self) {
if self.input_idx < self.input.iter().collect::<String>().width() {
self.input_idx += 1;
}
}
pub fn input_str(&self) -> String {
self.input.iter().collect()
}
@ -142,12 +129,8 @@ impl Component for TableFilterComponent {
}
return Ok(EventState::Consumed);
}
_ => println!("{}", key),
_ => (),
}
Ok(EventState::NotConsumed)
}
}
fn compute_character_width(c: char) -> u16 {
UnicodeWidthChar::width(c).unwrap().try_into().unwrap()
}

@ -63,7 +63,6 @@ pub enum Key {
F12,
Char(char),
Ctrl(char),
Shift(char),
Alt(char),
Unkown,
}
@ -104,7 +103,6 @@ impl fmt::Display for Key {
Key::Char(' ') => write!(f, "<Space>"),
Key::Alt(c) => write!(f, "<Alt+{}>", c),
Key::Ctrl(c) => write!(f, "<Ctrl+{}>", c),
Key::Shift(c) => write!(f, "<Shift+{}>", c),
Key::Char(c) => write!(f, "{}", c),
Key::Left | Key::Right | Key::Up | Key::Down => write!(f, "<{:?} Arrow Key>", self),
Key::Enter

@ -43,15 +43,14 @@ async fn main() -> anyhow::Result<()> {
loop {
terminal.draw(|f| app.draw(f).unwrap())?;
match events.next()? {
Event::Input(key) => {
if key == Key::Char('q') {
break;
};
match app.event(key).await {
Ok(_) => (),
Err(err) => app.error.set(err.to_string()),
Event::Input(key) => match app.event(key).await {
Ok(state) => {
if !state.is_consumed() && (key == Key::Char('q') || key == Key::Ctrl('c')) {
break;
}
}
}
Err(err) => app.error.set(err.to_string()),
},
Event::Tick => (),
}
}

Loading…
Cancel
Save