diff options
author | Tim Oram <dev@mitmaro.ca> | 2019-07-15 21:53:57 -0230 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-07-15 21:53:57 -0230 |
commit | 71ca096faa7e6c507b2d9bfe20974205e27b9e39 (patch) | |
tree | 131a52d08c403caf2dfd4297ffca95662f696bc6 | |
parent | 98fa4e5754eadbef23ec74d75df5cf06bb3abc15 (diff) | |
parent | 90930bf702a7ed8b04fce778acfe0b0b3bf7c16f (diff) |
Merge pull request #149 from MitMaro/tim/add-custom-key-bindings
Add custom key bindings
-rw-r--r-- | CHANGELOG.md | 1 | ||||
-rw-r--r-- | README.md | 53 | ||||
-rw-r--r-- | src/config.rs | 68 | ||||
-rw-r--r-- | src/constants.rs | 51 | ||||
-rw-r--r-- | src/help/help.rs | 51 | ||||
-rw-r--r-- | src/help/mod.rs | 1 | ||||
-rw-r--r-- | src/help/utils.rs | 90 | ||||
-rw-r--r-- | src/input/input_handler.rs | 79 | ||||
-rw-r--r-- | src/list/list.rs | 48 | ||||
-rw-r--r-- | src/list/utils.rs | 77 | ||||
-rw-r--r-- | src/main.rs | 4 | ||||
-rw-r--r-- | src/process/process.rs | 4 | ||||
-rw-r--r-- | src/view/view.rs | 15 |
13 files changed, 401 insertions, 141 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index d6ebe3b..ea070e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - The command of an exec action can now be edited - Visual mode - change action and reorder with multiple selections - Configuration option for vertical spacing character +- Configurable key bindings ## [1.0.0] - 2019-04-10 @@ -43,7 +43,9 @@ interactive-rebase-tool --version The tool has built-in help that can be accessed by hitting the `?` key. -### Key Bindings +### Default Key Bindings + +Key bindings can be configured, see [configuration](#configuration) for more information. | Key | Mode | Description | | ------------ | ------ | ----------- | @@ -93,21 +95,54 @@ git config --global interactive-rebase-tool.foregroundColor black | Key | Default | Type | Description | | -------------------------- | ------- | ------ | ----------- | | `autoSelectNext` | false | bool | If true, auto select the next line after action modification | -| `foregroundColor` | white | Color | Color used for most text and the UI | -| `indicatorColor` | cyan | Color | Color used for text the indicates or needs to standout | -| `errorColor` | red | Color | Color used for showing error messages | +| `breakColor` | white | Color | Color used for the break action | | `diffAddColor` | green | Color | Color used for lines and files added in a diff | -| `diffRemoveColor` | red | Color | Color used for lines and files removed in a diff | | `diffChangeColor` | yellow | Color | Color used for lines and files changed in a diff | -| `breakColor` | white | Color | Color used for the break action | +| `diffRemoveColor` | red | Color | Color used for lines and files removed in a diff | +| `dropColor` | red | Color | Color used for the drop action | +| `editColor` | blue | Color | Color used for the edit action | +| `errorColor` | red | Color | Color used for showing error messages | +| `fixupColor` | magenta | Color | Color used for the fixup action | +| `foregroundColor` | white | Color | Color used for most text and the UI | +| `indicatorColor` | cyan | Color | Color used for text the indicates or needs to standout | +| `inputAbort` | q | String | Key for abort rebase with prompt | +| `inputActionBreak` | b | String | Key for setting action to rebase | +| `inputActionDrop` | d | String | Key for setting action to drop | +| `inputActionEdit` | e | String | Key for setting action to edit | +| `inputActionFixup` | f | String | Key for setting action to fixup | +| `inputActionPick` | p | String | Key for setting action to pick | +| `inputActionReword` | r | String | Key for setting action to reword | +| `inputActionSquash` | s | String | Key for setting action to squash | +| `inputConfirmNo` | n | String | Key for rejecting a confirmation | +| `inputConfirmYes` | y | String | Key for confirming a confirmation | +| `inputEdit` | E | String | Key for entering edit mode | +| `inputForceAbort` | Q | String | Key for forcing an abort of the rebase | +| `inputForceRebase` | W | String | Key for forcing a rebase | +| `inputHelp` | ? | String | Key for showing the help | +| `inputMoveDown` | Down | String | Key for moving the selected line(s) down | +| `inputMoveLeft` | Left | String | Key for moving the selected line(s) down | +| `inputMoveRight` | Right | String | Key for moving the selected line(s) down | +| `inputMoveSelectionDown` | j | String | Key for moving the selected line(s) down | +| `inputMoveSelectionUp` | k | String | Key for moving the selected line(s) up | +| `inputMoveUp` | Up | String | Key for moving the selected line(s) up | +| `inputOpenInExternalEditor`| ! | String | Key for opening the external editor | +| `inputRebase` | w | String | Key for rebasing with confirmation | +| `inputShowCommit` | c | String | Key for showing the selected commit | +| `inputToggleVisualMode` | v | String | Key for toggling visual mode | | `pickColor` | green | Color | Color used for the pick action | | `rewordColor` | yellow | Color | Color used for the reword action | -| `editColor` | blue | Color | Color used for the edit action | | `squashColor` | cyan | Color | Color used for the squash action | -| `fixupColor` | magenta | Color | Color used for the fixup action | -| `dropColor` | red | Color | Color used for the drop action | | `verticalSpacingCharacter` | ~ | String | Vertical spacing character. Can be set to an empty string. | +#### Special Keys + +| Key | Description | +| ------- | ----------- | +| `Down` | Down arrow key | +| `Left` | Left arrow key | +| `Right` | Right arrow key | +| `Up` | Up arrow key | + #### Valid Color Values The valid colors are the [eight original 8 ANSI colors][ANSIColors]. They are black, blue, cyan, green, magenta, red, diff --git a/src/config.rs b/src/config.rs index a899888..a1c73af 100644 --- a/src/config.rs +++ b/src/config.rs @@ -18,12 +18,54 @@ pub struct Config { pub fixup_color: Color, pub foreground_color: Color, pub indicator_color: Color, + pub input_abort: String, + pub input_action_break: String, + pub input_action_drop: String, + pub input_action_edit: String, + pub input_action_fixup: String, + pub input_action_pick: String, + pub input_action_reword: String, + pub input_action_squash: String, + pub input_confirm_no: String, + pub input_confirm_yes: String, + pub input_edit: String, + pub input_force_abort: String, + pub input_force_rebase: String, + pub input_help: String, + pub input_move_down: String, + pub input_move_selection_down: String, + pub input_move_selection_up: String, + pub input_move_up: String, + pub input_open_in_external_editor: String, + pub input_rebase: String, + pub input_show_commit: String, + pub input_toggle_visual_mode: String, pub pick_color: Color, pub reword_color: Color, pub squash_color: Color, pub vertical_spacing_character: String, } +fn get_input(config: &git2::Config, name: &str, default: &str) -> Result<String, String> { + let value = get_string(config, name, default)?; + + match value.to_lowercase().as_ref() { + "left" => Ok(String::from("Left")), + "right" => Ok(String::from("Right")), + "down" => Ok(String::from("Down")), + "up" => Ok(String::from("Up")), + _ => { + if value.len() > 1 { + return Err(format!( + "Error reading git config: {} must contain only one character", + name + )); + } + Ok(value) + }, + } +} + fn get_string(config: &git2::Config, name: &str, default: &str) -> Result<String, String> { match config.get_string(name) { Ok(v) => Ok(v), @@ -92,6 +134,32 @@ impl Config { fixup_color: get_color(&git_config, "interactive-rebase-tool.fixupColor", Color::Magenta)?, foreground_color: get_color(&git_config, "interactive-rebase-tool.foregroundColor", Color::White)?, indicator_color: get_color(&git_config, "interactive-rebase-tool.indicatorColor", Color::Cyan)?, + input_abort: get_input(&git_config, "interactive-rebase-tool.inputAbort", "q")?, + input_action_break: get_input(&git_config, "interactive-rebase-tool.inputActionBreak", "b")?, + input_action_drop: get_input(&git_config, "interactive-rebase-tool.inputActionDrop", "d")?, + input_action_edit: get_input(&git_config, "interactive-rebase-tool.inputActionEdit", "e")?, + input_action_fixup: get_input(&git_config, "interactive-rebase-tool.inputActionFixup", "f")?, + input_action_pick: get_input(&git_config, "interactive-rebase-tool.inputActionPick", "p")?, + input_action_reword: get_input(&git_config, "interactive-rebase-tool.inputActionReword", "r")?, + input_action_squash: get_input(&git_config, "interactive-rebase-tool.inputActionSquash", "s")?, + input_confirm_no: get_input(&git_config, "interactive-rebase-tool.inputConfirmNo", "n")?, + input_confirm_yes: get_input(&git_config, "interactive-rebase-tool.inputConfirmYes", "y")?, + input_edit: get_input(&git_config, "interactive-rebase-tool.inputEdit", "E")?, + input_force_abort: get_input(&git_config, "interactive-rebase-tool.inputForceAbort", "Q")?, + input_force_rebase: get_input(&git_config, "interactive-rebase-tool.inputForceRebase", "W")?, + input_help: get_input(&git_config, "interactive-rebase-tool.inputHelp", "?")?, + input_move_down: get_input(&git_config, "interactive-rebase-tool.inputMoveDown", "Down")?, + input_move_selection_down: get_input(&git_config, "interactive-rebase-tool.inputMoveSelectionDown", "j")?, + input_move_selection_up: get_input(&git_config, "interactive-rebase-tool.inputMoveSelectionUp", "k")?, + input_move_up: get_input(&git_config, "interactive-rebase-tool.inputMoveUp", "Up")?, + input_open_in_external_editor: get_input( + &git_config, + "interactive-rebase-tool.inputOpenInExternalEditor", + "!", + )?, + input_rebase: get_input(&git_config, "interactive-rebase-tool.inputRebase", "w")?, + input_show_commit: get_input(&git_config, "interactive-rebase-tool.inputShowCommit", "c")?, + input_toggle_visual_mode: get_input(&git_config, "interactive-rebase-tool.inputToggleVisualMode", "v")?, pick_color: get_color(&git_config, "interactive-rebase-tool.pickColor", Color::Green)?, reword_color: get_color(&git_config, "interactive-rebase-tool.rewordColor", Color::Yellow)?, squash_color: get_color(&git_config, "interactive-rebase-tool.squashColor", Color::Cyan)?, diff --git a/src/constants.rs b/src/constants.rs index 1b6e40e..c18818a 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -2,19 +2,8 @@ pub const TITLE: &str = "Git Interactive Rebase Tool"; pub const TITLE_LENGTH: i32 = 27; pub const TITLE_SHORT: &str = "Git Rebase"; pub const TITLE_SHORT_LENGTH: i32 = 10; -pub const TITLE_HELP_INDICATOR: &str = "Help: ?"; pub const TITLE_HELP_INDICATOR_LENGTH: i32 = 7; -pub const LIST_FOOTER_FULL: &str = " up, down, q/Q, w/W, c, j, k, b, p, r, e, s, f, d, E, !, ?"; -pub const LIST_FOOTER_FULL_WIDTH: usize = 58; -pub const LIST_FOOTER_COMPACT: &str = "up,dn.q/Q,w/W,c,j,k,b,p,r,e,s,f,d,E,!,?"; -pub const LIST_FOOTER_COMPACT_WIDTH: usize = 39; - -pub const VISUAL_MODE_FOOTER_FULL: &str = "(VISUAL) up, down, j, k, p, r, e, s, f, d, ?"; -pub const VISUAL_MODE_FOOTER_FULL_WIDTH: usize = 44; -pub const VISUAL_MODE_FOOTER_COMPACT: &str = "(V) up,down,j,k,p,r,e,s,f,d,?"; -pub const VISUAL_MODE_FOOTER_COMPACT_WIDTH: usize = 29; - pub const HEIGHT_ERROR_MESSAGE: &str = "Window too small, increase height to continue\n"; pub const MINIMUM_WINDOW_HEIGHT_ERROR_WIDTH: usize = 45; pub const SHORT_ERROR_MESSAGE: &str = "Window too small\n"; @@ -26,43 +15,3 @@ pub const MINIMUM_FULL_WINDOW_WIDTH: usize = 34; // " > squash cccccccc mmmmmmmm pub const NAME: &str = "interactive-rebase-tool"; pub const VERSION: &str = env!("CARGO_PKG_VERSION"); - -pub const LIST_HELP_LINES: &[(&str, &str)] = &[ - ("Up", "Move selection up"), - ("Down", "Move selection down"), - ("PgUp", "Move selection up 5 lines"), - ("PgDn", "Move selection down 5 lines"), - ("q", "Abort interactive rebase"), - ("Q", "Immediately abort interactive rebase"), - ("w", "Write interactive rebase file"), - ("W", "Immediately write interactive rebase file"), - ("?", "Show help"), - ("c", "Show commit information"), - ("j", "Move selected commit down"), - ("k", "Move selected commit up"), - ("b", "Toggle break action"), - ("p", "Set selected commit to be picked"), - ("r", "Set selected commit to be reworded"), - ("e", "Set selected commit to be edited"), - ("s", "Set selected commit to be squashed"), - ("f", "Set selected commit to be fixed-up"), - ("d", "Set selected commit to be dropped"), - ("E", "Edit an exec action's command"), - ("!", "Open the todo file in the default editor"), -]; - -pub const VISUAL_MODE_HELP_LINES: &[(&str, &str)] = &[ - ("Up", "Move selection up"), - ("Down", "Move selection down"), - ("PgUp", "Move selection up 5 lines"), - ("PgDn", "Move selection down 5 lines"), - ("?", "Show help"), - ("j", "Move selected commits down"), - ("k", "Move selected commits up"), - ("p", "Set selected commits to be picked"), - ("r", "Set selected commits to be reworded"), - ("e", "Set selected commits to be edited"), - ("s", "Set selected commits to be squashed"), - ("f", "Set selected commits to be fixed-up"), - ("d", "Set selected commits to be dropped"), -]; diff --git a/src/help/help.rs b/src/help/help.rs index 34af153..d0bf2a6 100644 --- a/src/help/help.rs +++ b/src/help/help.rs @@ -1,31 +1,20 @@ -use crate::constants::{LIST_HELP_LINES, VISUAL_MODE_HELP_LINES}; use crate::git_interactive::GitInteractive; +use crate::help::utils::{get_list_normal_mode_help_lines, get_list_visual_mode_help_lines}; use crate::input::{Input, InputHandler}; use crate::process::{HandleInputResult, HandleInputResultBuilder, ProcessModule, State}; use crate::scroll::ScrollPosition; use crate::view::{LineSegment, View, ViewLine}; use crate::window::WindowColor; +use crate::Config; -fn get_help_lines(return_state: &State) -> &[(&str, &str)] { - if let State::List(visual_mode) = *return_state { - if visual_mode { - VISUAL_MODE_HELP_LINES - } - else { - LIST_HELP_LINES - } - } - else { - &[] - } -} - -pub struct Help { - scroll_position: ScrollPosition, +pub struct Help<'h> { + normal_mode_help_lines: [(String, &'h str); 21], return_state: State, + scroll_position: ScrollPosition, + visual_mode_help_lines: [(String, &'h str); 13], } -impl ProcessModule for Help { +impl<'h> ProcessModule for Help<'h> { fn activate(&mut self, state: State, _git_interactive: &GitInteractive) { self.scroll_position.reset(); if let State::Help(return_state) = state { @@ -49,11 +38,11 @@ impl ProcessModule for Help { match input { Input::MoveCursorDown => { self.scroll_position - .scroll_down(window_height, get_help_lines(&self.return_state).len()); + .scroll_down(window_height, self.get_help_lines().len()); }, Input::MoveCursorUp => { self.scroll_position - .scroll_up(window_height, get_help_lines(&self.return_state).len()); + .scroll_up(window_height, self.get_help_lines().len()); }, Input::Resize => { self.scroll_position.reset(); @@ -70,7 +59,7 @@ impl ProcessModule for Help { let mut view_lines: Vec<ViewLine> = vec![]; - for line in get_help_lines(&self.return_state) { + for line in self.get_help_lines() { view_lines.push(ViewLine::new(vec![ LineSegment::new_with_color(format!(" {:4} ", line.0).as_str(), WindowColor::IndicatorColor), LineSegment::new(line.1), @@ -94,11 +83,27 @@ impl ProcessModule for Help { } } -impl Help { - pub fn new() -> Self { +impl<'h> Help<'h> { + pub fn new(config: &'h Config) -> Self { Self { + normal_mode_help_lines: get_list_normal_mode_help_lines(config), return_state: State::List(false), scroll_position: ScrollPosition::new(3, 6, 3), + visual_mode_help_lines: get_list_visual_mode_help_lines(config), + } + } + + pub fn get_help_lines(&self) -> &[(String, &str)] { + if let State::List(visual_mode) = self.return_state { + if visual_mode { + &self.visual_mode_help_lines + } + else { + &self.normal_mode_help_lines + } + } + else { + &[] } } } diff --git a/src/help/mod.rs b/src/help/mod.rs index 013e492..d5aa82e 100644 --- a/src/help/mod.rs +++ b/src/help/mod.rs @@ -1,4 +1,5 @@ #[allow(clippy::module_inception)] mod help; +mod utils; pub use self::help::Help; diff --git a/src/help/utils.rs b/src/help/utils.rs new file mode 100644 index 0000000..7a8a97d --- /dev/null +++ b/src/help/utils.rs @@ -0,0 +1,90 @@ +use crate::Config; + +pub fn get_list_normal_mode_help_lines(config: &Config) -> [(String, &str); 21] { + [ + (String::from("Up"), "Move selection up"), + (String::from("Down"), "Move selection down"), + (String::from("PgUp"), "Move selection up 5 lines"), + (String::from("PgDn"), "Move selection down 5 lines"), + (config.input_abort.to_string(), "Abort interactive rebase"), + ( + config.input_force_abort.to_string(), + "Immediately abort interactive rebase", + ), + (config.input_rebase.to_string(), "Write interactive rebase file"), + ( + config.input_force_rebase.to_string(), + "Immediately write interactive rebase file", + ), + (config.input_help.to_string(), "Show help"), + (config.input_show_commit.to_string(), "Show commit information"), + ( + config.input_move_selection_down.to_string(), + "Move selected commit down", + ), + (config.input_move_selection_up.to_string(), "Move selected commit up"), + (config.input_action_break.to_string(), "Toggle break action"), + (config.input_action_pick.to_string(), "Set selected commit to be picked"), + ( + config.input_action_reword.to_string(), + "Set selected commit to be reworded", + ), + (config.input_action_edit.to_string(), "Set selected commit to be edited"), + ( + config.input_action_squash.to_string(), + "Set selected commit to be squashed", + ), + ( + config.input_action_fixup.to_string(), + "Set selected commit to be fixed-up", + ), + ( + config.input_action_drop.to_string(), + "Set selected commit to be dropped", + ), + (config.input_edit.to_string(), "Edit an exec action's command"), + ( + config.input_open_in_external_editor.to_string(), + "Open the todo file in the default editor", + ), + ] +} + +pub fn get_list_visual_mode_help_lines(config: &Config) -> [(String, &str); 13] { + [ + (String::from("Up"), "Move selection up"), + (String::from("Down"), "Move selection down"), + (String::from("PgUp"), "Move selection up 5 lines"), + (String::from("PgDn"), "Move selection down 5 lines"), + (config.input_help.to_string(), "Show help"), + ( + config.input_move_selection_down.to_string(), + "Move selected commits down", + ), + (config.input_move_selection_up.to_string(), "Move selected commits up"), + ( + config.input_action_pick.to_string(), + "Set selected commits to be picked", + ), + ( + config.input_action_reword.to_string(), + "Set selected commits to be reworded", + ), + ( + config.input_action_edit.to_string(), + "Set selected commits to be edited", + ), + ( + config.input_action_squash.to_string(), + "Set selected commits to be squashed", + ), + ( + config.input_action_fixup.to_string(), + "Set selected commits to be fixed-up", + ), + ( + config.input_action_drop.to_string(), + "Set selected commits to be dropped", + ), + ] +} diff --git a/src/input/input_handler.rs b/src/input/input_handler.rs index aeefe00..3de6023 100644 --- a/src/input/input_handler.rs +++ b/src/input/input_handler.rs @@ -1,14 +1,22 @@ use crate::input::Input; use crate::window::Window; +use crate::Config; use pancurses::Input as PancursesInput; pub struct InputHandler<'i> { + config: &'i Config, + confirm_yes_input: char, window: &'i Window<'i>, } impl<'i> InputHandler<'i> { - pub fn new(window: &'i Window) -> Self { - Self { window } + pub fn new(window: &'i Window, config: &'i Config) -> Self { + let confirm_yes_input = config.input_confirm_yes.to_lowercase().chars().next().unwrap_or('y'); + Self { + config, + confirm_yes_input, + window, + } } pub fn get_input(&self) -> Input { @@ -20,37 +28,54 @@ impl<'i> InputHandler<'i> { } }; - match c { - PancursesInput::Character(c) if c == '?' => Input::Help, - PancursesInput::Character(c) if c == 'c' => Input::ShowCommit, - PancursesInput::Character(c) if c == 'q' => Input::Abort, - PancursesInput::Character(c) if c == 'Q' => Input::ForceAbort, - PancursesInput::Character(c) if c == 'w' => Input::Rebase, - PancursesInput::Character(c) if c == 'W' => Input::ForceRebase, - PancursesInput::Character(c) if c == 'p' => Input::ActionPick, - PancursesInput::Character(c) if c == 'b' => Input::ActionBreak, - PancursesInput::Character(c) if c == 'r' => Input::ActionReword, - PancursesInput::Character(c) if c == 'e' => Input::ActionEdit, - PancursesInput::Character(c) if c == 's' => Input::ActionSquash, - PancursesInput::Character(c) if c == 'f' => Input::ActionFixup, - PancursesInput::Character(c) if c == 'd' => Input::ActionDrop, - PancursesInput::Character(c) if c == 'E' => Input::Edit, - PancursesInput::Character(c) if c == 'v' => Input::ToggleVisualMode, - PancursesInput::Character(c) if c == 'j' => Input::SwapSelectedDown, - PancursesInput::Character(c) if c == 'k' => Input::SwapSelectedUp, - PancursesInput::KeyDown => Input::MoveCursorDown, - PancursesInput::KeyUp => Input::MoveCursorUp, - PancursesInput::KeyPPage => Input::MoveCursorPageUp, - PancursesInput::KeyNPage => Input::MoveCursorPageDown, - PancursesInput::KeyResize => Input::Resize, - PancursesInput::Character(c) if c == '!' => Input::OpenInEditor, + let input = match c { + PancursesInput::Character(c) => c.to_string(), + PancursesInput::KeyDown => String::from("Down"), + PancursesInput::KeyUp => String::from("Up"), + PancursesInput::KeyPPage => String::from("PageUp"), + PancursesInput::KeyNPage => String::from("PageDown"), + PancursesInput::KeyResize => String::from("Resize"), + _ => String::from("Other"), + }; + + match input.as_str() { + i if i == self.config.input_abort.as_str() => Input::Abort, + i if i == self.config.input_action_break.as_str() => Input::ActionBreak, + i if i == self.config.input_action_drop.as_str() => Input::ActionDrop, + i if i == self.config.input_action_drop.as_str() => Input::Help, + i if i == self.config.input_action_edit.as_str() => Input::ActionEdit, + i if i == self.config.input_action_fixup.as_str() => Input::ActionFixup, + i if i == self.config.input_action_pick.as_str() => Input::ActionPick, + i if i == self.config.input_action_reword.as_str() => Input::ActionReword, + i if i == self.config.input_action_squash.as_str() => Input::ActionSquash, + i if i == self.config.input_edit.as_str() => Input::Edit, + i if i == self.config.input_force_abort.as_str() => Input::ForceAbort, + i if i == self.config.input_force_rebase.as_str() => Input::ForceRebase, + i if i == self.config.input_move_down.as_str() => Input::MoveCursorDown, + i if i == self.config.input_move_selection_down.as_str() => Input::SwapSelectedDown, + i if i == self.config.input_move_selection_up.as_str() => Input::SwapSelectedUp, + i if i == self.config.input_move_up.as_str() => Input::MoveCursorUp, + i if i == self.config.input_open_in_external_editor.as_str() => Input::OpenInEditor, + i if i == self.config.input_rebase.as_str() => Input::Rebase, + i if i == self.config.input_show_commit.as_str() => Input::ShowCommit, + i if i == self.config.input_toggle_visual_mode.as_str() => Input::ToggleVisualMode, + "PageUp" => Input::MoveCursorPageUp, + "PageDown" => Input::MoveCursorPageDown, + "Resize" => Input::Resize, _ => Input::Other, } } pub fn get_confirm(&self) -> Input { match self.window.getch() { - Some(PancursesInput::Character(c)) if c == 'y' || c == 'Y' => Input::Yes, + Some(PancursesInput::Character(c)) => { + if c.to_lowercase().next().unwrap() == self.confirm_yes_input { + Input::Yes + } + else { + Input::No + } + }, Some(PancursesInput::KeyResize) => Input::Resize, _ => Input::No, } diff --git a/src/list/list.rs b/src/list/list.rs index f604d92..60c3eaa 100644 --- a/src/list/list.rs +++ b/src/list/list.rs @@ -1,20 +1,16 @@ use crate::action::Action; use crate::config::Config; -use crate::constants::{ - LIST_FOOTER_COMPACT, - LIST_FOOTER_COMPACT_WIDTH, - LIST_FOOTER_FULL, - LIST_FOOTER_FULL_WIDTH, - MINIMUM_FULL_WINDOW_WIDTH, - VISUAL_MODE_FOOTER_COMPACT, - VISUAL_MODE_FOOTER_COMPACT_WIDTH, - VISUAL_MODE_FOOTER_FULL, - VISUAL_MODE_FOOTER_FULL_WIDTH, -}; +use crate::constants::MINIMUM_FULL_WINDOW_WIDTH; use crate::git_interactive::GitInteractive; use crate::input::{Input, InputHandler}; use crate::line::Line; -use crate::list::get_action_color; +use crate::list::utils::{ + get_action_color, + get_normal_footer_compact, + get_normal_footer_full, + get_visual_footer_compact, + get_visual_footer_full, +}; use crate::process::{ExitStatus, HandleInputResult, HandleInputResultBuilder, ProcessModule, ProcessResult, State}; use crate::scroll::ScrollPosition; use crate::view::{LineSegment, View, ViewLine}; @@ -29,8 +25,12 @@ enum ListState { pub struct List<'l> { config: &'l Config, + normal_footer_compact: String, + normal_footer_full: String, scroll_position: ScrollPosition, state: ListState, + visual_footer_compact: String, + visual_footer_full: String, } impl<'l> ProcessModule for List<'l> { @@ -85,24 +85,24 @@ impl<'l> ProcessModule for List<'l> { view.set_color(WindowColor::Foreground); view.set_style(true, false, false); if is_visual_mode { - if view_width >= VISUAL_MODE_FOOTER_FULL_WIDTH { - view.draw_str(VISUAL_MODE_FOOTER_FULL); + if view_width >= self.visual_footer_full.len() { + view.draw_str(self.visual_footer_full.as_str()); } - else if view_width >= VISUAL_MODE_FOOTER_COMPACT_WIDTH { - view.draw_str(VISUAL_MODE_FOOTER_COMPACT); + else if view_width >= self.visual_footer_compact.len() { + view.draw_str(self.visual_footer_compact.as_str()); } else { - view.draw_str("(Visual) Help: ?"); + view.draw_str(format!("(Visual) Help: {}", self.config.input_help).as_str()); } } - else if view_width >= LIST_FOOTER_FULL_WIDTH { - view.draw_str(LIST_FOOTER_FULL); + else if view_width >= self.normal_footer_full.len() { + view.draw_str(self.normal_footer_full.as_str()); } - else if view_width >= LIST_FOOTER_COMPACT_WIDTH { - view.draw_str(LIST_FOOTER_COMPACT); + else if view_width >= self.normal_footer_compact.len() { + view.draw_str(self.normal_footer_compact.as_str()); } else { - view.draw_str("Help: ?"); + view.draw_str(format!("Help: {}", self.config.input_help).as_str()); } view.set_style(false, false, false); } @@ -112,8 +112,12 @@ impl<'l> List<'l> { pub fn new(config: &'l Config) -> Self { Self { config, + normal_footer_compact: get_normal_footer_compact(config), + normal_footer_full: get_normal_footer_full(config), scroll_position: ScrollPosition::new(2, 1, 1), state: ListState::Normal, + visual_footer_compact: get_visual_footer_compact(config), + visual_footer_full: get_visual_footer_full(config), } } diff --git a/src/list/utils.rs b/src/list/utils.rs index 8794ae7..1fd19c0 100644 --- a/src/list/utils.rs +++ b/src/list/utils.rs @@ -1,5 +1,6 @@ use crate::action::Action; use crate::window::WindowColor; +use crate::Config; pub fn get_action_color(action: Action) -> WindowColor { match action { @@ -13,3 +14,79 @@ pub fn get_action_color(action: Action) -> WindowColor { Action::Squash => WindowColor::ActionSquash, } } + +pub fn get_normal_footer_full(config: &Config) -> String { + format!( + " up, down, {}/{}, {}/{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}", + config.input_abort, + config.input_force_abort, + config.input_rebase, + config.input_force_rebase, + config.input_show_commit, + config.input_move_selection_down, + config.input_move_selection_up, + config.input_action_break, + config.input_action_pick, + config.input_action_reword, + config.input_action_edit, + config.input_action_squash, + config.input_action_fixup, + config.input_action_drop, + config.input_edit, + config.input_open_in_external_editor, + config.input_help, + ) +} + +pub fn get_visual_footer_full(config: &Config) -> String { + format!( + " up, down, {}, {}, {}, {}, {}, {}, {}, {}, {}", + config.input_move_selection_down, + config.input_move_selection_up, + config.input_action_pick, + config.input_action_reword, + config.input_action_edit, + config.input_action_squash, + config.input_action_fixup, + config.input_action_drop, + config.input_help, + ) +} + +pub fn get_normal_footer_compact(config: &Config) -> String { + format!( + "up,dn,{}/{},{}/{},{},{},{},{},{},{},{},{},{},{},{},{},{}", + config.input_abort, + config.input_force_abort, + config.input_rebase, + config.input_force_rebase, + config.input_show_commit, + config.input_move_selection_down, + config.input_move_selection_up, + config.input_action_break, + config.input_action_pick, + config.input_action_reword, + config.input_action_edit, + config.input_action_squash, + config.input_action_fixup, + config.input_action_drop, + config.input_edit, + config.input_open_in_external_editor, + config.input_help, + ) +} + +pub fn get_visual_footer_compact(config: &Config) -> String { + format!( + "up,dn,{},{},{},{},{},{},{},{},{}", + config.input_move_selection_down, + config.input_move_selection_up, + config.input_action_pick, + config.input_action_reword, + config.input_action_edit, + config.input_action_squash, + config.input_action_fixup, + config.input_action_drop, + config.input_help, + ) +} diff --git a/src/main.rs b/src/main.rs index 38bdc42..0c4edd0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -81,9 +81,9 @@ fn try_main() -> Result<ExitStatus, Exit> { let window = Window::new(&config); - let input_handler = InputHandler::new(&window); + let input_handler = InputHandler::new(&window, &config); - let view = View::new(&window); + let view = View::new(&window, &config); let mut process = Process::new(git_interactive, &view, &input_handler, &config); diff --git a/src/process/process.rs b/src/process/process.rs index d316162..fffe5bf 100644 --- a/src/process/process.rs +++ b/src/process/process.rs @@ -25,7 +25,7 @@ pub struct Process<'r> { exiting: Exiting, external_editor: ExternalEditor<'r>, git_interactive: GitInteractive, - help: Help, + help: Help<'r>, input_handler: &'r InputHandler<'r>, list: List<'r>, show_commit: ShowCommit, @@ -51,7 +51,7 @@ impl<'r> Process<'r> { exiting: Exiting::new(), external_editor: ExternalEditor::new(config), git_interactive, - help: Help::new(), + help: Help::new(config), input_handler, list: List::new(config), show_commit: ShowCommit::new(), diff --git a/src/view/view.rs b/src/view/view.rs index 898cffb..48a377d 100644 --- a/src/view/view.rs +++ b/src/view/view.rs @@ -2,7 +2,6 @@ use crate::constants::{ MINIMUM_COMPACT_WINDOW_WIDTH, MINIMUM_WINDOW_HEIGHT, TITLE, - TITLE_HELP_INDICATOR, TITLE_HELP_INDICATOR_LENGTH, TITLE_LENGTH, TITLE_SHORT, @@ -12,14 +11,16 @@ use crate::scroll::get_scroll_position; use crate::view::ViewLine; use crate::window::Window; use crate::window::WindowColor; +use crate::Config; pub struct View<'v> { + config: &'v Config, window: &'v Window<'v>, } impl<'v> View<'v> { - pub fn new(window: &'v Window) -> Self { - Self { window } + pub fn new(window: &'v Window, config: &'v Config) -> Self { + Self { window, config } } pub fn draw_str(&self, s: &str) { @@ -116,7 +117,8 @@ impl<'v> View<'v> { self.window.draw_str(padding.as_str()); } if show_help { - self.window.draw_str(TITLE_HELP_INDICATOR); + self.window + .draw_str(format!("Help: {}", self.config.inp |