diff options
author | Tim Oram <dev@mitmaro.ca> | 2019-06-12 19:26:05 -0230 |
---|---|---|
committer | Tim Oram <dev@mitmaro.ca> | 2019-06-12 19:30:18 -0230 |
commit | 957a5d2dd8bc8eb38c88b1e7db7ac113c1e18c46 (patch) | |
tree | 2b987e656dbbf1f9242e1bf83e90512f399c900b | |
parent | 023c92bc6348a666b62e0b6d080361ae89b0250a (diff) |
Move edit into module
-rw-r--r-- | src/application.rs | 105 | ||||
-rw-r--r-- | src/edit/edit.rs | 155 | ||||
-rw-r--r-- | src/edit/mod.rs | 4 | ||||
-rw-r--r-- | src/main.rs | 1 | ||||
-rw-r--r-- | src/process/state.rs | 1 | ||||
-rw-r--r-- | src/view/view.rs | 34 |
6 files changed, 172 insertions, 128 deletions
diff --git a/src/application.rs b/src/application.rs index e91435d..63b2c37 100644 --- a/src/application.rs +++ b/src/application.rs @@ -3,6 +3,7 @@ use crate::git_interactive::GitInteractive; use crate::config::Config; use crate::constants::{LIST_HELP_LINES, VISUAL_MODE_HELP_LINES}; +use crate::edit::Edit; use crate::input::{Input, InputHandler}; use crate::process::{ ExitStatus, @@ -19,12 +20,10 @@ use crate::window::Window; use core::borrow::Borrow; use std::process::Command; use std::process::ExitStatus as ProcessExitStatus; -use unicode_segmentation::UnicodeSegmentation; pub struct Application<'a> { config: &'a Config, - edit_content: String, - edit_content_cursor: usize, + edit: Edit, git_interactive: GitInteractive, input_handler: &'a InputHandler<'a>, show_commit: ShowCommit, @@ -41,8 +40,7 @@ impl<'a> Application<'a> { { Self { config, - edit_content: String::from(""), - edit_content_cursor: 0, + edit: Edit::new(), git_interactive, input_handler, show_commit: ShowCommit::new(), @@ -58,8 +56,7 @@ impl<'a> Application<'a> { match state { State::ConfirmAbort => {}, State::ConfirmRebase => {}, - State::Edit => {}, - State::EditFinish => {}, + State::Edit => self.edit.activate(state, &self.git_interactive), State::Error { .. } => {}, State::Exiting => {}, State::ExternalEditor(_) => {}, @@ -77,8 +74,7 @@ impl<'a> Application<'a> { match state { State::ConfirmAbort => {}, State::ConfirmRebase => {}, - State::Edit => {}, - State::EditFinish => {}, + State::Edit => self.edit.deactivate(), State::Error { .. } => {}, State::Exiting => {}, State::ExternalEditor(_) => {}, @@ -96,8 +92,7 @@ impl<'a> Application<'a> { match state { State::ConfirmAbort => ProcessResult::new(), State::ConfirmRebase => ProcessResult::new(), - State::Edit => ProcessResult::new(), - State::EditFinish => self.process_edit_finish(), + State::Edit => self.edit.process(&mut self.git_interactive), State::Error { .. } => ProcessResult::new(), State::Exiting => ProcessResult::new(), State::ExternalEditor(return_state) => self.process_external_editor(return_state.borrow()), @@ -111,11 +106,6 @@ impl<'a> Application<'a> { } } - pub fn process_edit_finish(&mut self) -> ProcessResult { - self.git_interactive.edit_selected_line(self.edit_content.as_str()); - ProcessResultBuilder::new().state(State::List).build() - } - pub fn process_external_editor(&mut self, return_state: &State) -> ProcessResult { let mut result = ProcessResultBuilder::new(); @@ -174,8 +164,7 @@ impl<'a> Application<'a> { match state { State::ConfirmAbort => self.draw_confirm_abort(), State::ConfirmRebase => self.draw_confirm_rebase(), - State::Edit => self.draw_edit(), - State::EditFinish => {}, + State::Edit => self.edit.render(&self.view, &self.git_interactive), State::Error { message, .. } => self.draw_error(message.as_str()), State::Exiting => self.draw_exiting(), State::ExternalEditor(_) => {}, @@ -215,11 +204,6 @@ impl<'a> Application<'a> { ); } - fn draw_edit(&self) { - self.view - .draw_edit(self.edit_content.as_str(), self.edit_content_cursor); - } - fn draw_help(&self, help_state: &State) { self.view.draw_help( if *help_state == State::List { @@ -247,16 +231,11 @@ impl<'a> Application<'a> { self.input_handler.get_confirm() } - pub fn get_character(&self) -> Input { - self.input_handler.get_character() - } - pub fn handle_input(&mut self, state: State) -> HandleInputResult { match state { State::ConfirmAbort => self.handle_confirm_abort_input(), State::ConfirmRebase => self.handle_confirm_rebase_input(), - State::Edit => self.handle_edit(), - State::EditFinish => HandleInputResult::new(Input::Other), + State::Edit => self.edit.handle_input(&self.input_handler, &mut self.git_interactive), State::Error { return_state, .. } => self.handle_error_input(return_state.borrow()), State::Exiting => HandleInputResult::new(Input::Other), State::ExternalEditor(return_state) => self.handle_external_editor_input(return_state.borrow()), @@ -368,72 +347,6 @@ impl<'a> Application<'a> { result.build() } - fn handle_edit(&mut self) -> HandleInputResult { - let mut input; - let mut result; - loop { - input = self.get_character(); - result = HandleInputResultBuilder::new(input); - match input { - Input::Character(c) => { - let start = UnicodeSegmentation::graphemes(self.edit_content.as_str(), true) - .take(self.edit_content_cursor) - .collect::<String>(); - let end = UnicodeSegmentation::graphemes(self.edit_content.as_str(), true) - .skip(self.edit_content_cursor) - .collect::<String>(); - self.edit_content = format!("{}{}{}", start, c, end); - self.edit_content_cursor += 1; - }, - Input::Backspace => { - if self.edit_content_cursor == 0 { - break; - } - let start = UnicodeSegmentation::graphemes(self.edit_content.as_str(), true) - .take(self.edit_content_cursor - 1) - .collect::<String>(); - let end = UnicodeSegmentation::graphemes(self.edit_content.as_str(), true) - .skip(self.edit_content_cursor) - .collect::<String>(); - self.edit_content = format!("{}{}", start, end); - self.edit_content_cursor -= 1; - }, - Input::Delete => { - let length = UnicodeSegmentation::graphemes(self.edit_content.as_str(), true).count(); - if self.edit_content_cursor == length { - break; - } - let start = UnicodeSegmentation::graphemes(self.edit_content.as_str(), true) - .take(self.edit_content_cursor) - .collect::<String>(); - let end = UnicodeSegmentation::graphemes(self.edit_content.as_str(), true) - .skip(self.edit_content_cursor + 1) - .collect::<String>(); - self.edit_content = format!("{}{}", start, end); - }, - Input::MoveCursorRight => { - let length = UnicodeSegmentation::graphemes(self.edit_content.as_str(), true).count(); - if self.edit_content_cursor < length { - self.edit_content_cursor += 1; - } - }, - Input::MoveCursorLeft => { - if self.edit_content_cursor != 0 { - self.edit_content_cursor -= 1; - } - }, - Input::Enter => { - result = result.state(State::EditFinish); - }, - _ => { - continue; - }, - } - break; - } - result.build() - } - pub fn handle_error_input(&mut self, return_state: &State) -> HandleInputResult { let input = self.get_input(); let mut result = HandleInputResultBuilder::new(input); @@ -493,8 +406,6 @@ impl<'a> Application<'a> { Input::ActionSquash => self.set_selected_line_action(Action::Squash), Input::Edit => { if *self.git_interactive.get_selected_line_action() == Action::Exec { - self.edit_content = self.git_interactive.get_selected_line_edit_content().clone(); - self.edit_content_cursor = UnicodeSegmentation::graphemes(self.edit_content.as_str(), true).count(); result = result.state(State::Edit); } }, diff --git a/src/edit/edit.rs b/src/edit/edit.rs new file mode 100644 index 0000000..e7a6fa9 --- /dev/null +++ b/src/edit/edit.rs @@ -0,0 +1,155 @@ +use crate::git_interactive::GitInteractive; +use crate::input::{Input, InputHandler}; +use crate::process::{HandleInputResult, ProcessModule, ProcessResult, ProcessResultBuilder, State}; +use crate::view::View; +use crate::window::WindowColor; +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) -> 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); + }, + }; + result.build() + } + + fn handle_input( + &mut self, + input_handler: &InputHandler, + _git_interactive: &mut GitInteractive, + ) -> 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::<String>(); + let end = UnicodeSegmentation::graphemes(self.content.as_str(), true) + .skip(self.cursor_position) + .collect::<String>(); + 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::<String>(); + let end = UnicodeSegmentation::graphemes(self.content.as_str(), true) + .skip(self.cursor_position) + .collect::<String>(); + 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::<String>(); + let end = UnicodeSegmentation::graphemes(self.content.as_str(), true) + .skip(self.cursor_position + 1) + .collect::<String>(); + 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(WindowColor::Foreground); + + // 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(WindowColor::IndicatorColor); + 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 new file mode 100644 index 0000000..7083f01 --- /dev/null +++ b/src/edit/mod.rs @@ -0,0 +1,4 @@ +#[allow(clippy::module_inception)] +mod edit; + +pub use self::edit::Edit; diff --git a/src/main.rs b/src/main.rs index 79854f5..07919cd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,6 +8,7 @@ mod color; mod commit; mod config; mod constants; +mod edit; mod git_interactive; mod input; mod line; diff --git a/src/process/state.rs b/src/process/state.rs index 3d98c29..d750982 100644 --- a/src/process/state.rs +++ b/src/process/state.rs @@ -3,7 +3,6 @@ pub enum State { ConfirmAbort, ConfirmRebase, Edit, - EditFinish, Error { return_state: Box<State>, message: String }, Exiting, ExternalEditor(Box<State>), diff --git a/src/view/view.rs b/src/view/view.rs index 0ab26f9..93da142 100644 --- a/src/view/view.rs +++ b/src/view/view.rs @@ -28,7 +28,6 @@ use crate::view::{LineSegment, ViewLine}; use crate::window::Window; use crate::window::WindowColor; use std::cmp; -use unicode_segmentation::UnicodeSegmentation; pub struct View<'v> { help_top: ScrollPosition, @@ -53,6 +52,10 @@ impl<'v> View<'v> { self.window.color(color); } + pub fn set_style(&self, dim: bool, underline: bool, reverse: bool) { + self.window.set_style(dim, underline, reverse); + } + pub fn check_window_size(&self) -> bool { let (window_width, window_height) = self.window.get_window_size(); !(window_width <= MINIMUM_COMPACT_WINDOW_WIDTH || window_height <= MINIMUM_WINDOW_HEIGHT) @@ -408,33 +411,4 @@ impl<'v> View<'v> { pub fn draw_exiting(&self) { self.window.draw_str("Exiting...") } - - pub fn draw_edit(&self, line: &str, pointer: usize) { - self.draw_title(false); - self.window.set_style(false, true, false); - self.window.color(WindowColor::Foreground); - - // 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 { - self.window.set_style(false, true, false); - self.window.draw_str(c); - self.window.set_style(false, false, false); - } - else { - self.window.draw_str(c); - } - } - if pointer >= segment_length { - self.window.set_style(false, true, false); - self.window.draw_str(" "); - self.window.set_style(false, false, false); - } - - self.window.draw_str("\n\n"); - self.window.color(WindowColor::IndicatorColor); - self.window.draw_str("Enter to finish"); - } } |