From 669151c70e9dcadd781a07d4be187c2afc14b94d Mon Sep 17 00:00:00 2001 From: Arijit Basu Date: Thu, 4 Mar 2021 13:33:14 +0530 Subject: [PATCH] Show help menu --- README.md | 6 ++--- src/app.rs | 73 ++++++++++++++++++++++++++++++++++++++++++---------- src/input.rs | 8 +++++- src/main.rs | 29 ++++++++++++++++++--- src/ui.rs | 23 +++++++++++++++-- 5 files changed, 116 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index d4d5ece..721334d 100644 --- a/README.md +++ b/README.md @@ -8,13 +8,13 @@ Example usage: ```bash # Edit file -vim $(xplr) +vim "$(xplr)" # Copy file(s) -cp $(xplr) $(xplr) +cp "$(xplr)" "$(xplr)/" # Search and move file -mv $(fzf) $(xplr) +mv "$(fzf)" "$(xplr)/" ``` diff --git a/src/app.rs b/src/app.rs index 1feeee8..27344c7 100644 --- a/src/app.rs +++ b/src/app.rs @@ -254,6 +254,26 @@ pub struct DirectoryItemMetadata { pub total: usize, } +pub fn parse_help_menu<'a>( + kb: impl Iterator))>, +) -> Vec<(String, String)> { + let mut m = kb + .map(|(k, a)| { + ( + a.0.clone(), + serde_yaml::to_string(k) + .unwrap() + .strip_prefix("---") + .unwrap_or_default() + .trim() + .to_string(), + ) + }) + .collect::>(); + m.sort(); + m +} + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct App { pub version: String, @@ -263,6 +283,7 @@ pub struct App { pub selected_paths: HashSet, pub mode: Mode, pub parsed_key_bindings: HashMap)>, + pub parsed_help_menu: Vec<(String, String)>, pub show_hidden: bool, pub call: Option, pub result: Option, @@ -289,6 +310,8 @@ impl App { let parsed_key_bindings = config.key_bindings.clone().filtered(&mode); + let parsed_help_menu = parse_help_menu(parsed_key_bindings.iter()); + Ok(Self { version: VERSION.into(), config: config.to_owned(), @@ -297,6 +320,7 @@ impl App { selected_paths: selected_paths.to_owned(), mode, parsed_key_bindings, + parsed_help_menu, show_hidden, result: None, call: None, @@ -526,8 +550,8 @@ impl App { } pub fn back(self) -> Result { - let app = self.clone(); - self.focus_path(&app.directory_buffer.pwd) + let pwd = self.directory_buffer.pwd.clone(); + self.focus_path(&pwd) } pub fn select(self) -> Result { @@ -541,10 +565,15 @@ impl App { }) .unwrap_or_else(|| self.selected_paths.clone()); - let mut app = self; - app.selected_paths = selected_paths; - app.mode = Mode::Select; - Ok(app) + Self::new( + &self.config, + &self.directory_buffer.pwd, + &self.saved_buffers, + &selected_paths, + Mode::Select, + self.show_hidden, + self.directory_buffer.focus, + ) } pub fn toggle_selection(self) -> Result { @@ -568,16 +597,34 @@ impl App { Mode::Select }; - let mut app = self; - app.selected_paths = selected_paths; - app.mode = mode; - Ok(app) + Self::new( + &self.config, + &self.directory_buffer.pwd, + &self.saved_buffers, + &selected_paths, + mode, + self.show_hidden, + self.directory_buffer.focus, + ) } pub fn enter_submode(self, submode: &String) -> Result { - let mut app = self; - app.mode = Mode::ExploreSubmode(submode.clone()); - Ok(app) + let mode = match self.mode { + Mode::Explore => Mode::ExploreSubmode(submode.clone()), + Mode::ExploreSubmode(_) => Mode::ExploreSubmode(submode.clone()), + Mode::Select => Mode::SelectSubmode(submode.clone()), + Mode::SelectSubmode(_) => Mode::SelectSubmode(submode.clone()), + }; + + Self::new( + &self.config, + &self.directory_buffer.pwd, + &self.saved_buffers, + &self.selected_paths, + mode, + self.show_hidden, + self.directory_buffer.focus, + ) } pub fn print_focused(self) -> Result { diff --git a/src/input.rs b/src/input.rs index 8bf1c11..f55e252 100644 --- a/src/input.rs +++ b/src/input.rs @@ -1,5 +1,5 @@ -use termion::event::Key as TermionKey; use serde::{Deserialize, Serialize}; +use termion::event::Key as TermionKey; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(rename_all = "kebab-case")] @@ -246,6 +246,12 @@ pub enum Key { NotSupported, } +impl std::fmt::Display for Key { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + impl Key { pub fn from_termion_event(key: TermionKey) -> Self { match key { diff --git a/src/main.rs b/src/main.rs index c9ac7b7..bd8a139 100644 --- a/src/main.rs +++ b/src/main.rs @@ -48,7 +48,15 @@ fn main() -> Result<(), Error> { let mut list_state = ListState::default(); term::enable_raw_mode().unwrap(); - terminal.draw(|f| ui::draw(&app, &hb, f, &mut table_state, &mut list_state))?; + terminal.draw(|f| { + ui::draw( + &app, + &hb, + f, + &mut table_state, + &mut list_state, + ) + })?; let mut result = Ok(()); 'outer: for key in keys { @@ -56,8 +64,15 @@ fn main() -> Result<(), Error> { for action in actions.iter() { app = match app.handle(action) { Ok(mut a) => { - terminal - .draw(|f| ui::draw(&a, &hb, f, &mut table_state, &mut list_state))?; + terminal.draw(|f| { + ui::draw( + &a, + &hb, + f, + &mut table_state, + &mut list_state, + ) + })?; if let Some(result) = a.result.clone() { term::disable_raw_mode().unwrap(); @@ -89,7 +104,13 @@ fn main() -> Result<(), Error> { terminal = Terminal::new(backend)?; a = a.refresh()?; terminal.draw(|f| { - ui::draw(&a, &hb, f, &mut table_state, &mut list_state) + ui::draw( + &a, + &hb, + f, + &mut table_state, + &mut list_state, + ) })?; }; diff --git a/src/ui.rs b/src/ui.rs index 5f1c902..bb39f76 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -102,7 +102,11 @@ pub fn draw( .focus .map(app::DirectoryBuffer::relative_focus), ); - f.render_stateful_widget(table, chunks[0], table_state); + + let left_chunks = Layout::default() + .direction(Direction::Vertical) + .constraints([TUIConstraint::Percentage(40), TUIConstraint::Percentage(60)].as_ref()) + .split(chunks[1]); let selected: Vec = app .selected_paths @@ -120,5 +124,20 @@ pub fn draw( .borders(Borders::ALL) .title(format!(" Selected ({}) ", selected_count)), ); - f.render_stateful_widget(selected_list, chunks[1], list_state); + + // Help menu + let help_menu_rows: Vec = app + .parsed_help_menu + .clone() + .iter() + .map(|(h, k)| Row::new(vec![Cell::from(h.to_string()), Cell::from(k.to_string())])) + .collect(); + + let help_menu = Table::new(help_menu_rows) + .block(Block::default().borders(Borders::ALL).title(" Help ")) + .widths(&[TUIConstraint::Percentage(40), TUIConstraint::Percentage(60)]); + + f.render_stateful_widget(table, chunks[0], table_state); + f.render_stateful_widget(selected_list, left_chunks[0], list_state); + f.render_widget(help_menu, left_chunks[1]); }