fix event order and table filter cursor

pull/24/head
Takayuki Maeda 3 years ago
parent 8b1f611b6b
commit 401c390800

@ -117,10 +117,6 @@ impl App {
} }
pub async fn event(&mut self, key: Key) -> anyhow::Result<()> { pub async fn event(&mut self, key: Key) -> anyhow::Result<()> {
if self.tab.event(key)?.is_consumed() {
return Ok(());
}
if let Key::Esc = key { if let Key::Esc = key {
if self.error.error.is_some() { if self.error.error.is_some() {
self.error.error = None; self.error.error = None;
@ -228,7 +224,7 @@ impl App {
if self.record_table.filter.input.is_empty() { if self.record_table.filter.input.is_empty() {
None None
} else { } else {
Some(self.record_table.filter.input.to_string()) Some(self.record_table.filter.input_str())
}, },
) )
.await?; .await?;
@ -259,7 +255,7 @@ impl App {
if self.record_table.filter.input.is_empty() { if self.record_table.filter.input.is_empty() {
None None
} else { } else {
Some(self.record_table.filter.input.to_string()) Some(self.record_table.filter.input_str())
}, },
) )
.await?; .await?;
@ -291,10 +287,13 @@ impl App {
Ok(EventState::NotConsumed) Ok(EventState::NotConsumed)
} }
pub fn move_focus(&mut self, key: Key) { pub fn move_focus(&mut self, key: Key) -> anyhow::Result<()> {
if let Key::Char('c') = key { if let Key::Char('c') = key {
self.focus = Focus::ConnectionList; self.focus = Focus::ConnectionList;
return; return Ok(());
}
if self.tab.event(key)?.is_consumed() {
return Ok(());
} }
match self.focus { match self.focus {
Focus::ConnectionList => { Focus::ConnectionList => {
@ -311,5 +310,6 @@ impl App {
_ => (), _ => (),
}, },
} }
Ok(())
} }
} }

@ -228,7 +228,12 @@ impl Component for DatabasesComponent {
return Ok(EventState::Consumed); return Ok(EventState::Consumed);
} }
Key::Char(c) if matches!(self.focus_block, FocusBlock::Filter) => { Key::Char(c) if matches!(self.focus_block, FocusBlock::Filter) => {
self.input.push(c); 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.filterd_tree = Some(self.tree.filter(self.input.clone()));
return Ok(EventState::Consumed); return Ok(EventState::Consumed);
} }

@ -40,6 +40,10 @@ impl RecordTableComponent {
pub fn update(&mut self, rows: Vec<Vec<String>>, headers: Vec<String>) { pub fn update(&mut self, rows: Vec<Vec<String>>, headers: Vec<String>) {
self.table.rows = rows; self.table.rows = rows;
self.table.headers = headers; self.table.headers = headers;
if !self.table.rows.is_empty() {
self.table.state.select(None);
self.table.state.select(Some(0));
}
} }
pub fn reset(&mut self) { pub fn reset(&mut self) {

@ -1,6 +1,7 @@
use super::{Component, DrawableComponent, EventState}; use super::{Component, DrawableComponent, EventState};
use crate::event::Key; use crate::event::Key;
use anyhow::Result; use anyhow::Result;
use std::convert::TryInto;
use tui::{ use tui::{
backend::Backend, backend::Backend,
layout::Rect, layout::Rect,
@ -9,36 +10,42 @@ use tui::{
widgets::{Block, Borders, Paragraph}, widgets::{Block, Borders, Paragraph},
Frame, Frame,
}; };
use unicode_width::UnicodeWidthStr; use unicode_width::{UnicodeWidthChar, UnicodeWidthStr};
pub struct TableFilterComponent { pub struct TableFilterComponent {
pub table: Option<String>, pub table: Option<String>,
pub input: String, pub input: Vec<char>,
pub input_cursor_x: u16, pub input_idx: usize,
pub input_cursor_position: u16,
} }
impl Default for TableFilterComponent { impl Default for TableFilterComponent {
fn default() -> Self { fn default() -> Self {
Self { Self {
table: None, table: None,
input: String::new(), input: Vec::new(),
input_cursor_x: 0, input_idx: 0,
input_cursor_position: 0,
} }
} }
} }
impl TableFilterComponent { impl TableFilterComponent {
pub fn increment_input_cursor_x(&mut self) { pub fn increment_input_idx(&mut self) {
if self.input_cursor_x > 0 { if self.input_idx > 0 {
self.input_cursor_x -= 1; self.input_idx -= 1;
} }
} }
pub fn decrement_input_cursor_x(&mut self) { pub fn decrement_input_idx(&mut self) {
if self.input_cursor_x < self.input.width() as u16 { if self.input_idx < self.input.iter().collect::<String>().width() {
self.input_cursor_x += 1; self.input_idx += 1;
} }
} }
pub fn input_str(&self) -> String {
self.input.iter().collect()
}
} }
impl DrawableComponent for TableFilterComponent { impl DrawableComponent for TableFilterComponent {
@ -53,9 +60,9 @@ impl DrawableComponent for TableFilterComponent {
Span::from(format!( Span::from(format!(
" {}", " {}",
if focused || !self.input.is_empty() { if focused || !self.input.is_empty() {
self.input.as_ref() self.input.iter().collect::<String>()
} else { } else {
"Enter a SQL expression in WHERE clause" "Enter a SQL expression in WHERE clause".to_string()
} }
)), )),
])) ]))
@ -69,15 +76,13 @@ impl DrawableComponent for TableFilterComponent {
if focused { if focused {
f.set_cursor( f.set_cursor(
(area.x (area.x
+ self.input.width() as u16 + (1 + self
+ 1
+ self
.table .table
.as_ref() .as_ref()
.map_or(String::new(), |table| table.to_string()) .map_or(String::new(), |table| table.to_string())
.width() as u16 .width()
+ 1) + 1) as u16)
.saturating_sub(self.input_cursor_x), .saturating_add(self.input_cursor_position),
area.y + 1, area.y + 1,
) )
} }
@ -87,34 +92,62 @@ impl DrawableComponent for TableFilterComponent {
impl Component for TableFilterComponent { impl Component for TableFilterComponent {
fn event(&mut self, key: Key) -> Result<EventState> { fn event(&mut self, key: Key) -> Result<EventState> {
let input_str: String = self.input.iter().collect();
match key { match key {
Key::Char(c) => { Key::Char(c) => {
self.input.push(c); self.input.insert(self.input_idx, c);
self.input_idx += 1;
self.input_cursor_position += compute_character_width(c);
return Ok(EventState::Consumed); return Ok(EventState::Consumed);
} }
Key::Delete | Key::Backspace => { Key::Delete | Key::Backspace => {
if self.input.width() > 0 { if input_str.width() > 0 {
if self.input_cursor_x == 0 { if !self.input.is_empty() && self.input_idx > 0 {
self.input.pop(); let last_c = self.input.remove(self.input_idx - 1);
self.input_idx -= 1;
self.input_cursor_position -= compute_character_width(last_c);
}
}
return Ok(EventState::Consumed); return Ok(EventState::Consumed);
} }
if self.input.width() - self.input_cursor_x as usize > 0 { Key::Left => {
self.input if !self.input.is_empty() && self.input_idx > 0 {
.remove(self.input.width() - self.input_cursor_x as usize); 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); 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
} }
Key::Left => {
self.decrement_input_cursor_x();
return Ok(EventState::Consumed); return Ok(EventState::Consumed);
} }
Key::Right => { Key::Right => {
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); return Ok(EventState::Consumed);
} }
_ => (), _ => println!("{}", key),
} }
Ok(EventState::NotConsumed) Ok(EventState::NotConsumed)
} }
} }
fn compute_character_width(c: char) -> u16 {
UnicodeWidthChar::width(c).unwrap().try_into().unwrap()
}

@ -195,10 +195,6 @@ impl From<event::KeyEvent> for Key {
code: event::KeyCode::Char(c), code: event::KeyCode::Char(c),
modifiers: event::KeyModifiers::CONTROL, modifiers: event::KeyModifiers::CONTROL,
} => Key::Ctrl(c), } => Key::Ctrl(c),
event::KeyEvent {
code: event::KeyCode::Char(c),
modifiers: event::KeyModifiers::SHIFT,
} => Key::Shift(c),
event::KeyEvent { event::KeyEvent {
code: event::KeyCode::Char(c), code: event::KeyCode::Char(c),

Loading…
Cancel
Save