From 950992df8dbebb6a3555a219332c4f20a264df98 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda <41065217+TaKO8Ki@users.noreply.github.com> Date: Thu, 16 Sep 2021 13:20:11 +0900 Subject: [PATCH] Enable to change database tree width (#99) * add a border width * add a left_chunk_percentage field * add keys for extending widget width * fix completion pop-ups so that they do not protrude from frame * use expand_or_shorten_widget_width * handle extend shorten widget width event after component events * add tests * add command description * add tests * change commands help order * fix extend_or_shorten_widget_width help * change left_chunk_percentage to left_main_chunk_percentage --- src/app.rs | 86 +++++++++++++++++++++++++++++++++--- src/components/command.rs | 10 +++++ src/components/completion.rs | 7 ++- src/components/mod.rs | 2 +- src/components/table.rs | 4 +- src/config.rs | 4 ++ 6 files changed, 101 insertions(+), 12 deletions(-) diff --git a/src/app.rs b/src/app.rs index 77e1905..cfb5031 100644 --- a/src/app.rs +++ b/src/app.rs @@ -34,6 +34,7 @@ pub struct App { databases: DatabasesComponent, connections: ConnectionsComponent, pool: Option>, + left_main_chunk_percentage: u16, pub config: Config, pub error: ErrorComponent, } @@ -54,6 +55,7 @@ impl App { error: ErrorComponent::new(config.key_config), focus: Focus::ConnectionList, pool: None, + left_main_chunk_percentage: 15, } } @@ -73,7 +75,10 @@ impl App { let main_chunks = Layout::default() .direction(Direction::Horizontal) - .constraints([Constraint::Percentage(15), Constraint::Percentage(85)]) + .constraints([ + Constraint::Percentage(self.left_main_chunk_percentage), + Constraint::Percentage((100_u16).saturating_sub(self.left_main_chunk_percentage)), + ]) .split(f.size()); self.databases @@ -122,15 +127,18 @@ impl App { fn commands(&self) -> Vec { let mut res = vec![ + CommandInfo::new(command::filter(&self.config.key_config)), + CommandInfo::new(command::help(&self.config.key_config)), + CommandInfo::new(command::toggle_tabs(&self.config.key_config)), CommandInfo::new(command::scroll(&self.config.key_config)), CommandInfo::new(command::scroll_to_top_bottom(&self.config.key_config)), CommandInfo::new(command::scroll_up_down_multiple_lines( &self.config.key_config, )), CommandInfo::new(command::move_focus(&self.config.key_config)), - CommandInfo::new(command::filter(&self.config.key_config)), - CommandInfo::new(command::help(&self.config.key_config)), - CommandInfo::new(command::toggle_tabs(&self.config.key_config)), + CommandInfo::new(command::extend_or_shorten_widget_width( + &self.config.key_config, + )), ]; self.databases.commands(&mut res); @@ -301,7 +309,7 @@ impl App { Ok(EventState::NotConsumed) } - pub async fn components_event(&mut self, key: Key) -> anyhow::Result { + async fn components_event(&mut self, key: Key) -> anyhow::Result { if self.error.event(key)?.is_consumed() { return Ok(EventState::Consumed); } @@ -329,7 +337,9 @@ impl App { return Ok(EventState::Consumed); } - return Ok(state); + if state.is_consumed() { + return Ok(EventState::Consumed); + } } Focus::Table => { match self.tab.selected_tab { @@ -430,10 +440,37 @@ impl App { }; } } + + if self.extend_or_shorten_widget_width(key)?.is_consumed() { + return Ok(EventState::Consumed); + }; + Ok(EventState::NotConsumed) } - pub fn move_focus(&mut self, key: Key) -> anyhow::Result { + fn extend_or_shorten_widget_width(&mut self, key: Key) -> anyhow::Result { + if key + == self + .config + .key_config + .extend_or_shorten_widget_width_to_left + { + self.left_main_chunk_percentage = + self.left_main_chunk_percentage.saturating_sub(5).max(15); + return Ok(EventState::Consumed); + } else if key + == self + .config + .key_config + .extend_or_shorten_widget_width_to_right + { + self.left_main_chunk_percentage = (self.left_main_chunk_percentage + 5).min(70); + return Ok(EventState::Consumed); + } + Ok(EventState::NotConsumed) + } + + fn move_focus(&mut self, key: Key) -> anyhow::Result { if key == self.config.key_config.focus_connections { self.focus = Focus::ConnectionList; return Ok(EventState::Consumed); @@ -464,3 +501,38 @@ impl App { Ok(EventState::NotConsumed) } } + +#[cfg(test)] +mod test { + use super::{App, Config, EventState, Key}; + + #[test] + fn test_extend_or_shorten_widget_width() { + let mut app = App::new(Config::default()); + assert_eq!( + app.extend_or_shorten_widget_width(Key::Char('>')).unwrap(), + EventState::Consumed + ); + assert_eq!(app.left_main_chunk_percentage, 20); + + app.left_main_chunk_percentage = 70; + assert_eq!( + app.extend_or_shorten_widget_width(Key::Char('>')).unwrap(), + EventState::Consumed + ); + assert_eq!(app.left_main_chunk_percentage, 70); + + assert_eq!( + app.extend_or_shorten_widget_width(Key::Char('<')).unwrap(), + EventState::Consumed + ); + assert_eq!(app.left_main_chunk_percentage, 65); + + app.left_main_chunk_percentage = 15; + assert_eq!( + app.extend_or_shorten_widget_width(Key::Char('<')).unwrap(), + EventState::Consumed + ); + assert_eq!(app.left_main_chunk_percentage, 15); + } +} diff --git a/src/components/command.rs b/src/components/command.rs index 54bdf11..192b870 100644 --- a/src/components/command.rs +++ b/src/components/command.rs @@ -95,6 +95,16 @@ pub fn extend_selection_by_one_cell(key: &KeyConfig) -> CommandText { ) } +pub fn extend_or_shorten_widget_width(key: &KeyConfig) -> CommandText { + CommandText::new( + format!( + "Extend/shorten widget width to left/right [{},{}]", + key.extend_or_shorten_widget_width_to_left, key.extend_or_shorten_widget_width_to_right + ), + CMD_GROUP_GENERAL, + ) +} + pub fn tab_records(key: &KeyConfig) -> CommandText { CommandText::new(format!("Records [{}]", key.tab_records), CMD_GROUP_TABLE) } diff --git a/src/components/completion.rs b/src/components/completion.rs index 42b36f8..df643c5 100644 --- a/src/components/completion.rs +++ b/src/components/completion.rs @@ -110,8 +110,11 @@ impl MovableComponent for CompletionComponent { let area = Rect::new( area.x + x, area.y + y + 2, - width.min(f.size().width), - candidates.len().min(5) as u16 + 2, + width + .min(f.size().width) + .min(f.size().right().saturating_sub(area.x + x)), + (candidates.len().min(5) as u16 + 2) + .min(f.size().bottom().saturating_sub(area.y + y + 2)), ); f.render_widget(Clear, area); f.render_stateful_widget(candidate_list, area, &mut self.state); diff --git a/src/components/mod.rs b/src/components/mod.rs index 46d7dce..79440ce 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -37,7 +37,7 @@ use std::convert::TryInto; use tui::{backend::Backend, layout::Rect, Frame}; use unicode_width::UnicodeWidthChar; -#[derive(PartialEq)] +#[derive(PartialEq, Debug)] pub enum EventState { Consumed, NotConsumed, diff --git a/src/components/table.rs b/src/components/table.rs index 988e3ea..1da7a6d 100644 --- a/src/components/table.rs +++ b/src/components/table.rs @@ -314,7 +314,7 @@ impl TableComponent { ) .clamp(&3, &20) }); - if widths.iter().map(|(_, width)| width).sum::() + length + widths.len() + if widths.iter().map(|(_, width)| width).sum::() + length + widths.len() + 1 >= area_width.saturating_sub(number_column_width) as usize { column_index += 1; @@ -332,7 +332,7 @@ impl TableComponent { let selected_column_index = widths.len().saturating_sub(1); let mut column_index = far_right_column_index + 1; while widths.iter().map(|(_, width)| width).sum::() + widths.len() - <= area_width.saturating_sub(number_column_width) as usize + < area_width.saturating_sub(number_column_width) as usize { let length = self .rows diff --git a/src/config.rs b/src/config.rs index 1c26f0e..5b0c07b 100644 --- a/src/config.rs +++ b/src/config.rs @@ -102,6 +102,8 @@ pub struct KeyConfig { pub tab_constraints: Key, pub tab_foreign_keys: Key, pub tab_indexes: Key, + pub extend_or_shorten_widget_width_to_right: Key, + pub extend_or_shorten_widget_width_to_left: Key, } impl Default for KeyConfig { @@ -136,6 +138,8 @@ impl Default for KeyConfig { tab_constraints: Key::Char('3'), tab_foreign_keys: Key::Char('4'), tab_indexes: Key::Char('5'), + extend_or_shorten_widget_width_to_right: Key::Char('>'), + extend_or_shorten_widget_width_to_left: Key::Char('<'), } } }