diff options
author | Vinegret43 <67828321+Vinegret43@users.noreply.github.com> | 2021-10-02 15:20:02 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-10-02 08:20:02 -0400 |
commit | 5e3839ad3255d7056c00d09e479c234b87730ba8 (patch) | |
tree | c64f16062563c73571b24d5e4baf5bef866bf610 | |
parent | 44c1952831abc4bc8496dfd60e72e47dcdc45caa (diff) |
Add a help page (#95)
* add basic help page functionality
change search_skim keybind
* refactor 'run' function, improve sorting
* add search functionality for help page
improve some comments in tui_help
-rw-r--r-- | config/keymap.toml | 3 | ||||
-rw-r--r-- | src/commands/command_keybind.rs | 7 | ||||
-rw-r--r-- | src/commands/command_line.rs | 4 | ||||
-rw-r--r-- | src/commands/help.rs | 94 | ||||
-rw-r--r-- | src/commands/key_command.rs | 104 | ||||
-rw-r--r-- | src/commands/mod.rs | 1 | ||||
-rw-r--r-- | src/commands/rename_file.rs | 18 | ||||
-rw-r--r-- | src/config/keymap/keymapping.rs | 4 | ||||
-rw-r--r-- | src/run.rs | 11 | ||||
-rw-r--r-- | src/ui/widgets/mod.rs | 2 | ||||
-rw-r--r-- | src/ui/widgets/tui_help.rs | 174 | ||||
-rw-r--r-- | src/util/input.rs | 16 |
12 files changed, 416 insertions, 22 deletions
diff --git a/config/keymap.toml b/config/keymap.toml index 606d0c1..a4ae906 100644 --- a/config/keymap.toml +++ b/config/keymap.toml @@ -69,7 +69,7 @@ mapcommand = [ { keys = [ "/" ], command = ":search " }, { keys = [ "\\" ], command = ":search_glob " }, - { keys = [ "?" ], command = ":search_skim " }, + { keys = [ "%", "s" ], command = ":search_skim " }, { keys = [ "n" ], command = "search_next" }, { keys = [ "N" ], command = "search_prev" }, @@ -86,4 +86,5 @@ mapcommand = [ { keys = [ "g", "d" ], command = "cd ~/Downloads" }, { keys = [ "g", "e" ], command = "cd /etc" }, { keys = [ "g", "h" ], command = "cd ~/" }, + { keys = [ "?" ], command = "help" } ] diff --git a/src/commands/command_keybind.rs b/src/commands/command_keybind.rs index 6fff00f..afe87ef 100644 --- a/src/commands/command_keybind.rs +++ b/src/commands/command_keybind.rs @@ -21,7 +21,12 @@ impl std::fmt::Display for CommandKeybind { } pub trait AppExecute { - fn execute(&self, context: &mut AppContext, backend: &mut TuiBackend) -> JoshutoResult<()>; + fn execute( + &self, + context: &mut AppContext, + backend: &mut TuiBackend, + keymap_t: &AppKeyMapping, + ) -> JoshutoResult<()>; } pub trait AppCommand: AppExecute + std::fmt::Display + std::fmt::Debug {} diff --git a/src/commands/command_line.rs b/src/commands/command_line.rs index 0c80aa2..e9bcc07 100644 --- a/src/commands/command_line.rs +++ b/src/commands/command_line.rs @@ -1,6 +1,7 @@ use std::str::FromStr; use crate::commands::KeyCommand; +use crate::config::AppKeyMapping; use crate::context::AppContext; use crate::error::JoshutoResult; use crate::ui::views::TuiTextField; @@ -11,6 +12,7 @@ use super::AppExecute; pub fn readline( context: &mut AppContext, backend: &mut TuiBackend, + keymap_t: &AppKeyMapping, prefix: &str, suffix: &str, ) -> JoshutoResult<()> { @@ -24,7 +26,7 @@ pub fn readline( if let Some(s) = user_input { let trimmed = s.trim_start(); let command = KeyCommand::from_str(trimmed)?; - command.execute(context, backend) + command.execute(context, backend, keymap_t) } else { Ok(()) } diff --git a/src/commands/help.rs b/src/commands/help.rs new file mode 100644 index 0000000..3a01d91 --- /dev/null +++ b/src/commands/help.rs @@ -0,0 +1,94 @@ +use termion::event::{Event, Key}; + +use crate::commands::{CommandKeybind, KeyCommand}; +use crate::config::AppKeyMapping; +use crate::context::AppContext; +use crate::error::JoshutoResult; +use crate::event::AppEvent; +use crate::ui::widgets; +use crate::ui::widgets::TuiHelp; +use crate::ui::TuiBackend; +use crate::util::input; + +pub fn help_loop( + context: &mut AppContext, + backend: &mut TuiBackend, + keymap_t: &AppKeyMapping, +) -> JoshutoResult<()> { + context.flush_event(); + + let mut offset = 0; + let mut search_query = String::new(); + let mut sort_by = 1; + + loop { + let keymap = if search_query.is_empty() { + widgets::get_keymap_table(keymap_t, &search_query, sort_by) + } else { + widgets::get_keymap_table(keymap_t, &search_query[1..], sort_by) + }; + backend.render(TuiHelp::new(&keymap, &mut offset, &search_query)); + + let event = match context.poll_event() { + Ok(event) => event, + Err(_) => return Ok(()), + }; + + match event { + AppEvent::Termion(event) => { + if search_query.is_empty() { + match event { + Event::Key(Key::Esc) => break, + Event::Key(Key::Char('1')) => sort_by = 0, + Event::Key(Key::Char('2')) => sort_by = 1, + Event::Key(Key::Char('3')) => sort_by = 2, + Event::Key(Key::Char('/')) => search_query.push('/'), + event => { + if let Some(CommandKeybind::SimpleKeybind(command)) = + keymap_t.as_ref().get(&event) + { + match command { + KeyCommand::CursorMoveUp(_) => move_offset(&mut offset, -1), + KeyCommand::CursorMoveDown(_) => move_offset(&mut offset, 1), + KeyCommand::CursorMoveHome => offset = 0, + KeyCommand::CursorMoveEnd => offset = 255, + KeyCommand::CursorMovePageUp => move_offset(&mut offset, -10), + KeyCommand::CursorMovePageDown => move_offset(&mut offset, 10), + KeyCommand::CloseTab | KeyCommand::Help => break, + _ => (), + } + } + } + } + } else { + match event { + Event::Key(Key::Esc) => search_query.clear(), + Event::Key(Key::Backspace) => { + search_query.pop(); + } + Event::Key(Key::Char(chr)) => search_query.push(chr), + _ => (), + } + } + context.flush_event(); + } + _ => input::process_noninteractive(event, context), + } + } + + Ok(()) +} + +// offset is a u8, so if we make it negative program will fail. +// This function prevents this error +fn move_offset(offset: &mut u8, moving_amount: i8) { + if moving_amount > 0 { + *offset += moving_amount as u8; + } else if moving_amount < 0 { + if *offset > -moving_amount as u8 { + *offset -= -moving_amount as u8; + } else { + *offset = 0; + } + } +} diff --git a/src/commands/key_command.rs b/src/commands/key_command.rs index bd6c45c..9c99270 100644 --- a/src/commands/key_command.rs +++ b/src/commands/key_command.rs @@ -2,6 +2,7 @@ use std::path; use termion::event::Key; +use crate::config::AppKeyMapping; use crate::context::AppContext; use crate::error::{JoshutoError, JoshutoErrorKind, JoshutoResult}; use crate::io::IoWorkerOptions; @@ -76,6 +77,7 @@ pub enum KeyCommand { NewTab, CloseTab, TabSwitch(i32), + Help, } impl KeyCommand { @@ -138,6 +140,92 @@ impl KeyCommand { Self::SortReverse => "sort reverse", Self::TabSwitch(_) => "tab_switch", + Self::Help => "help", + } + } + + // These comments are displayed at the help page + pub fn comment(&self) -> &'static str { + match self { + Self::BulkRename => "Bulk rename", + Self::ChangeDirectory(_) => "Change directory", + Self::NewTab => "Open a new tab", + Self::CloseTab => "Close current tab", + Self::CommandLine(command, _) => match command.trim() { + "cd" => "Change directory", + "search" => "Open a search prompt", + "search_glob" => "Glob search", + "rename" => "Rename selected file", + "touch" => "Touch file", + "mkdir" => "Make a new directory", + _ => "Open a command line", + }, + + Self::CutFiles => "Cut selected files", + Self::CopyFiles => "Copy selected files", + Self::PasteFiles(IoWorkerOptions { + overwrite, + skip_exist, + }) => match (overwrite, skip_exist) { + (true, false) => "Paste, overwrite", + (false, true) => "Paste, skip existing files", + _ => "Paste", + }, + Self::CopyFileName => "Copy filename", + Self::CopyFileNameWithoutExtension => "Copy filename without extension", + Self::CopyFilePath => "Copy path to file", + Self::CopyDirPath => "Copy directory name", + + Self::CursorMoveUp(_) => "Move cursor up", + Self::CursorMoveDown(_) => "Move cursor down", + Self::CursorMoveHome => "Move cursor to the very top", + Self::CursorMoveEnd => "Move cursor to the ver bottom", + Self::CursorMovePageUp => "Move cursor one page up", + Self::CursorMovePageDown => "Move cursor one page down", + + Self::ParentCursorMoveUp(_) => "Cursor up in parent list", + Self::ParentCursorMoveDown(_) => "Cursor down in parent list", + + Self::DeleteFiles => "Delete selected files", + Self::NewDirectory(_) => "Make a new directory", + Self::OpenFile => "Open a file", + Self::OpenFileWith(_) => "Open using selected program", + Self::ParentDirectory => "CD to parent directory", + + Self::Quit => "Quit the program", + Self::QuitToCurrentDirectory => "Quit to current directory", + Self::ForceQuit => "Force quit", + Self::ReloadDirList => "Reload current dir listing", + Self::RenameFile(_) => "Rename file", + Self::TouchFile(_) => "Touch file", + Self::RenameFileAppend => "Rename a file", + Self::RenameFilePrepend => "Rename a file", + + Self::SearchString(_) => "Search", + Self::SearchGlob(_) => "Search with globbing", + Self::SearchSkim => "Search via skim", + Self::SearchNext => "Next search entry", + Self::SearchPrev => "Previous search entry", + + Self::SelectFiles(_, _) => "Select file", + Self::SetMode => "Set file permissions", + Self::SubProcess(_, false) => "Run a shell command", + Self::SubProcess(_, true) => "Run commmand in background", + Self::ShowWorkers(_) => "Show IO workers", + + Self::ToggleHiddenFiles => "Toggle hidden files displaying", + + Self::Sort(sort_type) => match sort_type { + SortType::Lexical => "Sort lexically", + SortType::Mtime => "Sort by modifiaction time", + SortType::Natural => "Sort naturally", + SortType::Size => "Sort by size", + SortType::Ext => "Sort by extension", + }, + Self::SortReverse => "Reverse sort order", + + Self::TabSwitch(_) => "Swith to the next tab", + Self::Help => "Open this help page", } } } @@ -369,6 +457,7 @@ impl std::str::FromStr for KeyCommand { )), }, "toggle_hidden" => Ok(Self::ToggleHiddenFiles), + "help" => Ok(Self::Help), inp => Err(JoshutoError::new( JoshutoErrorKind::UnrecognizedCommand, format!("Unrecognized command '{}'", inp), @@ -378,7 +467,12 @@ impl std::str::FromStr for KeyCommand { } impl AppExecute for KeyCommand { - fn execute(&self, context: &mut AppContext, backend: &mut TuiBackend) -> JoshutoResult<()> { + fn execute( + &self, + context: &mut AppContext, + backend: &mut TuiBackend, + keymap_t: &AppKeyMapping, + ) -> JoshutoResult<()> { match &*self { Self::BulkRename => bulk_rename::bulk_rename(context, backend), Self::ChangeDirectory(p) => { @@ -388,7 +482,7 @@ impl AppExecute for KeyCommand { Self::NewTab => tab_ops::new_tab(context), Self::CloseTab => tab_ops::close_tab(context), Self::CommandLine(p, s) => { - command_line::readline(context, backend, p.as_str(), s.as_str()) + command_line::readline(context, backend, keymap_t, p.as_str(), s.as_str()) } Self::CutFiles => file_ops::cut(context), Self::CopyFiles => file_ops::copy(context), @@ -426,8 +520,8 @@ impl AppExecute for KeyCommand { Self::ReloadDirList => reload::reload_dirlist(context), Self::RenameFile(p) => rename_file::rename_file(context, p.as_path()), - Self::RenameFileAppend => rename_file::rename_file_append(context, backend), - Self::RenameFilePrepend => rename_file::rename_file_prepend(context, backend), + Self::RenameFileAppend => rename_file::rename_file_append(context, backend, keymap_t), + Self::RenameFilePrepend => rename_file::rename_file_prepend(context, backend, keymap_t), Self::TouchFile(arg) => touch_file::touch_file(context, arg.as_str()), Self::SearchGlob(pattern) => search_glob::search_glob(context, pattern.as_str()), Self::SearchString(pattern) => search_string::search_string(context, pattern.as_str()), @@ -453,6 +547,8 @@ impl AppExecute for KeyCommand { tab_ops::tab_switch(*i, context)?; Ok(()) } + + Self::Help => help::help_loop(context, backend, keymap_t), } } } diff --git a/src/commands/mod.rs b/src/commands/mod.rs index bcf4b3a..d294b60 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -4,6 +4,7 @@ pub mod command_line; pub mod cursor_move; pub mod delete_files; pub mod file_ops; +pub mod help; pub mod new_directory; pub mod open_file; pub mod parent_cursor_move; diff --git a/src/commands/rename_file.rs b/src/commands/rename_file.rs index 718aef8..1386211 100644 --- a/src/commands/rename_file.rs +++ b/src/commands/rename_file.rs @@ -1,5 +1,6 @@ use std::path; +use crate::config::AppKeyMapping; use crate::context::AppContext; use crate::error::JoshutoResult; use crate::history::create_dirlist_with_history; @@ -52,6 +53,7 @@ pub fn rename_file(context: &mut AppContext, dest: &path::Path) -> JoshutoResult pub fn _rename_file_append( context: &mut AppContext, backend: &mut TuiBackend, + keymap_t: &AppKeyMapping, file_name: &str, ) -> JoshutoResult<()> { let (prefix, suffix): (String, String) = match file_name.rfind('.') { @@ -61,10 +63,14 @@ pub fn _rename_file_append( ), None => (format!("rename {}", file_name), "".to_string()), }; - command_line::readline(context, backend, &prefix, &suffix) + command_line::readline(context, backend, keymap_t, &prefix, &suffix) } -pub fn rename_file_append(context: &mut AppContext, backend: &mut TuiBackend) -> JoshutoResult<()> { +pub fn rename_file_append( + context: &mut AppContext, + backend: &mut TuiBackend, + keymap_t: &AppKeyMapping, +) -> JoshutoResult<()> { let mut file_name: Option<String> = None; if let Some(curr_list) = context.tab_context_ref().curr_tab_ref().curr_list_ref() { @@ -74,7 +80,7 @@ pub fn rename_file_append(context: &mut AppContext, backend: &mut TuiBackend) -> } if let Some(file_name) = file_name { - _rename_file_append(context, backend, file_name.as_str())?; + _rename_file_append(context, backend, keymap_t, file_name.as_str())?; } Ok(()) } @@ -82,16 +88,18 @@ pub fn rename_file_append(context: &mut AppContext, backend: &mut TuiBackend) -> pub fn _rename_file_prepend( context: &mut AppContext, backend: &mut TuiBackend, + keymap_t: &AppKeyMapping, file_name: String, ) -> JoshutoResult<()> { let prefix = String::from("rename "); let suffix = file_name; - command_line::readline(context, backend, &prefix, &suffix) + command_line::readline(context, backend, keymap_t, &prefix, &suffix) } pub fn rename_file_prepend( context: &mut AppContext, backend: &mut TuiBackend, + keymap_t: &AppKeyMapping, ) -> JoshutoResult<()> { let mut file_name: Option<String> = None; @@ -102,7 +110,7 @@ pub fn rename_file_prepend( } if let Some(file_name) = file_name { - _rename_file_prepend(context, backend, file_name)?; + _rename_file_prepend(context, backend, keymap_t, file_name)?; } Ok(()) } diff --git a/src/config/keymap/keymapping.rs b/src/config/keymap/keymapping.rs index 4a2e24e..071bdf7 100644 --- a/src/config/keymap/keymapping.rs +++ b/src/config/keymap/keymapping.rs @@ -236,6 +236,10 @@ impl AppKeyMapping { let keys = [Event::Key(Key::Char('c')), Event::Key(Key::Char('w'))]; insert_keycommand(&mut m, cmd, &keys)?; + let cmd = KeyCommand::Help; + let keys = [Event::Key(Key::Char('?'))]; + insert_keycommand(&mut m, cmd, &keys)?; + Ok(()) } } @@ -37,9 +37,10 @@ pub fn run( Ok(event) => event, Err(_) => return Ok(()), // TODO }; + match event { AppEvent::Termion(Event::Mouse(event)) => { - input::process_mouse(event, context, backend); + input::process_mouse(event, context, backend, &keymap_t); preview_default::load_preview(context, backend); } AppEvent::Termion(key) => { @@ -49,13 +50,13 @@ pub fn run( match key { Event::Unsupported(s) if s.as_slice() == [27, 79, 65] => { let command = KeyCommand::CursorMoveUp(1); - if let Err(e) = command.execute(context, backend) { + if let Err(e) = command.execute(context, backend, &keymap_t) { context.message_queue_mut().push_error(e.to_string()); } } Event::Unsupported(s) if s.as_slice() == [27, 79, 66] => { let command = KeyCommand::CursorMoveDown(1); - if let Err(e) = command.execute(context, backend) { + if let Err(e) = command.execute(context, backend, &keymap_t) { context.message_queue_mut().push_error(e.to_string()); } } @@ -66,7 +67,7 @@ pub fn run( .push_info(format!("Unmapped input: {}", key.to_string())); } Some(CommandKeybind::SimpleKeybind(command)) => { - if let Err(e) = command.execute(context, backend) { + if let Err(e) = command.execute(context, backend, &keymap_t) { context.message_queue_mut().push_error(e.to_string()); } } @@ -77,7 +78,7 @@ pub fn run( }; if let Some(command) = cmd { - if let Err(e) = command.execute(context, backend) { + if let Err(e) = command.execute(context, backend, &keymap_t) { context.message_queue_mut().push_error(e.to_string()); } } diff --git a/src/ui/widgets/mod.rs b/src/ui/widgets/mod.rs index 6319d91..12e65b4 100644 --- a/src/ui/widgets/mod.rs +++ b/src/ui/widgets/mod.rs @@ -2,6 +2,7 @@ mod tui_dirlist; mod tui_dirlist_detailed; mod tui_file_preview; mod tui_footer; +mod tui_help; mod tui_menu; mod tui_prompt; mod tui_tab; @@ -13,6 +14,7 @@ pub use self::tui_dirlist::TuiDirList; pub use self::tui_dirlist_detailed::{trim_file_label, TuiDirListDetailed}; pub use self::tui_file_preview::TuiFilePreview; pub use self::tui_footer::TuiFooter; +pub use self::tui_help::{get_keymap_table, TuiHelp}; pub use self::tui_menu::TuiMenu; pub use self::tui_prompt::TuiPrompt; pub use self::tui_tab::TuiTabBar; diff --git a/src/ui/widgets/tui_help.rs b/src/ui/widgets/tui_help.rs new file mode 100644 index 0000000..da4f6ed --- /dev/null +++ b/src/ui/widgets/tui_help.rs @@ -0,0 +1,174 @@ +use tui::buffer::Buffer; +use tui::layout::{Constraint, Rect}; +use tui::style::{Color, Modifier, Style}; +use tui::widgets::{Cell, Row, Table, Widget}; + +use crate::commands::CommandKeybind; +use crate::config::AppKeyMapping; +use termion::event::{Event, Key}; + +use lazy_static::lazy_static; + +lazy_static! { + static ref COMMENT_STYLE: Style = Style::default().add_modifier(Modifier::REVERSED); + static ref DEFAULT_STYLE: Style = Style::default(); + static ref HEADER_STYLE: Style = Style::default().fg(Color::Yellow); + static ref KEY_STYLE: Style = Style::default().fg(Color::Green); + static ref COMMAND_STYLE: Style = Style::default().fg(Color::Blue); +} + +const TITLE: &str = "Keybindings"; +const FOOTER: &str = "Press <ESC> to return, / to search, 1,2,3 to sort"; + +pub struct TuiHelp<'a> { + // This keymap is constructed with get_keymap_table function + keymap: &'a Vec<Row<'a>>, + offset: &'a mut u8, + search_query: &'a str, +} + +impl<'a> TuiHelp<'a> { + pub fn new(keymap: &'a Vec<Row>, offset: &'a mut u8, search_query: &'a str) -> TuiHelp<'a> { + TuiHelp { + keymap, + offset, + search_query, + } + } +} + +impl<'a> Widget for TuiHelp<'a> { + fn render(self, area: Rect, buf: &mut Buffer) { + // Subtracting 2 because we'll draw a title at the top and some + // additional information at the bottom of the page + let height = (area.bottom() - area.top() - 2) as i16; + let width = area.right() - area.left(); + let max_offset = Ord::max(self.keymap.len() as i16 - height + 2, 0) as u8; + if *self.offset > max_offset { + *self.offset = max_offset; + } + let keymap = Vec::from(&self.keymap[(*self.offset as usize)..]); + + let keybindings_area = Rect::new(0, 1, width, height as u16); + let mut keybindings_buffer = Buffer::default(); + keybindings_buffer.resize(keybindings_area); + let widths = [ + Constraint::Length((width as f32 * 0.12) as u16), + Constraint::Length((width as f32 * 0.50) as u16), + Constraint::Length((width as f32 * 0.38) as u16), + ]; + let table_widget = Table::new(keymap) + .header( + Row::new(vec!["Key", "Command", "Description"]) + .style(*HEADER_STYLE) + .bottom_margin(1), + ) + .widths(&widths) + .column_spacing(1); + + table_widget.render(keybindings_area, &mut keybindings_buffer); + buf.merge(&keybindings_buffer); + buf.set_stringn( + 0, + 0, + format!("{:^w$}", TITLE, w = width as usize), + width as usize, + *COMMENT_STYLE, + ); + + let footer = if self.search_query.is_empty() { + format!("{:^w$}", FOOTER, w = width as usize) + } else { + format!("{:<w$}", self.search_query, w = width as usize) + }; + buf.set_stringn( + 0, + (height + 1) as u16, + &footer, + footer.len(), + *COMMENT_STYLE, + ); + } +} + +// Translates output from 'get_raw_keymap_table' into format, +// readable by TUI table widget +pub fn get_keymap_table<'a>( + keymap: &'a AppKeyMapping, + search_query: &'a str, + sort_by: usize, +) -> Vec<Row<'a>> { + let raw_rows = get_raw_keymap_table(keymap, search_query, sort_by); + let mut rows = Vec::new(); + for row in raw_rows { + rows.push(Row::new(vec![ + Cell::from(row[0].clone()).style(*KEY_STYLE), + Cell::from(row[1].clone()).style(*COMMAND_STYLE), + Cell::from(row[2].clone()).style(*DEFAULT_STYLE), + ])); + } + rows +} + +// This function is needed because we cannot access Row items, which +// means that we won't be able to sort binds if we create Rows directly +pub fn get_raw_keymap_table<'a>( + keymap: &'a AppKeyMapping, + search_query: &'a str, + sort_by: usize, +) -> Vec<[String; 3]> { + let mut rows = Vec::new(); + for (event, bind) in keymap.as_ref() { + let key = key_event_to_string(event); + let (command, comment) = match bind { + CommandKeybind::SimpleKeybind(command) => (format!("{}", command), command.comment()), + CommandKeybind::CompositeKeybind(sub_keymap) => { + let mut sub_rows = get_raw_keymap_table(sub_keymap, "", sort_by); + for _ in 0..sub_rows.len() { + let mut sub_row = sub_rows.pop().unwrap(); + sub_row[0] = key.clone() + &sub_row[0]; + if sub_row[0].contains(search_query) || sub_row[1].contains(search_query) { + rows.push(sub_row) + } + } + continue; + } + }; + if key.contains(search_query) || command.contains(search_query) { + rows.push([key, command, comment.to_string()]); + } + } + rows.sort_by_cached_key(|x| x[sort_by].clone()); + rows +} + +fn key_event_to_string(event: &Event) -> String { + match event { + Event::Key(key) => match key { + Key::Backspace => "Backspace".to_string(), + Key::Left => "Left".to_string(), + Key::Right => "Right".to_string(), + Key::Up => "Up".to_string(), + Key::Down => "Down".to_string(), + Key::Home => "Home".to_string(), + Key::End => "End".to_string(), + Key::PageUp => "PageUp".to_string(), + Key::PageDown => "PageDown".to_string(), + Key::BackTab => "BackTab".to_string(), + Key::Delete => "Delete".to_string(), + Key::Insert => "Insert".to_string(), + Key::Esc => "Esc".to_string(), + Key::F(n) => format!("F{}", n), + Key::Char(chr) => match chr { + ' ' => "Space".to_string(), + '\t' => "Tab".to_string(), + '\n' => "Enter".to_string(), + chr => chr.to_string(), + }, + Key::Alt(chr) => format!("Alt+{}", chr), + Key::Ctrl(chr) => format!("Ctrl+{}", chr), + _ => "".to_string(), + }, + _ => "".to_string(), + } +} diff --git a/src/util/input.rs b/src/util/input.rs index 9aa2231..48e416c 100644 --- a/src/util/input.rs +++ b/src/util/input.rs @@ -7,6 +7,7 @@ use termion::event::{MouseButton, MouseEvent}; use tui::layout::{Constraint, Direction, Layout}; use crate::commands::{cursor_move, parent_cursor_move, AppExecute, KeyCommand}; +use crate::config::AppKeyMapping; use crate::context::AppContext; use crate::event::AppEvent; use crate::fs::JoshutoDirList; @@ -93,7 +94,12 @@ pub fn process_file_preview( } } -pub fn process_mouse(event: MouseEvent, context: &mut AppContext, backend: &mut ui::TuiBackend) { +pub fn process_mouse( + event: MouseEvent, + context: &mut AppContext, + backend: &mut ui::TuiBackend, + keymap_t: &AppKeyMapping, +) { let f_size = backend.terminal.as_ref().unwrap().size().unwrap(); let constraints: &[Constraint; 3] = &context.config_ref().display_options_ref().default_layout; @@ -113,12 +119,12 @@ pub fn process_mouse(event: MouseEvent, context: &mut AppContext, backend: &mut MouseEvent::Press(MouseButton::WheelUp, x, _) => { if x < layout_rect[1].x { let command = KeyCommand::ParentCursorMoveUp(1); - if let Err(e) = command.execute(context, backend) { + if let Err(e) = command.execute(context, backend, keymap_t) { context.message_queue_mut().push_error(e.to_string()); } } else if x < layout_rect[2].x { let command = KeyCommand::CursorMoveUp(1); - if let Err(e) = command.execute(context, backend) { + if let Err(e) = command.execute(context, backend, keymap_t) { context.message_queue_mut().push_error(e.to_string()); } } else { @@ -128,12 +134,12 @@ pub fn process_mouse(event: MouseEvent, context: &mut AppContext, backend: &mut MouseEvent::Press(MouseButton::WheelDown, x, _) => { if x < layout_rect[1].x { let command = KeyCommand::ParentCursorMoveDown(1); - if let Err(e) = command.execute(context, backend) { + if let Err(e) = command.execute(context, backend, keymap_t) { context.message_queue_mut().push_error(e.to_string()); } } else if x < layout_rect[2].x { let command = KeyCommand::CursorMoveDown(1); - if let Err(e) = command.execute(context, backend) { + if let Err(e) = command.execute(context, backend, keymap_t) { context.message_queue_mut().push_error(e.to_string()); } } else { |