From f97e2597709b6da6cd99cb42ea13dc25106795c2 Mon Sep 17 00:00:00 2001 From: Tim Oram Date: Thu, 17 Oct 2019 21:48:22 -0230 Subject: Update visibility to be required minimum This change updates the usages of `pub` to be the minimum level of visibility needed. This also required cleaning up some of the use statements to use a simpler set of imports. --- src/cli.rs | 2 +- src/commit/commit.rs | 70 ----- src/commit/file_stat.rs | 10 +- src/commit/mod.rs | 73 +++++- src/commit/user.rs | 6 +- src/commit/utils.rs | 4 +- src/config/config.rs | 105 -------- src/config/mod.rs | 111 +++++++- src/config/theme.rs | 36 +-- src/config/utils.rs | 14 +- src/confirm_abort/confirm_abort.rs | 40 --- src/confirm_abort/mod.rs | 46 +++- src/confirm_rebase/confirm_rebase.rs | 39 --- src/confirm_rebase/mod.rs | 45 +++- src/constants.rs | 28 +- src/display/color.rs | 4 +- src/display/color_manager.rs | 10 +- src/display/curses.rs | 36 ++- src/display/display.rs | 105 -------- src/display/display_color.rs | 2 +- src/display/mod.rs | 119 ++++++++- src/edit/edit.rs | 156 ----------- src/edit/mod.rs | 162 +++++++++++- src/error/error.rs | 56 ---- src/error/mod.rs | 61 ++++- src/exiting/exiting.rs | 17 -- src/exiting/mod.rs | 19 +- src/external_editor/argument_tolkenizer.rs | 4 +- src/external_editor/external_editor.rs | 188 -------------- src/external_editor/mod.rs | 188 +++++++++++++- src/git_interactive.rs | 53 ++-- src/help/help.rs | 150 ----------- src/help/mod.rs | 158 +++++++++++- src/help/utils.rs | 6 +- src/input/input.rs | 35 --- src/input/input_handler.rs | 10 +- src/input/mod.rs | 42 ++- src/input/utils.rs | 2 +- src/list/action.rs | 6 +- src/list/line.rs | 28 +- src/list/list.rs | 384 --------------------------- src/list/mod.rs | 402 ++++++++++++++++++++++++++++- src/list/utils.rs | 14 +- src/main.rs | 11 +- src/process/exit_status.rs | 4 +- src/process/handle_input_result.rs | 27 +- src/process/mod.rs | 268 +++++++++++++++++-- src/process/process.rs | 244 ----------------- src/process/process_module.rs | 9 +- src/process/process_result.rs | 23 +- src/process/state.rs | 2 +- src/scroll/mod.rs | 7 +- src/scroll/scroll_position.rs | 20 +- src/scroll/utils.rs | 2 +- src/show_commit/data.rs | 17 +- src/show_commit/mod.rs | 147 ++++++++++- src/show_commit/show_commit.rs | 147 ----------- src/show_commit/util.rs | 18 +- src/view/line_segment.rs | 15 +- src/view/mod.rs | 187 +++++++++++++- src/view/view.rs | 175 ------------- src/view/view_line.rs | 18 +- src/window_size_error/mod.rs | 65 ++++- src/window_size_error/window_size_error.rs | 62 ----- 64 files changed, 2240 insertions(+), 2274 deletions(-) delete mode 100644 src/commit/commit.rs delete mode 100644 src/config/config.rs delete mode 100644 src/confirm_abort/confirm_abort.rs delete mode 100644 src/confirm_rebase/confirm_rebase.rs delete mode 100644 src/display/display.rs delete mode 100644 src/edit/edit.rs delete mode 100644 src/error/error.rs delete mode 100644 src/exiting/exiting.rs delete mode 100644 src/external_editor/external_editor.rs delete mode 100644 src/help/help.rs delete mode 100644 src/input/input.rs delete mode 100644 src/list/list.rs delete mode 100644 src/process/process.rs delete mode 100644 src/show_commit/show_commit.rs delete mode 100644 src/view/view.rs delete mode 100644 src/window_size_error/window_size_error.rs (limited to 'src') diff --git a/src/cli.rs b/src/cli.rs index f9a52b0..ce217cb 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,7 +1,7 @@ use crate::constants::{NAME, VERSION}; use clap::App; -pub fn build_cli() -> App<'static, 'static> { +pub(crate) fn build_cli() -> App<'static, 'static> { App::new(NAME) .version(VERSION) .about("Full feature terminal based sequence editor for git interactive rebase.") diff --git a/src/commit/commit.rs b/src/commit/commit.rs deleted file mode 100644 index 4da3fb2..0000000 --- a/src/commit/commit.rs +++ /dev/null @@ -1,70 +0,0 @@ -use crate::commit::file_stat::FileStat; -use crate::commit::user::User; -use crate::commit::utils::load_commit_state; -use chrono::{DateTime, Local}; - -#[derive(Debug, PartialEq)] -pub struct Commit { - author: User, - body: Option, - committer: User, - date: DateTime, - file_stats: Option>, - hash: String, -} - -impl Commit { - pub fn new( - hash: String, - author: User, - committer: User, - date: DateTime, - file_stats: Option>, - body: Option, - ) -> Self - { - Commit { - author, - body, - committer, - date, - file_stats, - hash, - } - } - - pub fn from_commit_hash(hash: &str) -> Result { - load_commit_state(hash).map_err(|e| String::from(e.message())) - } - - pub fn get_author(&self) -> &User { - &self.author - } - - pub fn get_committer(&self) -> &User { - &self.committer - } - - pub fn get_date(&self) -> &DateTime { - &self.date - } - - pub fn get_hash(&self) -> &String { - &self.hash - } - - pub fn get_body(&self) -> &Option { - &self.body - } - - pub fn get_file_stats(&self) -> &Option> { - &self.file_stats - } - - pub fn get_file_stats_length(&self) -> usize { - match &self.file_stats { - Some(s) => s.len(), - None => 0, - } - } -} diff --git a/src/commit/file_stat.rs b/src/commit/file_stat.rs index d1eec95..5b9342b 100644 --- a/src/commit/file_stat.rs +++ b/src/commit/file_stat.rs @@ -1,14 +1,14 @@ use git2::Delta; #[derive(Debug, PartialEq)] -pub struct FileStat { +pub(crate) struct FileStat { status: Delta, to_name: String, from_name: String, } impl FileStat { - pub fn new(from_name: String, to_name: String, status: Delta) -> Self { + pub(super) fn new(from_name: String, to_name: String, status: Delta) -> Self { FileStat { status, to_name, @@ -16,15 +16,15 @@ impl FileStat { } } - pub fn get_status(&self) -> &Delta { + pub(crate) fn get_status(&self) -> &Delta { &self.status } - pub fn get_to_name(&self) -> &String { + pub(crate) fn get_to_name(&self) -> &String { &self.to_name } - pub fn get_from_name(&self) -> &String { + pub(crate) fn get_from_name(&self) -> &String { &self.from_name } } diff --git a/src/commit/mod.rs b/src/commit/mod.rs index a4d04aa..927c7dc 100644 --- a/src/commit/mod.rs +++ b/src/commit/mod.rs @@ -1,7 +1,74 @@ -#[allow(clippy::module_inception)] -mod commit; mod file_stat; mod user; mod utils; -pub use self::commit::Commit; +use crate::commit::file_stat::FileStat; +use crate::commit::user::User; +use crate::commit::utils::load_commit_state; +use chrono::{DateTime, Local}; + +#[derive(Debug, PartialEq)] +pub(crate) struct Commit { + author: User, + body: Option, + committer: User, + date: DateTime, + file_stats: Option>, + hash: String, +} + +impl Commit { + pub(super) fn new( + hash: String, + author: User, + committer: User, + date: DateTime, + file_stats: Option>, + body: Option, + ) -> Self + { + Commit { + author, + body, + committer, + date, + file_stats, + hash, + } + } + + pub(crate) fn from_commit_hash(hash: &str) -> Result { + load_commit_state(hash).map_err(|e| String::from(e.message())) + } + + pub(crate) fn get_author(&self) -> &User { + &self.author + } + + pub(crate) fn get_committer(&self) -> &User { + &self.committer + } + + pub(crate) fn get_date(&self) -> &DateTime { + &self.date + } + + pub(crate) fn get_hash(&self) -> &String { + &self.hash + } + + pub(crate) fn get_body(&self) -> &Option { + &self.body + } + + pub(crate) fn get_file_stats(&self) -> &Option> { + &self.file_stats + } + + pub(crate) fn get_file_stats_length(&self) -> usize { + match &self.file_stats { + Some(s) => s.len(), + None => 0, + } + } +} diff --git a/src/commit/user.rs b/src/commit/user.rs index cc4e963..d786ad1 100644 --- a/src/commit/user.rs +++ b/src/commit/user.rs @@ -1,18 +1,18 @@ #[derive(Debug, Eq, PartialEq)] -pub struct User { +pub(crate) struct User { name: Option, email: Option, } impl User { - pub fn new(name: Option<&str>, email: Option<&str>) -> Self { + pub(super) fn new(name: Option<&str>, email: Option<&str>) -> Self { User { email: email.map(String::from), name: name.map(String::from), } } - pub fn to_string(&self) -> Option { + pub(crate) fn to_string(&self) -> Option { let name = &self.name; let email = &self.email; match name { diff --git a/src/commit/utils.rs b/src/commit/utils.rs index 63b5308..e113428 100644 --- a/src/commit/utils.rs +++ b/src/commit/utils.rs @@ -1,10 +1,10 @@ -use crate::commit::commit::Commit; use crate::commit::file_stat::FileStat; use crate::commit::user::User; +use crate::commit::Commit; use chrono::{Local, TimeZone}; use git2::{Delta, DiffFindOptions, DiffOptions, Error, Repository}; -pub(crate) fn load_commit_state(hash: &str) -> Result { +pub(super) fn load_commit_state(hash: &str) -> Result { let repo = Repository::open_from_env()?; let commit = repo.find_commit(repo.revparse_single(hash)?.id())?; diff --git a/src/config/config.rs b/src/config/config.rs deleted file mode 100644 index 92e8155..0000000 --- a/src/config/config.rs +++ /dev/null @@ -1,105 +0,0 @@ -use crate::config::utils::{editor_from_env, get_bool, get_color, get_input, get_string, open_git_config}; -use crate::config::Theme; -use crate::display::Color; -use std::convert::TryFrom; - -#[derive(Clone, Debug)] -pub struct Config { - pub theme: Theme, - pub auto_select_next: bool, - pub comment_char: String, - pub editor: String, - 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_down_step: String, - pub input_move_left: String, - pub input_move_right: String, - pub input_move_selection_down: String, - pub input_move_selection_up: String, - pub input_move_up: String, - pub input_move_up_step: String, - pub input_open_in_external_editor: String, - pub input_rebase: String, - pub input_show_commit: String, - pub input_toggle_visual_mode: String, -} - -impl Config { - pub fn new() -> Result { - let git_config = open_git_config()?; - Ok(Config { - theme: Theme { - color_foreground: get_color(&git_config, "interactive-rebase-tool.foregroundColor", Color::White)?, - color_background: get_color(&git_config, "interactive-rebase-tool.backgroundColor", Color::Default)?, - color_selected_background: get_color( - &git_config, - "interactive-rebase-tool.selectedBackgroundColor", - Color::try_from("35,35,40").unwrap(), - )?, - color_indicator: get_color(&git_config, "interactive-rebase-tool.indicatorColor", Color::Cyan)?, - color_action_break: get_color(&git_config, "interactive-rebase-tool.breakColor", Color::White)?, - color_action_drop: get_color(&git_config, "interactive-rebase-tool.dropColor", Color::Red)?, - color_action_edit: get_color(&git_config, "interactive-rebase-tool.editColor", Color::Blue)?, - color_action_exec: get_color(&git_config, "interactive-rebase-tool.execColor", Color::White)?, - color_action_fixup: get_color(&git_config, "interactive-rebase-tool.fixupColor", Color::Magenta)?, - color_action_pick: get_color(&git_config, "interactive-rebase-tool.pickColor", Color::Green)?, - color_action_reword: get_color(&git_config, "interactive-rebase-tool.rewordColor", Color::Yellow)?, - color_action_squash: get_color(&git_config, "interactive-rebase-tool.squashColor", Color::Cyan)?, - color_diff_add: get_color(&git_config, "interactive-rebase-tool.diffAddColor", Color::Green)?, - color_diff_change: get_color(&git_config, "interactive-rebase-tool.diffChangeColor", Color::Yellow)?, - color_diff_remove: get_color(&git_config, "interactive-rebase-tool.diffRemoveColor", Color::Red)?, - character_vertical_spacing: get_string( - &git_config, - "interactive-rebase-tool.verticalSpacingCharacter", - "~", - )?, - }, - auto_select_next: get_bool(&git_config, "interactive-rebase-tool.autoSelectNext", false)?, - comment_char: get_string(&git_config, "core.commentChar", "#")?, - editor: get_string(&git_config, "core.editor", editor_from_env().as_str())?, - 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_left: get_input(&git_config, "interactive-rebase-tool.inputMoveLeft", "Left")?, - input_move_right: get_input(&git_config, "interactive-rebase-tool.inputMoveRight", "Right")?, - input_move_up_step: get_input(&git_config, "interactive-rebase-tool.inputMoveStepUp", "PageUp")?, - input_move_down_step: get_input(&git_config, "interactive-rebase-tool.inputMoveStepDown", "PageDown")?, - 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")?, - }) - } -} diff --git a/src/config/mod.rs b/src/config/mod.rs index 5afbb84..f786701 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -1,7 +1,108 @@ -#[allow(clippy::module_inception)] -mod config; -mod theme; +pub(crate) mod theme; mod utils; -pub use self::config::Config; -pub use self::theme::Theme; +use crate::config::theme::Theme; +use crate::config::utils::{editor_from_env, get_bool, get_color, get_input, get_string, open_git_config}; +use crate::display::color::Color; +use std::convert::TryFrom; + +#[derive(Clone, Debug)] +pub(crate) struct Config { + pub(crate) theme: Theme, + pub(crate) auto_select_next: bool, + pub(crate) comment_char: String, + pub(crate) editor: String, + pub(crate) input_abort: String, + pub(crate) input_action_break: String, + pub(crate) input_action_drop: String, + pub(crate) input_action_edit: String, + pub(crate) input_action_fixup: String, + pub(crate) input_action_pick: String, + pub(crate) input_action_reword: String, + pub(crate) input_action_squash: String, + pub(crate) input_confirm_no: String, + pub(crate) input_confirm_yes: String, + pub(crate) input_edit: String, + pub(crate) input_force_abort: String, + pub(crate) input_force_rebase: String, + pub(crate) input_help: String, + pub(crate) input_move_down: String, + pub(crate) input_move_down_step: String, + pub(crate) input_move_left: String, + pub(crate) input_move_right: String, + pub(crate) input_move_selection_down: String, + pub(crate) input_move_selection_up: String, + pub(crate) input_move_up: String, + pub(crate) input_move_up_step: String, + pub(crate) input_open_in_external_editor: String, + pub(crate) input_rebase: String, + pub(crate) input_show_commit: String, + pub(crate) input_toggle_visual_mode: String, +} + +impl Config { + pub(crate) fn new() -> Result { + let git_config = open_git_config()?; + Ok(Config { + theme: Theme { + color_foreground: get_color(&git_config, "interactive-rebase-tool.foregroundColor", Color::White)?, + color_background: get_color(&git_config, "interactive-rebase-tool.backgroundColor", Color::Default)?, + color_selected_background: get_color( + &git_config, + "interactive-rebase-tool.selectedBackgroundColor", + Color::try_from("35,35,40").unwrap(), + )?, + color_indicator: get_color(&git_config, "interactive-rebase-tool.indicatorColor", Color::Cyan)?, + color_action_break: get_color(&git_config, "interactive-rebase-tool.breakColor", Color::White)?, + color_action_drop: get_color(&git_config, "interactive-rebase-tool.dropColor", Color::Red)?, + color_action_edit: get_color(&git_config, "interactive-rebase-tool.editColor", Color::Blue)?, + color_action_exec: get_color(&git_config, "interactive-rebase-tool.execColor", Color::White)?, + color_action_fixup: get_color(&git_config, "interactive-rebase-tool.fixupColor", Color::Magenta)?, + color_action_pick: get_color(&git_config, "interactive-rebase-tool.pickColor", Color::Green)?, + color_action_reword: get_color(&git_config, "interactive-rebase-tool.rewordColor", Color::Yellow)?, + color_action_squash: get_color(&git_config, "interactive-rebase-tool.squashColor", Color::Cyan)?, + color_diff_add: get_color(&git_config, "interactive-rebase-tool.diffAddColor", Color::Green)?, + color_diff_change: get_color(&git_config, "interactive-rebase-tool.diffChangeColor", Color::Yellow)?, + color_diff_remove: get_color(&git_config, "interactive-rebase-tool.diffRemoveColor", Color::Red)?, + character_vertical_spacing: get_string( + &git_config, + "interactive-rebase-tool.verticalSpacingCharacter", + "~", + )?, + }, + auto_select_next: get_bool(&git_config, "interactive-rebase-tool.autoSelectNext", false)?, + comment_char: get_string(&git_config, "core.commentChar", "#")?, + editor: get_string(&git_config, "core.editor", editor_from_env().as_str())?, + 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_left: get_input(&git_config, "interactive-rebase-tool.inputMoveLeft", "Left")?, + input_move_right: get_input(&git_config, "interactive-rebase-tool.inputMoveRight", "Right")?, + input_move_up_step: get_input(&git_config, "interactive-rebase-tool.inputMoveStepUp", "PageUp")?, + input_move_down_step: get_input(&git_config, "interactive-rebase-tool.inputMoveStepDown", "PageDown")?, + 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")?, + }) + } +} diff --git a/src/config/theme.rs b/src/config/theme.rs index e655c1a..a94d209 100644 --- a/src/config/theme.rs +++ b/src/config/theme.rs @@ -1,21 +1,21 @@ -use crate::display::Color; +use crate::display::color::Color; #[derive(Clone, Debug)] -pub struct Theme { - pub color_foreground: Color, - pub color_background: Color, - pub color_selected_background: Color, - pub color_indicator: Color, - pub color_action_break: Color, - pub color_action_drop: Color, - pub color_action_edit: Color, - pub color_action_exec: Color, - pub color_action_fixup: Color, - pub color_action_pick: Color, - pub color_action_reword: Color, - pub color_action_squash: Color, - pub color_diff_add: Color, - pub color_diff_change: Color, - pub color_diff_remove: Color, - pub character_vertical_spacing: String, +pub(crate) struct Theme { + pub(crate) color_foreground: Color, + pub(crate) color_background: Color, + pub(crate) color_selected_background: Color, + pub(crate) color_indicator: Color, + pub(crate) color_action_break: Color, + pub(crate) color_action_drop: Color, + pub(crate) color_action_edit: Color, + pub(crate) color_action_exec: Color, + pub(crate) color_action_fixup: Color, + pub(crate) color_action_pick: Color, + pub(crate) color_action_reword: Color, + pub(crate) color_action_squash: Color, + pub(crate) color_diff_add: Color, + pub(crate) color_diff_change: Color, + pub(crate) color_diff_remove: Color, + pub(crate) character_vertical_spacing: String, } diff --git a/src/config/utils.rs b/src/config/utils.rs index 5251549..a5436ee 100644 --- a/src/config/utils.rs +++ b/src/config/utils.rs @@ -1,8 +1,8 @@ -use crate::display::Color; +use crate::display::color::Color; use std::convert::TryFrom; use std::env; -pub(in crate::config) fn get_input(config: &git2::Config, name: &str, default: &str) -> Result { +pub(super) fn get_input(config: &git2::Config, name: &str, default: &str) -> Result { let value = get_string(config, name, default)?; match value.to_lowercase().as_ref() { @@ -24,7 +24,7 @@ pub(in crate::config) fn get_input(config: &git2::Config, name: &str, default: & } } -pub(in crate::config) fn get_string(config: &git2::Config, name: &str, default: &str) -> Result { +pub(super) fn get_string(config: &git2::Config, name: &str, default: &str) -> Result { match config.get_string(name) { Ok(v) => Ok(v), Err(ref e) if e.code() == git2::ErrorCode::NotFound => Ok(String::from(default)), @@ -32,7 +32,7 @@ pub(in crate::config) fn get_string(config: &git2::Config, name: &str, default: } } -pub(in crate::config) fn get_bool(config: &git2::Config, name: &str, default: bool) -> Result { +pub(super) fn get_bool(config: &git2::Config, name: &str, default: bool) -> Result { match config.get_bool(name) { Ok(v) => Ok(v), Err(ref e) if e.code() == git2::ErrorCode::NotFound => Ok(default), @@ -40,7 +40,7 @@ pub(in crate::config) fn get_bool(config: &git2::Config, name: &str, default: bo } } -pub(in crate::config) fn get_color(config: &git2::Config, name: &str, default_color: Color) -> Result { +pub(super) fn get_color(config: &git2::Config, name: &str, default_color: Color) -> Result { match config.get_string(name) { Ok(v) => Color::try_from(v.to_lowercase().as_str()), Err(ref e) if e.code() == git2::ErrorCode::NotFound => Ok(default_color), @@ -48,13 +48,13 @@ pub(in crate::config) fn get_color(config: &git2::Config, name: &str, default_co } } -pub(in crate::config) fn editor_from_env() -> String { +pub(super) fn editor_from_env() -> String { env::var("VISUAL") .or_else(|_| env::var("EDITOR")) .unwrap_or_else(|_| String::from("vi")) } -pub(in crate::config) fn open_git_config() -> Result { +pub(super) fn open_git_config() -> Result { match git2::Repository::open_from_env() { Ok(f) => { match f.config() { diff --git a/src/confirm_abort/confirm_abort.rs b/src/confirm_abort/confirm_abort.rs deleted file mode 100644 index 7352b27..0000000 --- a/src/confirm_abort/confirm_abort.rs +++ /dev/null @@ -1,40 +0,0 @@ -use crate::git_interactive::GitInteractive; -use crate::input::{Input, InputHandler}; -use crate::process::{ExitStatus, HandleInputResult, HandleInputResultBuilder, ProcessModule, State}; -use crate::view::View; - -pub struct ConfirmAbort {} - -impl ProcessModule for ConfirmAbort { - fn handle_input( - &mut self, - input_handler: &InputHandler, - git_interactive: &mut GitInteractive, - _view: &View, - ) -> HandleInputResult - { - let input = input_handler.get_confirm(); - let mut result = HandleInputResultBuilder::new(input); - match input { - Input::Yes => { - git_interactive.clear(); - result = result.exit_status(ExitStatus::Good).state(State::Exiting); - }, - Input::No => { - result = result.state(State::List(false)); - }, - _ => {}, - } - result.build() - } - - fn render(&self, view: &View, _git_interactive: &GitInteractive) { - view.draw_confirm("Are you sure you want to abort"); - } -} - -impl ConfirmAbort { - pub fn new() -> Self { - Self {} - } -} diff --git a/src/confirm_abort/mod.rs b/src/confirm_abort/mod.rs index b91f7bc..2db9175 100644 --- a/src/confirm_abort/mod.rs +++ b/src/confirm_abort/mod.rs @@ -1,4 +1,44 @@ -#[allow(clippy::module_inception)] -mod confirm_abort; +use crate::git_interactive::GitInteractive; +use crate::input::input_handler::InputHandler; +use crate::input::Input; +use crate::process::exit_status::ExitStatus; +use crate::process::handle_input_result::{HandleInputResult, HandleInputResultBuilder}; +use crate::process::process_module::ProcessModule; +use crate::process::state::State; +use crate::view::View; -pub use self::confirm_abort::ConfirmAbort; +pub(crate) struct ConfirmAbort {} + +impl ProcessModule for ConfirmAbort { + fn handle_input( + &mut self, + input_handler: &InputHandler, + git_interactive: &mut GitInteractive, + _view: &View, + ) -> HandleInputResult + { + let input = input_handler.get_confirm(); + let mut result = HandleInputResultBuilder::new(input); + match input { + Input::Yes => { + git_interactive.clear(); + result = result.exit_status(ExitStatus::Good).state(State::Exiting); + }, + Input::No => { + result = result.state(State::List(false)); + }, + _ => {}, + } + result.build() + } + + fn render(&self, view: &View, _git_interactive: &GitInteractive) { + view.draw_confirm("Are you sure you want to abort"); + } +} + +impl ConfirmAbort { + pub(crate) fn new() -> Self { + Self {} + } +} diff --git a/src/confirm_rebase/confirm_rebase.rs b/src/confirm_rebase/confirm_rebase.rs deleted file mode 100644 index d362125..0000000 --- a/src/confirm_rebase/confirm_rebase.rs +++ /dev/null @@ -1,39 +0,0 @@ -use crate::git_interactive::GitInteractive; -use crate::input::{Input, InputHandler}; -use crate::process::{ExitStatus, HandleInputResult, HandleInputResultBuilder, ProcessModule, State}; -use crate::view::View; - -pub struct ConfirmRebase {} - -impl ProcessModule for ConfirmRebase { - fn handle_input( - &mut self, - input_handler: &InputHandler, - _git_interactive: &mut GitInteractive, - _view: &View, - ) -> HandleInputResult - { - let input = input_handler.get_confirm(); - let mut result = HandleInputResultBuilder::new(input); - match input { - Input::Yes => { - result = result.exit_status(ExitStatus::Good).state(State::Exiting); - }, - Input::No => { - result = result.state(State::List(false)); - }, - _ => {}, - } - result.build() - } - - fn render(&self, view: &View, _git_interactive: &GitInteractive) { - view.draw_confirm("Are you sure you want to rebase"); - } -} - -impl ConfirmRebase { - pub fn new() -> Self { - Self {} - } -} diff --git a/src/confirm_rebase/mod.rs b/src/confirm_rebase/mod.rs index d737016..b0d46d9 100644 --- a/src/confirm_rebase/mod.rs +++ b/src/confirm_rebase/mod.rs @@ -1,4 +1,43 @@ -#[allow(clippy::module_inception)] -mod confirm_rebase; +use crate::git_interactive::GitInteractive; +use crate::input::input_handler::InputHandler; +use crate::input::Input; +use crate::process::exit_status::ExitStatus; +use crate::process::handle_input_result::{HandleInputResult, HandleInputResultBuilder}; +use crate::process::process_module::ProcessModule; +use crate::process::state::State; +use crate::view::View; -pub use self::confirm_rebase::ConfirmRebase; +pub(crate) struct ConfirmRebase {} + +impl ProcessModule for ConfirmRebase { + fn handle_input( + &mut self, + input_handler: &InputHandler, + _git_interactive: &mut GitInteractive, + _view: &View, + ) -> HandleInputResult + { + let input = input_handler.get_confirm(); + let mut result = HandleInputResultBuilder::new(input); + match input { + Input::Yes => { + result = result.exit_status(ExitStatus::Good).state(State::Exiting); + }, + Input::No => { + result = result.state(State::List(false)); + }, + _ => {}, + } + result.build() + } + + fn render(&self, view: &View, _git_interactive: &GitInteractive) { + view.draw_confirm("Are you sure you want to rebase"); + } +} + +impl ConfirmRebase { + pub(crate) fn new() -> Self { + Self {} + } +} diff --git a/src/constants.rs b/src/constants.rs index 9dded56..7977aed 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -1,17 +1,17 @@ -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_LENGTH: i32 = 7; +pub(crate) const TITLE: &str = "Git Interactive Rebase Tool"; +pub(crate) const TITLE_LENGTH: i32 = 27; +pub(crate) const TITLE_SHORT: &str = "Git Rebase"; +pub(crate) const TITLE_SHORT_LENGTH: i32 = 10; +pub(crate) const TITLE_HELP_INDICATOR_LENGTH: i32 = 7; -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"; -pub const SHORT_ERROR_MESSAGE_WIDTH: usize = 16; +pub(crate) const HEIGHT_ERROR_MESSAGE: &str = "Window too small, increase height to continue\n"; +pub(crate) const MINIMUM_WINDOW_HEIGHT_ERROR_WIDTH: usize = 45; +pub(crate) const SHORT_ERROR_MESSAGE: &str = "Window too small\n"; +pub(crate) const SHORT_ERROR_MESSAGE_WIDTH: usize = 16; -pub const MINIMUM_WINDOW_HEIGHT: usize = 5; // title + pad top + line + pad bottom + help -pub const MINIMUM_COMPACT_WINDOW_WIDTH: usize = 20; // ">s ccc mmmmmmmmmmmmm".len() -pub const MINIMUM_FULL_WINDOW_WIDTH: usize = 34; // " > squash cccccccc mmmmmmmmmmmmm %".len() +pub(crate) const MINIMUM_WINDOW_HEIGHT: usize = 5; // title + pad top + line + pad bottom + help +pub(crate) const MINIMUM_COMPACT_WINDOW_WIDTH: usize = 20; // ">s ccc mmmmmmmmmmmmm".len() +pub(crate) const MINIMUM_FULL_WINDOW_WIDTH: usize = 34; // " > squash cccccccc mmmmmmmmmmmmm %".len() -pub const NAME: &str = "interactive-rebase-tool"; -pub const VERSION: &str = env!("CARGO_PKG_VERSION"); +pub(crate) const NAME: &str = "interactive-rebase-tool"; +pub(crate) const VERSION: &str = env!("CARGO_PKG_VERSION"); diff --git a/src/display/color.rs b/src/display/color.rs index a47e312..c311431 100644 --- a/src/display/color.rs +++ b/src/display/color.rs @@ -1,7 +1,7 @@ use std::convert::TryFrom; #[derive(Clone, Copy, Debug, PartialEq)] -pub enum Color { +pub(crate) enum Color { White, Black, Blue, @@ -55,7 +55,7 @@ impl TryFrom<&str> for Color { #[cfg(test)] mod tests { use super::Color; - use super::TryFrom; + use std::convert::TryFrom; #[test] fn action_try_from_str_black() { diff --git a/src/display/color_manager.rs b/src/display/color_manager.rs index 0aed928..ee30a77 100644 --- a/src/display/color_manager.rs +++ b/src/display/color_manager.rs @@ -1,9 +1,9 @@ -use crate::config::Theme; +use crate::config::theme::Theme; +use crate::display::curses::Curses; use crate::display::display_color::DisplayColor; -use crate::display::Curses; use pancurses::chtype; -pub(in crate::display) struct ColorManager { +pub(super) struct ColorManager { action_break: (chtype, chtype), action_drop: (chtype, chtype), action_edit: (chtype, chtype), @@ -20,7 +20,7 @@ pub(in crate::display) struct ColorManager { } impl ColorManager { - pub fn new(theme: &Theme, curses: &mut Curses) -> Self { + pub(super) fn new(theme: &Theme, curses: &mut Curses) -> Self { Self { normal: curses.register_selectable_color_pairs( theme.color_foreground, @@ -90,7 +90,7 @@ impl ColorManager { } } - pub fn get_color(&self, color: DisplayColor, selected: bool) -> chtype { + pub(super) fn get_color(&self, color: DisplayColor, selected: bool) -> chtype { if selected { match color { DisplayColor::ActionBreak => self.action_break.1, diff --git a/src/display/curses.rs b/src/display/curses.rs index bc3de35..9ca4baa 100644 --- a/src/display/curses.rs +++ b/src/display/curses.rs @@ -1,4 +1,4 @@ -use crate::display::Color; +use crate::display::color::Color; use pancurses::{ chtype, Input, @@ -13,17 +13,16 @@ use pancurses::{ }; use std::collections::HashMap; -pub struct Curses { +pub(crate) struct Curses { color_lookup: HashMap<(i16, i16, i16), i16>, color_index: i16, color_pair_index: i16, - pub number_of_colors: usize, + number_of_colors: usize, window: pancurses::Window, - pub has_colors: bool, } impl Curses { - pub fn new() -> Self { + pub(crate) fn new() -> Self { let window = pancurses::initscr(); window.keypad(true); @@ -41,7 +40,6 @@ impl Curses { Self { window, - has_colors, number_of_colors: pancurses::COLORS() as usize, color_lookup: HashMap::new(), color_index: 8, @@ -82,7 +80,7 @@ impl Curses { pancurses::COLOR_PAIR(index as chtype) } - pub fn register_selectable_color_pairs( + pub(super) fn register_selectable_color_pairs( &mut self, foreground: Color, background: Color, @@ -97,51 +95,51 @@ impl Curses { (standard_pair, standard_pair) } - pub fn erase(&self) { + pub(super) fn erase(&self) { self.window.erase(); } - pub fn refresh(&self) { + pub(super) fn refresh(&self) { self.window.refresh(); } - pub fn addstr(&self, s: &str) { + pub(super) fn addstr(&self, s: &str) { self.window.addstr(s); } - pub fn attrset>(&self, attributes: T) { + pub(super) fn attrset>(&self, attributes: T) { self.window.attrset(attributes); } - pub fn attron>(&self, attributes: T) { + pub(super) fn attron>(&self, attributes: T) { self.window.attron(attributes); } - pub fn attroff>(&self, attributes: T) { + pub(super) fn attroff>(&self, attributes: T) { self.window.attroff(attributes); } - pub fn getch(&self) -> Option { + pub(super) fn getch(&self) -> Option { self.window.getch() } - pub fn get_max_y(&self) -> i32 { + pub(super) fn get_max_y(&self) -> i32 { self.window.get_max_y() } - pub fn get_max_x(&self) -> i32 { + pub(super) fn get_max_x(&self) -> i32 { self.window.get_max_x() } - pub fn def_prog_mode(&self) { + pub(super) fn def_prog_mode(&self) { pancurses::def_prog_mode(); } - pub fn reset_prog_mode(&self) { + pub(super) fn reset_prog_mode(&self) { pancurses::reset_prog_mode(); } - pub fn endwin(&self) { + pub(super) fn endwin(&self) { pancurses::endwin(); } } diff --git a/src/display/display.rs b/src/display/display.rs deleted file mode 100644 index 9bb5d02..0000000 --- a/src/display/display.rs +++ /dev/null @@ -1,105 +0,0 @@ -use crate::config::Config; -use crate::display::color_manager::ColorManager; -use crate::display::display_color::DisplayColor; -use crate::display::Curses; -use pancurses::Input; -use std::cell::RefCell; - -pub struct Display<'d> { - color_manager: ColorManager, - curses: &'d Curses, - height: RefCell, - width: RefCell, -} - -impl<'d> Display<'d> { - pub fn new(curses: &'d mut Curses, config: &'d Config) -> Self { - Self { - color_manager: ColorManager::new(&config.theme, curses), - curses, - height: RefCell::new(curses.get_max_y()), - width: RefCell::new(curses.get_max_x()), - } - } - - pub fn draw_str(&self, s: &str) { - self.curses.addstr(s); - } - - pub fn clear(&self) { - self.color(DisplayColor::Normal, false); - self.set_style(false, false, false); - self.curses.erase(); - } - - pub fn refresh(&self) { - self.curses.refresh(); - } - - pub fn color(&self, color: DisplayColor, selected: bool) { - self.curses.attrset(self.color_manager.get_color(color, selected)); - } - - pub fn set_style(&self, dim: bool, underline: bool, reverse: bool) { - self.set_dim(dim); - self.set_underline(underline); - self.set_reverse(reverse); - } - - pub fn set_dim(&self, on: bool) { - if on { - self.curses.attron(pancurses::A_DIM); - } - else { - self.curses.attroff(pancurses::A_DIM); - } - } - - pub fn set_underline(&self, on: bool) { - // Windows uses blue text for underlined words - if !cfg!(windows) && on { - self.curses.attron(pancurses::A_UNDERLINE); - } - else { - self.curses.attroff(pancurses::A_UNDERLINE); - } - } - - pub fn set_reverse(&self, on: bool) { - if on { - self.curses.attron(pancurses::A_REVERSE); - } - else { - self.curses.attroff(pancurses::A_REVERSE); - } - } - - pub fn getch(&self) -> Option { - let input = self.curses.getch(); - - if let Some(Input::KeyResize) = input { - pancurses::resize_term(0, 0); - self.height.replace(self.curses.get_max_y()); - self.width.replace(self.curses.get_max_x()); - } - input - } - - pub fn get_window_size(&self) -> (i32, i32) { - (*self.width.borrow(), *self.height.borrow()) - } - - /// Leaves curses mode, runs the specified callback, and re-enables curses. - pub fn leave_temporarily(&self, callback: F) -> T - where F: FnOnce() -> T { - self.curses.def_prog_mode(); - self.curses.endwin(); - let rv = callback(); - self.curses.reset_prog_mode(); - rv - } - - pub fn end(&self) { - self.curses.endwin(); - } -} diff --git a/src/display/display_color.rs b/src/display/display_color.rs index 15212b8..742a83b 100644 --- a/src/display/display_color.rs +++ b/src/display/display_color.rs @@ -1,5 +1,5 @@ #[derive(Clone, Copy, Debug)] -pub enum DisplayColor { +pub(crate) enum DisplayColor { ActionBreak, ActionDrop, ActionEdit, diff --git a/src/display/mod.rs b/src/display/mod.rs index 5968399..556232e 100644 --- a/src/display/mod.rs +++ b/src/display/mod.rs @@ -1,11 +1,110 @@ -mod color; +pub(crate) mod color; mod color_manager; -mod curses; -#[allow(clippy::module_inception)] -mod display; -mod display_color; - -pub use self::color::Color; -pub use self::curses::Curses; -pub use self::display::Display; -pub use self::display_color::DisplayColor; +pub(crate) mod curses; +pub(crate) mod display_color; + +use crate::config::Config; +use crate::display::color_manager::ColorManager; +use crate::display::curses::Curses; +use crate::display::display_color::DisplayColor; +use pancurses::Input; +use std::cell::RefCell; + +pub(crate) struct Display<'d> { + color_manager: ColorManager, + curses: &'d Curses, + height: RefCell, + width: RefCell, +} + +impl<'d> Display<'d> { + pub(crate) fn new(curses: &'d mut Curses, config: &'d Config) -> Self { + Self { + color_manager: ColorManager::new(&config.theme, curses), + curses, + height: RefCell::new(curses.get_max_y()), + width: RefCell::new(curses.get_max_x()), + } + } + + pub(crate) fn draw_str(&self, s: &str) { + self.curses.addstr(s); + } + + pub(crate) fn clear(&self) { + self.color(DisplayColor::Normal, false); + self.set_style(false, false, false); + self.curses.erase(); + } + + pub(crate) fn refresh(&self) { + self.curses.refresh(); + } + + pub(crate) fn color(&self, color: DisplayColor, selected: bool) { + self.curses.attrset(self.color_manager.get_color(color, selected)); + } + + pub(crate) fn set_style(&self, dim: bool, underline: bool, reverse: bool) { + self.set_dim(dim); + self.set_underline(underline); + self.set_reverse(reverse); + } + + fn set_dim(&self, on: bool) { + if on { + self.curses.attron(pancurses::A_DIM); + } + else { + self.curses.attroff(pancurses::A_DIM); + } + } + + fn set_underline(&self, on: bool) { + // Windows uses blue text for underlined words + if !cfg!(windows) && on { + self.curses.attron(pancurses::A_UNDERLINE); + } + else { + self.curses.attroff(pancurses::A_UNDERLINE); + } + } + + fn set_reverse(&self, on: bool) { + if on { + self.curses.attron(pancurses::A_REVERSE); + } + else { + self.curses.attroff(pancurses::A_REVERSE); + } + } + + pub(crate) fn getch(&self) -> Option { + let input = self.curses.getch(); + + if let Some(Input::KeyResize) = input { + pancurses::resize_term(0, 0); + self.height.replace(self.curses.get_max_y()); + self.width.replace(self.curses.get_max_x()); + } + input + } + + pub(crate) fn get_window_size(&self) -> (i32, i32) { + (*self.width.borrow(), *self.height.borrow()) + } + + /// Leaves curses mode, runs the specified callback, and re-enables curses. + pub(crate) fn leave_temporarily(&self, callback: F) -> T + where F: FnOnce() -> T { + self.curses.def_prog_mode(); + self.curses.endwin(); + let rv = callback(); + self.curses.reset_prog_mode(); + rv + } + + pub(crate) fn end(&self) { + self.curses.endwin(); + } +} diff --git a/src/edit/edit.rs b/src/edit/edit.rs deleted file mode 100644 index 8415a2d..0000000 --- a/src/edit/edit.rs +++ /dev/null @@ -1,156 +0,0 @@ -use crate::display::DisplayColor; -use crate::git_interactive::GitInteractive; -use crate::input::{Input, InputHandler}; -use crate::process::{HandleInputResult, ProcessModule, ProcessResult, ProcessResultBuilder, State}; -use crate::view::View; -use unicode_segmentation::UnicodeSegmentation; - -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum EditState { - Active, - Finish, -} - -pub struct Edit { - content: String, - cursor_position: usize, - state: EditState, -} - -impl ProcessModule for Edit { - fn activate(&mut self, _state: State, application: &GitInteractive) { - self.state = EditState::Active; - self.content = application.get_selected_line_edit_content().clone(); - self.cursor_position = UnicodeSegmentation::graphemes(self.content.as_str(), true).count(); - } - - fn deactivate(&mut self) { - self.content.clear(); - self.cursor_position = 0; - } - - fn process(&mut self, git_interactive: &mut GitInteractive, _view: &View) -> ProcessResult { - let mut result = ProcessResultBuilder::new(); - match self.state { - EditState::Active => {}, - EditState::Finish => { - git_interactive.edit_selected_line(self.content.as_str()); - result = result.state(State::List(false)); - }, - }; - result.build() - } - - fn handle_input( - &mut self, - input_handler: &InputHandler, - _git_interactive: &mut GitInteractive, - _view: &View, - ) -> HandleInputResult - { - if self.state == EditState::Finish { - return HandleInputResult::new(Input::Enter); - } - let mut input; - loop { - input = input_handler.get_character(); - match input { - Input::Character(c) => { - let start = UnicodeSegmentation::graphemes(self.content.as_str(), true) - .take(self.cursor_position) - .collect::(); - let end = UnicodeSegmentation::graphemes(self.content.as_str(), true) - .skip(self.cursor_position) - .collect::(); - self.content = format!("{}{}{}", start, c, end); - self.cursor_position += 1; - }, - Input::Backspace => { - if self.cursor_position == 0 { - break; - } - let start = UnicodeSegmentation::graphemes(self.content.as_str(), true) - .take(self.cursor_position - 1) - .collect::(); - let end = UnicodeSegmentation::graphemes(self.content.as_str(), true) - .skip(self.cursor_position) - .collect::(); - self.content = format!("{}{}", start, end); - self.cursor_position -= 1; - }, - Input::Delete => { - let length = UnicodeSegmentation::graphemes(self.content.as_str(), true).count(); - if self.cursor_position == length { - break; - } - let start = UnicodeSegmentation::graphemes(self.content.as_str(), true) - .take(self.cursor_position) - .collect::(); - let end = UnicodeSegmentation::graphemes(self.content.as_str(), true) - .skip(self.cursor_position + 1) - .collect::(); - self.content = format!("{}{}", start, end); - }, - Input::MoveCursorRight => { - let length = UnicodeSegmentation::graphemes(self.content.as_str(), true).count(); - if self.cursor_position < length { - self.cursor_position += 1; - } - }, - Input::MoveCursorLeft => { - if self.cursor_position != 0 { - self.cursor_position -= 1; - } - }, - Input::Enter => self.state = EditState::Finish, - _ => { - continue; - }, - } - break; - } - HandleInputResult::new(input) - } - - fn render(&self, view: &View, _git_interactive: &GitInteractive) { - let line = self.content.as_str(); - let pointer = self.cursor_position; - - view.draw_title(false); - view.set_style(false, true, false); - view.set_color(DisplayColor::Normal, false); - - // this could probably be made way more efficient - let graphemes = UnicodeSegmentation::graphemes(line, true); - let segment_length = graphemes.clone().count(); - for (counter, c) in graphemes.enumerate() { - if counter == pointer { - view.set_style(false, true, false); - view.draw_str(c); - view.set_style(false, false, false); - } - else { - view.draw_str(c); - } - } - if pointer >= segment_length { - view.set_style(false, true, false); - view.draw_str(" "); - view.set_style(false, false, false); - } - - view.draw_str("\n\n"); - view.set_color(DisplayColor::IndicatorColor, false); - view.draw_str("Enter to finish"); - } -} - -impl Edit { - pub fn new() -> Self { - Self { - content: String::from(""), - cursor_position: 0, - state: EditState::Active, - } - } -} diff --git a/src/edit/mod.rs b/src/edit/mod.rs index 7083f01..2f500be 100644 --- a/src/edit/mod.rs +++ b/src/edit/mod.rs @@ -1,4 +1,160 @@ -#[allow(clippy::module_inception)] -mod edit; +use crate::display::display_color::DisplayColor; +use crate::git_interactive::GitInteractive; +use crate::input::input_handler::InputHandler; +use crate::input::Input; +use crate::process::handle_input_result::HandleInputResult; +use crate::process::process_module::ProcessModule; +use crate::process::process_result::{ProcessResult, ProcessResultBuilder}; +use crate::process::state::State; +use crate::view::View; +use unicode_segmentation::UnicodeSegmentation; -pub use self::edit::Edit; +#[derive(Clone, Copy, Debug, PartialEq)] +enum EditState { + Active, + Finish, +} + +pub(crate) struct Edit { + content: String, + cursor_position: usize, + state: EditState, +} + +impl ProcessModule for Edit { + fn activate(&mut self, _state: State, application: &GitInteractive) { + self.state = EditState::Active; + self.content = application.get_selected_line_edit_content().clone(); + self.cursor_position = UnicodeSegmentation::graphemes(self.content.as_str(), true).count(); + } + + fn deactivate(&mut self) { + self.content.clear(); + self.cursor_position = 0; + } + + fn process(&mut self, git_interactive: &mut GitInteractive, _view: &View) -> ProcessResult { + let mut result = ProcessResultBuilder::new(); + match self.state { + EditState::Active => {}, + EditState::Finish => { + git_interactive.edit_selected_line(self.content.as_str()); + result = result.state(State::List(false)); + }, + }; + result.build() + } + + fn handle_input( + &mut self, + input_handler: &InputHandler, + _git_interactive: &mut GitInteractive, + _view: &View, + ) -> HandleInputResult + { + if self.state == EditState::Finish { + return HandleInputResult::new(Input::Enter); + } + let mut input; + loop { + input = input_handler.get_character(); + match input { + Input::Character(c) => { + let start = UnicodeSegmentation::graphemes(self.content.as_str(), true) + .take(self.cursor_position) + .collect::(); + let end = UnicodeSegmentation::graphemes(self.content.as_str(), true) + .skip(self.cursor_position) + .collect::(); + self.content = format!("{}{}{}", start, c, end); + self.cursor_position += 1; + }, + Input::Backspace => { + if self.cursor_position == 0 { + break; + } + let start = UnicodeSegmentation::graphemes(self.content.as_str(), true) + .take(self.cursor_position - 1) + .collect::(); + let end = UnicodeSegmentation::graphemes(self.content.as_str(), true) + .skip(self.cursor_position) + .collect::(); + self.content = format!("{}{}", start, end); + self.cursor_position -= 1; + }, + Input::Delete => { + let length = UnicodeSegmentation::graphemes(self.content.as_str(), true).count(); + if self.cursor_position == length { + break; + } + let start = UnicodeSegmentation::graphemes(self.content.as_str(), true) + .take(self.cursor_position) + .collect::(); + let end = UnicodeSegmentation::graphemes(self.content.as_str(), true) + .skip(self.cursor_position + 1) + .collect::(); + self.content = format!("{}{}", start, end); + }, + Input::MoveCursorRight => { + let length = UnicodeSegmentation::graphemes(self.content.as_str(), true).count(); + if self.cursor_position < length { + self.cursor_position += 1; + } + }, + Input::MoveCursorLeft => { + if self.cursor_position != 0 { + self.cursor_position -= 1; + } + }, + Input::Enter => self.state = EditState::Finish, + _ => { + continue; + }, + } + break; + } + HandleInputResult::new(input) + } + + fn render(&self, view: &View, _git_interactive: &GitInteractive) { + let line = self.content.as_str(); + let pointer = self.cursor_position; + + view.draw_title(false); + view.set_style(false, true, false); + view.set_color(DisplayColor::Normal, false); + + // this could probably be made way more efficient + let graphemes = UnicodeSegmentation::graphemes(line, true); + let segment_length = graphemes.clone().count(); + for (counter, c) in graphemes.enumerate() { + if counter == pointer { + view.set_style(false, true, false); + view.draw_str(c); + view.set_style(false, false, false); + } + else { + view.draw_str(c); + } + } + if pointer >= segment_length { + view.set_style(false, true, false); + view.draw_str(" "); + view.set_style(false, false, false); + } + + view.draw_str("\n\n"); + view.set_color(DisplayColor::IndicatorColor, false); + view.draw_str("Enter to finish"); + } +} + +impl Edit { + pub(crate) fn new() -> Self { + Self { + content: String::from(""), + cursor_position: 0, + state: EditState::Active, + } + } +} diff --git a/src/error/error.rs b/src/error/error.rs deleted file mode 100644 index 4e631ad..0000000 --- a/src/error/error.rs +++ /dev/null @@ -1,56 +0,0 @@ -use crate::git_interactive::GitInteractive; -use crate::input::{Input, InputHandler}; -use crate::process::{HandleInputResult, HandleInputResultBuilder, ProcessModule, State}; -use crate::view::View; - -pub struct Error { - error_message: String, - return_state: State, -} - -impl ProcessModule for Error { - fn activate(&mut self, state: State, _git_interactive: &GitInteractive) { - if let State::Error { message, return_state } = state { - self.error_message = message; - self.return_state = *return_state; - } - else { - panic!("Help module activated when not expected"); - } - } - - fn deactivate(&mut self) { - self.error_message.clear(); - } - - fn handle_input( - &mut self, - input_handler: &InputHandler, - _git_interactive: &mut GitInteractive, - _view: &View, - ) -> HandleInputResult - { - let input = input_handler.get_input(); - let mut result = HandleInputResultBuilder::new(input); - match input { - Input::Resize => {}, - _ => { - result = result.state(self.return_state.clone()); - }, - } - result.build() - } - - fn render(&self, view: &View, _git_interactive: &GitInteractive) { - view.draw_error(self.error_message.as_str()); - } -} - -impl Error { - pub fn new() -> Self { - Self { - error_message: String::from(""), - return_state: State::List(false), - } - } -} diff --git a/src/error/mod.rs b/src/error/mod.rs index 604779b..c088252 100644 --- a/src/error/mod.rs +++ b/src/error/mod.rs @@ -1,4 +1,59 @@ -#[allow(clippy::module_inception)] -mod error; +use crate::git_interactive::GitInteractive; +use crate::input::input_handler::InputHandler; +use crate::input::Input; +use crate::process::handle_input_result::{HandleInputResult, HandleInputResultBuilder}; +use crate::process::process_module::ProcessModule; +use crate::process::state::State; +use crate::view::View; -pub use self::error::Error; +pub(crate) struct Error { + error_message: String, + return_state: State, +} + +impl ProcessModule for Error { + fn activate(&mut self, state: State, _git_interactive: &GitInteractive) { + if let State::Error { message, return_state } = state { + self.error_message = message; + self.return_state = *return_state; + } + else { + panic!("Help module activated when not expected"); + } + } + + fn deactivate(&mut self) { + self.error_message.clear(); + } + + fn handle_input( + &mut self, + input_handler: &InputHandler, + _git_interactive: &mut GitInteractive, + _view: &View, + ) -> HandleInputResult + { + let input = input_handler.get_input(); + let mut result = HandleInputResultBuilder::new(input); + match input { + Input::Resize => {}, + _ => { + result = result.state(self.return_state.clone()); + }, + } + result.build() + } + + fn render(&self, view: &View, _git_interactive: &GitInteractive) { + view.draw_error(self.error_message.as_str()); + } +} + +impl Error { + pub(crate) fn new() -> Self { + Self { + error_message: String::from(""), + return_state: State::List(false), + } + } +} diff --git a/src/exiting/exiting.rs b/src/exiting/exiting.rs deleted file mode 100644 index ef13fa4..0000000 --- a/src/exiting/exiting.rs +++ /dev/null @@ -1,17 +0,0 @@ -use crate::git_interactive::GitInteractive; -use crate::process::ProcessModule; -use crate::view::View; - -pub struct Exiting {} - -impl ProcessModule for Exiting { - fn render(&self, view: &View, _git_interactive: &GitInteractive) { - view.draw_str("Exiting...") - } -} - -impl Exiting { - pub fn new() -> Self { - Self {} - } -} diff --git a/src/exiting/mod.rs b/src/exiting/mod.rs index 2d7e7f4..5c29372 100644 --- a/src/exiting/mod.rs +++ b/src/exiting/mod.rs @@ -1,4 +1,17 @@ -#[allow(clippy::module_inception)] -mod exiting; +use crate::git_interactive::GitInteractive; +use crate::process::process_module::ProcessModule; +use crate::view::View; -pub use self::exiting::Exiting; +pub(crate) struct Exiting {} + +impl ProcessModule for Exiting { + fn render(&self, view: &View, _git_interactive: &GitInteractive) { + view.draw_str("Exiting...") + } +} + +impl Exiting { + pub(crate) fn new() -> Self { + Self {} + } +} diff --git a/src/external_editor/argument_tolkenizer.rs b/src/external_editor/argument_tolkenizer.rs index f1b007a..e3c0e54 100644 --- a/src/external_editor/argument_tolkenizer.rs +++ b/src/external_editor/argument_tolkenizer.rs @@ -1,3 +1,5 @@ +use std::iter::Iterator; + #[derive(Clone, Copy, Debug, PartialEq)] enum State { Normal, @@ -7,7 +9,7 @@ enum State { WhiteSpace, } -pub fn tolkenize(input: &str) -> Option> { +pub(super) fn tolkenize(input: &str) -> Option> { let mut previous_state = State::Normal; let mut state = State::Normal; let mut token_start: usize = 0; diff --git a/src/external_editor/external_editor.rs b/src/external_editor/external_editor.rs deleted file mode 100644 index db36d2b..0000000 --- a/src/external_editor/external_editor.rs +++ /dev/null @@ -1,188 +0,0 @@ -use crate::config::Config; -use crate::display::Display; -use crate::external_editor::argument_tolkenizer::tolkenize; -use crate::git_interactive::GitInteractive; -use crate::input::{Input, InputHandler}; -use crate::process::{ - ExitStatus, - HandleInputResult, - HandleInputResultBuilder, - ProcessModule, - ProcessResult, - ProcessResultBuilder, - State, -}; -use crate::view::View; -use std::ffi::OsString; -use std::process::Command; -use std::process::ExitStatus as ProcessExitStatus; - -#[derive(Clone, Debug, PartialEq)] -enum ExternalEditorState { - Active, - Error, - Empty, - Finish, -} - -pub struct ExternalEditor<'e> { - config: &'e Config, - display: &'e Display<'e>, - state: ExternalEditorState, -} - -impl<'e> ProcessModule for ExternalEditor<'e> { - fn activate(&mut self, _state: State, _git_interactive: &GitInteractive) { - if self.state != ExternalEditorState::Empty { - self.state = ExternalEditorState::Active; - } - } - - fn process(&mut self, git_interactive: &mut GitInteractive, _view: &View) -> ProcessResult { - match self.state { - ExternalEditorState::Active => self.process_active(git_interactive), - ExternalEditorState::Error => self.process_error(git_interactive), - ExternalEditorState::Empty => ProcessResult::new(), - ExternalEditorState::Finish => self.process_finish(git_interactive), - } - } - - fn handle_input( - &mut self, - input_handler: &InputHandler, - _git_interactive: &mut GitInteractive, - _view: &View, - ) -> HandleInputResult - { - match self.state { - ExternalEditorState::Active => self.handle_input_active(input_handler), - ExternalEditorState::Empty => self.handle_input_empty(input_handler), - _ => HandleInputResult::new(Input::Other), - } - } - - fn render(&self, view: &View, _git_interactive: &GitInteractive) { - if let ExternalEditorState::Empty = self.state { - view.draw_confirm("Empty rebase todo file. Do you wish to exit?"); - } - } -} - -impl<'e> ExternalEditor<'e> { - pub fn new(display: &'e Display, config: &'e Config) -> Self { - Self { - config, - display, - state: ExternalEditorState::Active, - } - } - - pub fn run_editor(&mut self, git_interactive: &GitInteractive) -> Result<(), String> { - let mut arguments = match tolkenize(self.config.editor.as_str()) { - Some(args) => { - if args.is_empty() { - return Err(String::from("No editor configured")); - } - args.into_iter().map(OsString::from) - }, - None => { - return Err(format!("Invalid editor: {}", self.config.editor)); - }, - }; - - git_interactive.write_file()?; - let filepath = git_interactive.get_filepath(); - let callback = || -> Result { - let mut file_pattern_found = false; - let mut cmd = Command::new(arguments.next().unwrap()); - for arg in arguments { - if arg.as_os_str() == "%" { - file_pattern_found = true; - cmd.arg(filepath.as_os_str()); - } - else { - cmd.arg(arg); - } - } - if !file_pattern_found { - cmd.arg(filepath.as_os_str()); - } - cmd.status() - .map_err(|e| format!("Unable to run editor ({}):\n{}", self.config.editor, e.to_string())) - }; - let exit_status: ProcessExitStatus = self.display.leave_temporarily(callback)?; - - if !exit_status.success() { - return Err(String::from("Editor returned non-zero exit status.")); - } - - Ok(()) - } - - fn process_active(&mut self, git_interactive: &GitInteractive) -> ProcessResult { - let mut result = ProcessResultBuilder::new(); - if let Err(e) = self.run_editor(git_interactive) { - result = result.error(e.as_str(), State::ExternalEditor); - self.state = ExternalEditorState::Error; - } - else { - self.state = ExternalEditorState::Finish; - } - result.build() - } - - fn process_finish(&mut self, git_interactive: &mut GitInteractive) -> ProcessResult { - let mut result = ProcessResultBuilder::new(); - if let Err(e) = git_interactive.reload_file(self.config.comment_char.as_str()) { - result = result.error(e.as_str(), State::ExternalEditor); - self.state = ExternalEditorState::Error; - } - else if git_interactive.get_lines().is_empty() { - self.state = ExternalEditorState::Empty; - } - else { - result = result.state(State::List(false)); - } - result.build() - } - - fn process_error(&self, git_interactive: &GitInteractive) -> ProcessResult { - let mut result = ProcessResultBuilder::new().state(State::Exiting); - - if git_interactive.get_lines().is_empty() { - result = result.exit_status(ExitStatus::Good); - } - else { - result = result.exit_status(ExitStatus::StateError); - } - result.build() - } - - fn handle_input_active(&self, input_handler: &InputHandler) -> HandleInputResult { - let input = input_handler.get_input(); - let mut result = HandleInputResultBuilder::new(input); - match input { - Input::Resize => {}, - _ => { - result = result.state(State::List(false)); - }, - } - result.build() - } - - fn handle_input_empty(&mut self, input_handler: &InputHandler) -> HandleInputResult { - let input = input_handler.get_confirm(); - let mut result = HandleInputResultBuilder::new(input); - match input { - Input::Yes => { - result = result.exit_status(ExitStatus::Good).state(State::Exiting); - }, - Input::No => { - self.state = ExternalEditorState::Active; - result = result.state(State::ExternalEditor); - }, - _ => {}, - } - result.build() - } -} diff --git a/src/external_editor/mod.rs b/src/external_editor/mod.rs index 495d507..1099fde 100644 --- a/src/external_editor/mod.rs +++ b/src/external_editor/mod.rs @@ -1,5 +1,187 @@ mod argument_tolkenizer; -#[allow(clippy::module_inception)] -mod external_editor; -pub use self::external_editor::ExternalEditor; +use crate::config::Config; +use crate::display::Display; +use crate::external_editor::argument_tolkenizer::tolkenize; +use crate::git_interactive::GitIn