diff options
author | Tim Oram <dev@mitmaro.ca> | 2021-03-26 23:17:14 -0230 |
---|---|---|
committer | Tim Oram <dev@mitmaro.ca> | 2021-03-26 23:34:56 -0230 |
commit | 38550a49acb8b1953b847685e3f459979480e89a (patch) | |
tree | 952ced728d4f033e990ee154715f3bb8c55540db | |
parent | ee694d94b8d5c1c9117db6af692a12e8de1bd3ae (diff) |
Add insert line support
This adds the ability to insert new exec, label, reset and merge lines
to the rebase todo file.
-rw-r--r-- | CHANGELOG.md | 1 | ||||
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | readme/customization.md | 2 | ||||
-rw-r--r-- | src/components/edit/mod.rs | 9 | ||||
-rw-r--r-- | src/components/edit/tests.rs | 9 | ||||
-rw-r--r-- | src/config/key_bindings.rs | 2 | ||||
-rw-r--r-- | src/config/tests.rs | 14 | ||||
-rw-r--r-- | src/input/input_handler.rs | 2 | ||||
-rw-r--r-- | src/input/mod.rs | 1 | ||||
-rw-r--r-- | src/insert/insert_state.rs | 5 | ||||
-rw-r--r-- | src/insert/line_type.rs | 40 | ||||
-rw-r--r-- | src/insert/mod.rs | 118 | ||||
-rw-r--r-- | src/insert/tests.rs | 254 | ||||
-rw-r--r-- | src/list/mod.rs | 3 | ||||
-rw-r--r-- | src/list/tests.rs | 19 | ||||
-rw-r--r-- | src/list/utils.rs | 1 | ||||
-rw-r--r-- | src/main.rs | 9 | ||||
-rw-r--r-- | src/process/modules.rs | 5 | ||||
-rw-r--r-- | src/process/state.rs | 1 | ||||
-rw-r--r-- | src/process/testutil.rs | 3 | ||||
-rw-r--r-- | src/todo_file/line.rs | 76 |
21 files changed, 570 insertions, 6 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index a924f18..c37e113 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - Support for multiple key bindings per configuration ([#437](https://github.com/MitMaro/git-interactive-rebase-tool/pull/437)) - Open external editor from visual mode ([#442](https://github.com/MitMaro/git-interactive-rebase-tool/pull/442)) - Delete selected lines from the todo list ([#443](https://github.com/MitMaro/git-interactive-rebase-tool/pull/443)) +- Insert new exec, label, reset or merge line ([#454](https://github.com/MitMaro/git-interactive-rebase-tool/pull/454)) ### Fixed - Most modifier key combinations could not be used as key bindings ([#435](https://github.com/MitMaro/git-interactive-rebase-tool/pull/435)) @@ -144,6 +144,8 @@ Key bindings can be configured, see [configuration](readme/customization.md#key- | `E` | Normal | Edit the command of an exec action | | `v` | All | Enter and exit visual mode | | `d` | Diff | Show full commit diff | +| `I` | Normal | Insert a new line | +| `Delete` | All | Remove selected lines | | `Control+z` | All | Undo the previous change | | `Control+y` | All | Redo the previously undone change | diff --git a/readme/customization.md b/readme/customization.md index 7c236f4..85ceef3 100644 --- a/readme/customization.md +++ b/readme/customization.md @@ -111,6 +111,7 @@ Most keys can be changed to any printable character or supported special charact | `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 | +| `inputInsertLine` | I | String | Key for inserting a new line | | `inputMoveDown` | Down | String | Key for moving the cursor down | | `inputMoveLeft` | Left | String | Key for moving the cursor left | | `inputMoveRight` | Right | String | Key for moving the cursor right | @@ -122,6 +123,7 @@ Most keys can be changed to any printable character or supported special charact | `inputOpenInExternalEditor`| ! | String | Key for opening the external editor | | `inputRebase` | w | String | Key for rebasing with confirmation | | `inputRedo` | Control+y| String | Key for redoing the previous undone change | +| `inputRemoveLine` | Delete | String | Key for removing selected commits | | `inputShowCommit` | c | String | Key for showing the overview of the selected commit | | `inputShowDiff` | d | String | Key for showing the diff of the selected commit | | `inputToggleVisualMode` | v | String | Key for toggling visual mode | diff --git a/src/components/edit/mod.rs b/src/components/edit/mod.rs index c50d745..5894c3a 100644 --- a/src/components/edit/mod.rs +++ b/src/components/edit/mod.rs @@ -148,7 +148,12 @@ impl Edit { self.cursor_position = UnicodeSegmentation::graphemes(content, true).count(); } - pub fn get_content(&self) -> &str { - self.content.as_str() + pub fn clear(&mut self) { + self.content.clear(); + self.cursor_position = 0; + } + + pub fn get_content(&self) -> String { + self.content.clone() } } diff --git a/src/components/edit/tests.rs b/src/components/edit/tests.rs index 6430232..f913c9d 100644 --- a/src/components/edit/tests.rs +++ b/src/components/edit/tests.rs @@ -522,3 +522,12 @@ fn set_get_content() { assert_eq!(module.cursor_position, 4); assert_eq!(module.get_content(), "abcd"); } + +#[test] +fn clear_content() { + let mut module = Edit::new(); + module.set_content("abcd"); + module.clear(); + assert_eq!(module.cursor_position, 0); + assert_eq!(module.get_content(), ""); +} diff --git a/src/config/key_bindings.rs b/src/config/key_bindings.rs index 039b636..d583324 100644 --- a/src/config/key_bindings.rs +++ b/src/config/key_bindings.rs @@ -19,6 +19,7 @@ pub struct KeyBindings { pub(crate) force_abort: Vec<String>, pub(crate) force_rebase: Vec<String>, pub(crate) help: Vec<String>, + pub(crate) insert_line: Vec<String>, pub(crate) move_down: Vec<String>, pub(crate) move_down_step: Vec<String>, pub(crate) move_left: Vec<String>, @@ -62,6 +63,7 @@ impl KeyBindings { force_abort: get_input(git_config, "interactive-rebase-tool.inputForceAbort", "Q")?, force_rebase: get_input(git_config, "interactive-rebase-tool.inputForceRebase", "W")?, help: get_input(git_config, "interactive-rebase-tool.inputHelp", "?")?, + insert_line: get_input(git_config, "interactive-rebase-tool.insertLine", "I")?, move_down: get_input(git_config, "interactive-rebase-tool.inputMoveDown", "Down")?, move_left: get_input(git_config, "interactive-rebase-tool.inputMoveLeft", "Left")?, move_right: get_input(git_config, "interactive-rebase-tool.inputMoveRight", "Right")?, diff --git a/src/config/tests.rs b/src/config/tests.rs index 7aa5655..a429979 100644 --- a/src/config/tests.rs +++ b/src/config/tests.rs @@ -977,6 +977,20 @@ fn config_key_bindings_help() { } #[test] +fn config_key_bindings_insert_line_default() { + let config = load(|_| {}); + assert_eq!(config.key_bindings.insert_line, vec![String::from("I")]); +} + +#[test] +fn config_key_bindings_insert_line() { + let config = load(|git_config| { + git_config.set_str("interactive-rebase-tool.insertLine", "X").unwrap(); + }); + assert_eq!(config.key_bindings.insert_line, vec![String::from("X")]); +} + +#[test] fn config_key_bindings_move_down_default() { let config = load(|_| {}); assert_eq!(config.key_bindings.move_down, vec![String::from("Down")]); diff --git a/src/input/input_handler.rs b/src/input/input_handler.rs index 60611d0..9ff4efa 100644 --- a/src/input/input_handler.rs +++ b/src/input/input_handler.rs @@ -148,6 +148,7 @@ impl<'i> InputHandler<'i> { i if self.key_bindings.show_commit.contains(&i) => Input::ShowCommit, i if self.key_bindings.edit.contains(&i) => Input::Edit, i if self.key_bindings.help.contains(&i) => Input::Help, + i if self.key_bindings.insert_line.contains(&i) => Input::InsertLine, i if self.key_bindings.toggle_visual_mode.contains(&i) => Input::ToggleVisualMode, i if self.key_bindings.action_break.contains(&i) => Input::ActionBreak, i if self.key_bindings.action_drop.contains(&i) => Input::ActionDrop, @@ -414,6 +415,7 @@ mod tests { case::show_commit(create_key_event!('c'), Input::ShowCommit), case::edit(create_key_event!('E'), Input::Edit), case::help(create_key_event!('?'), Input::Help), + case::insert_line(create_key_event!('I'), Input::InsertLine), case::toggle_visual_mode(create_key_event!('v'), Input::ToggleVisualMode), case::action_break(create_key_event!('b'), Input::ActionBreak), case::action_drop(create_key_event!('d'), Input::ActionDrop), diff --git a/src/input/mod.rs b/src/input/mod.rs index c9e8aea..ed90990 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -17,6 +17,7 @@ pub enum Input { ForceAbort, ForceRebase, Help, + InsertLine, Kill, MoveCursorDown, MoveCursorLeft, diff --git a/src/insert/insert_state.rs b/src/insert/insert_state.rs new file mode 100644 index 0000000..599e621 --- /dev/null +++ b/src/insert/insert_state.rs @@ -0,0 +1,5 @@ +#[derive(Debug, PartialEq)] +pub enum InsertState { + Prompt, + Edit, +} diff --git a/src/insert/line_type.rs b/src/insert/line_type.rs new file mode 100644 index 0000000..761c93f --- /dev/null +++ b/src/insert/line_type.rs @@ -0,0 +1,40 @@ +#[derive(Clone, Debug, PartialEq)] +pub enum LineType { + Exec, + Label, + Reset, + Merge, + Cancel, +} + +impl ToString for LineType { + fn to_string(&self) -> String { + match *self { + Self::Exec => String::from("exec"), + Self::Label => String::from("label"), + Self::Reset => String::from("reset"), + Self::Merge => String::from("merge"), + Self::Cancel => String::from("<cancel>"), + } + } +} + +#[cfg(test)] +mod tests { + use rstest::rstest; + + use super::*; + + #[rstest( + line_type, + expected, + case::exec(&LineType::Exec, "exec"), + case::exec(&LineType::Label, "label"), + case::exec(&LineType::Reset, "reset"), + case::exec(&LineType::Merge, "merge"), + case::exec(&LineType::Cancel, "<cancel>"), + )] + fn to_string(line_type: &LineType, expected: &str) { + assert_eq!(line_type.to_string(), String::from(expected)); + } +} diff --git a/src/insert/mod.rs b/src/insert/mod.rs new file mode 100644 index 0000000..9add788 --- /dev/null +++ b/src/insert/mod.rs @@ -0,0 +1,118 @@ +mod insert_state; +mod line_type; + +#[cfg(all(unix, test))] +mod tests; + +use crate::{ + components::{Choice, Edit}, + input::{input_handler::InputMode, Input}, + insert::{insert_state::InsertState, line_type::LineType}, + process::{process_module::ProcessModule, process_result::ProcessResult, state::State}, + todo_file::{line::Line, TodoFile}, + view::{view_data::ViewData, view_line::ViewLine, View}, +}; + +pub struct Insert { + action_choices: Choice<LineType>, + edit: Edit, + edit_view_data: ViewData, + line_type: LineType, + state: InsertState, +} + +impl ProcessModule for Insert { + fn activate(&mut self, _: &TodoFile, _: State) -> ProcessResult { + self.state = InsertState::Prompt; + self.edit.clear(); + ProcessResult::new() + } + + fn build_view_data(&mut self, view: &View<'_>, _: &TodoFile) -> &ViewData { + let view_width = view.get_view_size().width(); + let view_height = view.get_view_size().height(); + + match self.state { + InsertState::Prompt => self.action_choices.get_view_data(view_width, view_height), + InsertState::Edit => { + self.edit_view_data.clear(); + self.edit_view_data.set_view_size(view_width, view_height); + self.edit.update_view_data(&mut self.edit_view_data); + &self.edit_view_data + }, + } + } + + fn handle_input(&mut self, view: &mut View<'_>, rebase_todo: &mut TodoFile) -> ProcessResult { + let mut result = ProcessResult::new(); + match self.state { + InsertState::Prompt => { + let input = view.get_input(InputMode::Default); + result = result.input(input); + if let Some(action) = self.action_choices.handle_input(input) { + if action == &LineType::Cancel { + result = result.state(State::List); + } + else { + self.line_type = action.clone(); + self.edit.set_label(format!("{} ", action.to_string()).as_str()); + self.state = InsertState::Edit; + } + } + }, + InsertState::Edit => { + let input = view.get_input(InputMode::Raw); + result = result.input(input); + if !self.edit.handle_input(input) && input == Input::Enter { + let content = self.edit.get_content(); + result = result.state(State::List); + if !content.is_empty() { + let line = match self.line_type { + LineType::Exec => Line::new_exec(content.as_str()), + LineType::Label => Line::new_label(content.as_str()), + LineType::Reset => Line::new_reset(content.as_str()), + LineType::Merge => Line::new_merge(content.as_str()), + // this should exit in the prompt state and never get here + LineType::Cancel => unreachable!(), + }; + let new_line_index = rebase_todo.get_selected_line_index() + 1; + rebase_todo.add_line(new_line_index, line); + rebase_todo.set_selected_line_index(new_line_index); + } + } + }, + } + + result + } +} + +impl Insert { + pub(crate) fn new() -> Self { + let mut edit = Edit::new(); + edit.set_description("Enter contents of the new line. Empty content cancels creation of a new line."); + + let mut action_choices = Choice::new(vec![ + (LineType::Exec, 'e', String::from("exec <command>")), + (LineType::Label, 'l', String::from("label <label>")), + (LineType::Reset, 'r', String::from("reset <label>")), + ( + LineType::Merge, + 'm', + String::from("merge [-C <commit> | -c <commit>] <label> [# <oneline>]"), + ), + (LineType::Cancel, 'c', String::from("Cancel add line")), + ]); + action_choices.set_prompt(vec![ViewLine::from("Select the type of line to insert:")]); + let mut edit_view_data = ViewData::new(); + edit_view_data.set_show_title(true); + + Self { + state: InsertState::Prompt, + edit, + edit_view_data, + action_choices, + line_type: LineType::Exec, + } + } +} diff --git a/src/insert/tests.rs b/src/insert/tests.rs new file mode 100644 index 0000000..80936e2 --- /dev/null +++ b/src/insert/tests.rs @@ -0,0 +1,254 @@ +use super::*; +use crate::{ + assert_process_result, + assert_rendered_output, + process::testutil::{process_module_test, TestContext, ViewState}, +}; + +#[test] +#[serial_test::serial] +fn activate() { + process_module_test(&[], ViewState::default(), &[], |test_context: TestContext<'_>| { + let mut module = Insert::new(); + assert_process_result!(test_context.activate(&mut module, State::List)); + }); +} + +#[test] +#[serial_test::serial] +fn render_prompt() { + process_module_test(&[], ViewState::default(), &[], |test_context: TestContext<'_>| { + let mut module = Insert::new(); + let view_data = test_context.build_view_data(&mut module); + assert_rendered_output!( + view_data, + "{TITLE}", + "{LEADING}", + "{Normal}Select the type of line to insert:", + "", + "{BODY}", + "{Normal}e) exec <command>", + "{Normal}l) label <label>", + "{Normal}r) reset <label>", + "{Normal}m) merge [-C <commit> | -c <commit>] <label> [# <oneline>]", + "{Normal}c) Cancel add line", + "", + "{IndicatorColor}Please choose an option." + ); + }); +} + +#[test] +#[serial_test::serial] +fn prompt_cancel() { + process_module_test( + &[], + ViewState::default(), + &[Input::Character('c')], + |mut test_context: TestContext<'_>| { + let mut module = Insert::new(); + assert_process_result!( + test_context.handle_input(&mut module), + input = Input::Character('c'), + state = State::List + ); + }, + ); +} + +#[test] +#[serial_test::serial] +fn edit_render_exec() { + process_module_test( + &[], + ViewState::default(), + &[ + Input::Character('e'), + Input::Character('f'), + Input::Character('o'), + Input::Character('o'), + Input::Enter, + ], + |mut test_context: TestContext<'_>| { + let mut module = Insert::new(); + test_context.handle_n_inputs(&mut module, 4); + let view_data = test_context.build_view_data(&mut module); + assert_rendered_output!( + view_data, + "{TITLE}", + "{LEADING}", + "{IndicatorColor}Enter contents of the new line. Empty content cancels creation of a new line.", + "", + "{BODY}", + "{Normal,Dimmed}exec {Normal}foo{Normal,Underline} ", + "{TRAILING}", + "{IndicatorColor}Enter to finish" + ); + assert_process_result!( + test_context.handle_input(&mut module), + input = Input::Enter, + state = State::List + ); + assert_eq!(test_context.rebase_todo_file.get_line(0).unwrap().to_text(), "exec foo"); + }, + ); +} + +#[test] +#[serial_test::serial] +fn edit_render_label() { + process_module_test( + &[], + ViewState::default(), + &[ + Input::Character('l'), + Input::Character('f'), + Input::Character('o'), + Input::Character('o'), + Input::Enter, + ], + |mut test_context: TestContext<'_>| { + let mut module = Insert::new(); + test_context.handle_n_inputs(&mut module, 4); + let view_data = test_context.build_view_data(&mut module); + assert_rendered_output!( + view_data, + "{TITLE}", + "{LEADING}", + "{IndicatorColor}Enter contents of the new line. Empty content cancels creation of a new line.", + "", + "{BODY}", + "{Normal,Dimmed}label {Normal}foo{Normal,Underline} ", + "{TRAILING}", + "{IndicatorColor}Enter to finish" + ); + assert_process_result!( + test_context.handle_input(&mut module), + input = Input::Enter, + state = State::List + ); + assert_eq!( + test_context.rebase_todo_file.get_line(0).unwrap().to_text(), + "label foo" + ); + }, + ); +} + +#[test] +#[serial_test::serial] +fn edit_render_reset() { + process_module_test( + &[], + ViewState::default(), + &[ + Input::Character('r'), + Input::Character('f'), + Input::Character('o'), + Input::Character('o'), + Input::Enter, + ], + |mut test_context: TestContext<'_>| { + let mut module = Insert::new(); + test_context.handle_n_inputs(&mut module, 4); + let view_data = test_context.build_view_data(&mut module); + assert_rendered_output!( + view_data, + "{TITLE}", + "{LEADING}", + "{IndicatorColor}Enter contents of the new line. Empty content cancels creation of a new line.", + "", + "{BODY}", + "{Normal,Dimmed}reset {Normal}foo{Normal,Underline} ", + "{TRAILING}", + "{IndicatorColor}Enter to finish" + ); + assert_process_result!( + test_context.handle_input(&mut module), + input = Input::Enter, + state = State::List + ); + assert_eq!( + test_context.rebase_todo_file.get_line(0).unwrap().to_text(), + "reset foo" + ); + }, + ); +} + +#[test] +#[serial_test::serial] +fn edit_render_merge() { + process_module_test( + &[], + ViewState::default(), + &[ + Input::Character('m'), + Input::Character('f'), + Input::Character('o'), + Input::Character('o'), + Input::Enter, + ], + |mut test_context: TestContext<'_>| { + let mut module = Insert::new(); + test_context.handle_n_inputs(&mut module, 4); + let view_data = test_context.build_view_data(&mut module); + assert_rendered_output!( + view_data, + "{TITLE}", + "{LEADING}", + "{IndicatorColor}Enter contents of the new line. Empty content cancels creation of a new line.", + "", + "{BODY}", + "{Normal,Dimmed}merge {Normal}foo{Normal,Underline} ", + "{TRAILING}", + "{IndicatorColor}Enter to finish" + ); + assert_process_result!( + test_context.handle_input(&mut module), + input = Input::Enter, + state = State::List + ); + assert_eq!( + test_context.rebase_todo_file.get_line(0).unwrap().to_text(), + "merge foo" + ); + }, + ); +} + +#[test] +#[serial_test::serial] +fn edit_select_next_index() { + process_module_test( + &["pick aaa c1"], + ViewState::default(), + &[ + Input::Character('e'), + Input::Character('f'), + Input::Character('o'), + Input::Character('o'), + Input::Enter, + ], + |mut test_context: TestContext<'_>| { + let mut module = Insert::new(); + test_context.handle_all_inputs(&mut module); + assert_eq!(test_context.rebase_todo_file.get_selected_line_index(), 1); + }, + ); +} + +#[test] +#[serial_test::serial] +fn cancel_edit() { + process_module_test( + &[], + ViewState::default(), + &[Input::Character('e'), Input::Enter], + |mut test_context: TestContext<'_>| { + let mut module = Insert::new(); + test_context.handle_all_inputs(&mut module); + assert!(test_context.rebase_todo_file.is_empty()); + }, + ); +} diff --git a/src/list/mod.rs b/src/list/mod.rs index ad37875..3aa0447 100644 --- a/src/list/mod.rs +++ b/src/list/mod.rs @@ -330,6 +330,7 @@ impl<'l> List<'l> { } } }, + Input::InsertLine => result = result.state(State::Insert), _ => {}, } result @@ -355,7 +356,7 @@ impl<'l> List<'l> { rebase_todo.update_range( selected_index, selected_index, - &EditContext::new().content(self.edit.get_content()), + &EditContext::new().content(self.edit.get_content().as_str()), ); self.visual_index_start = None; self.state = ListState::Normal; diff --git a/src/list/tests.rs b/src/list/tests.rs index 19e97a1..9a94902 100644 --- a/src/list/tests.rs +++ b/src/list/tests.rs @@ -1367,6 +1367,24 @@ fn normal_mode_edit_without_selected_line() { #[test] #[serial_test::serial] +fn normal_mode_insert_line() { + process_module_test( + &[], + ViewState::default(), + &[Input::InsertLine], + |mut test_context: TestContext<'_>| { + let mut module = List::new(test_context.config); + assert_process_result!( + test_context.handle_input(&mut module), + input = Input::InsertLine, + state = State::Insert + ); + }, + ); +} + +#[test] +#[serial_test::serial] fn normal_mode_open_external_editor() { process_module_test( &["pick aaa c1"], @@ -2755,6 +2773,7 @@ fn normal_mode_help() { "{IndicatorColor} f {Normal,Dimmed}|{Normal}Set selected commit to be fixed-up", "{IndicatorColor} d {Normal,Dimmed}|{Normal}Set selected commit to be dropped", "{IndicatorColor} E {Normal,Dimmed}|{Normal}Edit an exec action's command", + "{IndicatorColor} I {Normal,Dimmed}|{Normal}Insert a new line", "{IndicatorColor} Delete {Normal,Dimmed}|{Normal}Completely remove the selected line", "{IndicatorColor} Controlz{Normal,Dimmed}|{Normal}Undo the last change", "{IndicatorColor} Controly{Normal,Dimmed}|{Normal}Redo the previous undone change", diff --git a/src/list/utils.rs b/src/list/utils.rs index 7556dc4..2342978 100644 --- a/src/list/utils.rs +++ b/src/list/utils.rs @@ -84,6 +84,7 @@ pub(super) fn get_list_normal_mode_help_lines(key_bindings: &KeyBindings) -> Vec String::from("Set selected commit to be dropped"), ), (key_bindings.edit.clone(), String::from("Edit an exec action's command")), + (key_bindings.insert_line.clone(), String::from("Insert a new line")), ( key_bindings.remove_line.clone(), String::from("Completely remove the selected line"), diff --git a/src/main.rs b/src/main.rs index 2bc61fc..d065d44 100644 --- a/src/main.rs +++ b/src/main.rs @@ -29,6 +29,8 @@ #![allow(clippy::unwrap_used)] #![allow(clippy::wildcard_enum_match_arm)] #![allow(clippy::similar_names)] +#![allow(clippy::unreachable)] +#![allow(clippy::missing_panics_doc)] mod components; mod config; @@ -38,12 +40,16 @@ mod constants; mod display; mod external_editor; mod input; +mod insert; mod list; mod process; mod show_commit; mod todo_file; mod view; +#[cfg(test)] +pub mod testutil; + use clap::{App, Arg}; use crate::{ @@ -56,9 +62,6 @@ use crate::{ view::View, }; -#[cfg(test)] -pub mod testutil; - #[derive(Debug)] pub struct Exit { message: String, diff --git a/src/process/modules.rs b/src/process/modules.rs index 9aac49a..a057530 100644 --- a/src/process/modules.rs +++ b/src/process/modules.rs @@ -3,6 +3,7 @@ use crate::{ confirm_abort::ConfirmAbort, confirm_rebase::ConfirmRebase, external_editor::ExternalEditor, + insert::Insert, list::List, process::{ error::Error, @@ -21,6 +22,7 @@ pub struct Modules<'m> { pub confirm_rebase: ConfirmRebase, pub error: Error, pub external_editor: ExternalEditor, + pub insert: Insert, pub list: List<'m>, pub show_commit: ShowCommit<'m>, pub window_size_error: WindowSizeError, @@ -33,6 +35,7 @@ impl<'m> Modules<'m> { confirm_rebase: ConfirmRebase::new(), error: Error::new(), external_editor: ExternalEditor::new(config.git.editor.as_str()), + insert: Insert::new(), list: List::new(config), show_commit: ShowCommit::new(config), window_size_error: WindowSizeError::new(), @@ -45,6 +48,7 @@ impl<'m> Modules<'m> { State::ConfirmRebase => &mut self.confirm_rebase as &mut dyn ProcessModule, State::Error => &mut self.error as &mut dyn ProcessModule, State::ExternalEditor => &mut self.external_editor as &mut dyn ProcessModule, + State::Insert => &mut self.insert as &mut dyn ProcessModule, State::List => &mut self.list as &mut dyn ProcessModule, State::ShowCommit => &mut self.show_commit as &mut dyn ProcessModule, State::WindowSizeError => &mut self.window_size_error as &mut dyn ProcessModule, @@ -90,6 +94,7 @@ mod tests { case::confirm_rabase(State::ConfirmRebase), case::error(State::Error), case::external_editor(State::ExternalEditor), + case::insert(State::Insert), case::list(State::List), case::show_commit(State::ShowCommit), case::window_size_error(State::WindowSizeError) diff --git a/src/process/state.rs b/src/process/state.rs index b4bf7d2..4c42f22 100644 --- a/src/process/state.rs +++ b/src/process/state.rs @@ -5,6 +5,7 @@ pub enum State { Error, ExternalEditor, List, + Insert, ShowCommit, WindowSizeError, } diff --git a/src/process/testutil.rs b/src/process/testutil.rs index 02d2454..59e64b3 100644 --- a/src/process/testutil.rs +++ b/src/process/testutil.rs @@ -146,6 +146,7 @@ fn map_input_to_event(key_bindings: &KeyBindings, input: Input) -> Event { Input::ForceAbort => map_str_to_event(key_bindings.force_abort.first().unwrap().as_str()), Input::ForceRebase => map_str_to_event(key_bindings.force_rebase.first().unwrap().as_str()), Input::Help => map_str_to_event(key_bindings.help.first().unwrap().as_str()), + Input::InsertLine => map_str_to_event(key_bindings.insert_line.first().unwrap().as_str()), Input::Home | Input::ScrollTop => map_str_to_event("Home"), Input::Left | Input::ScrollLeft => map_str_to_event("Left"), Input::MoveCursorDown => map_str_to_event(key_bindings.move_down.first().unwrap().as_str()), @@ -202,6 +203,7 @@ fn format_process_result( State::ConfirmRebase => "ConfirmRebase", State::Error => "Error", State::ExternalEditor => "ExternalEditor", + State::Insert => "Insert", State::List => "List", State::ShowCommit => "ShowCommit", State::WindowSizeError => "WindowSizeError", @@ -230,6 +232,7 @@ fn format_process_result( Input::ForceAbort => String::from("ForceAbort"), Input::ForceRebase => String::from("ForceRebase"), Input::Help => String::from("Help"), + Input::InsertLine => String::from("InsertLine"), Input::Home => String::from("Home"), Input::Ignore => String::from("Ignore"), Input::Insert => String::from("Insert"), diff --git a/src/todo_file/line.rs b/src/todo_file/line.rs index 08e109b..e81d437 100644 --- a/src/todo_file/line.rs +++ b/src/todo_file/line.rs @@ -31,6 +31,42 @@ impl Line { } } + pub(crate) fn new_exec(command: &str) -> Self { + Self { + action: Action::Exec, + content: String::from(command), + hash: String::from(""), + mutated: false, + } + } + + pub(crate) fn new_merge(command: &str) -> Self { + Self { + action: Action::Merge, + content: String::from(command), + hash: String::from(""), + mutated: false, + } + } + + pub(crate) fn new_label(label: &str) -> Self { + Self { + action: Action::Label, + content: String::from(label), + hash: String::from(""), + mutated: false, + } + } + + pub(crate) fn new_reset(label: &str) -> Self { + Self { + action: Action::Reset, + content: String::from(label), + hash: String::from(""), + mutated: false, + } + } + pub(crate) fn new(input_line: &str) -> Result<Self> { if input_line.starts_with("noop") { return Ok(Self::new_noop()); @@ -235,6 +271,46 @@ mod tests { }); } + #[test] |