diff options
author | Tim Oram <dev@mitmaro.ca> | 2021-01-17 19:36:19 -0330 |
---|---|---|
committer | Tim Oram <dev@mitmaro.ca> | 2021-01-27 19:03:19 -0330 |
commit | ca089a55bd8ab3c7387bff0a92a4aab674e73d05 (patch) | |
tree | 541ed80c3cf197fdf8bb4c9ecac723568adf0131 | |
parent | 65ffadbe8481cd1c852f585fe1e14820f2c74f67 (diff) |
Return result in display
-rw-r--r-- | src/display/mod.rs | 59 | ||||
-rw-r--r-- | src/display/virtual_curses.rs | 2 | ||||
-rw-r--r-- | src/process/mod.rs | 9 | ||||
-rw-r--r-- | src/view/mod.rs | 121 |
4 files changed, 104 insertions, 87 deletions
diff --git a/src/display/mod.rs b/src/display/mod.rs index 1d7fdfd..3114e28 100644 --- a/src/display/mod.rs +++ b/src/display/mod.rs @@ -20,6 +20,7 @@ use crate::display::display_color::DisplayColor; pub use crate::display::size::Size; use crate::input::input_handler::{InputHandler, InputMode}; use crate::input::Input; +use anyhow::Result; use std::cell::RefCell; use std::convert::TryInto; @@ -165,21 +166,24 @@ impl<'d> Display<'d> { } } - pub(crate) fn draw_str(&mut self, s: &str) { + pub(crate) fn draw_str(&mut self, s: &str) -> Result<()> { self.curses.addstr(s); + Ok(()) } - pub(crate) fn clear(&mut self) { - self.color(DisplayColor::Normal, false); - self.set_style(false, false, false); + pub(crate) fn clear(&mut self) -> Result<()> { + self.color(DisplayColor::Normal, false)?; + self.set_style(false, false, false)?; self.curses.erase(); + Ok(()) } - pub(crate) fn refresh(&mut self) { + pub(crate) fn refresh(&mut self) -> Result<()> { self.curses.refresh(); + Ok(()) } - pub(crate) fn color(&mut self, color: DisplayColor, selected: bool) { + pub(crate) fn color(&mut self, color: DisplayColor, selected: bool) -> Result<()> { self.curses.attrset( if selected { match color { @@ -220,24 +224,26 @@ impl<'d> Display<'d> { } }, ); + Ok(()) } - pub(crate) fn set_style(&mut self, dim: bool, underline: bool, reverse: bool) { - self.set_dim(dim); - self.set_underline(underline); - self.set_reverse(reverse); + pub(crate) fn set_style(&mut self, dim: bool, underline: bool, reverse: bool) -> Result<()> { + self.set_dim(dim)?; + self.set_underline(underline)?; + self.set_reverse(reverse) } - fn set_dim(&mut self, on: bool) { + fn set_dim(&mut self, on: bool) -> Result<()> { if on { self.curses.attron(A_DIM); } else { self.curses.attroff(A_DIM); } + Ok(()) } - fn set_underline(&mut self, on: bool) { + fn set_underline(&mut self, on: bool) -> Result<()> { // Windows uses blue text for underlined words if !cfg!(windows) && on { self.curses.attron(A_UNDERLINE); @@ -245,15 +251,17 @@ impl<'d> Display<'d> { else { self.curses.attroff(A_UNDERLINE); } + Ok(()) } - fn set_reverse(&mut self, on: bool) { + fn set_reverse(&mut self, on: bool) -> Result<()> { if on { self.curses.attron(A_REVERSE); } else { self.curses.attroff(A_REVERSE); } + Ok(()) } pub(crate) fn get_input(&self, mode: InputMode) -> Input { @@ -275,16 +283,19 @@ impl<'d> Display<'d> { Size::new(*self.width.borrow(), *self.height.borrow()) } - pub(crate) fn fill_end_of_line(&mut self) { + pub(crate) fn fill_end_of_line(&mut self) -> Result<()> { self.curses.hline(' ', self.curses.get_max_x()); + Ok(()) } - pub(crate) fn ensure_at_line_start(&mut self, y: i32) { + pub(crate) fn ensure_at_line_start(&mut self, y: i32) -> Result<()> { self.curses.mv(y, 0); + Ok(()) } - pub(crate) fn move_from_end_of_line(&mut self, right: i32) { + pub(crate) fn move_from_end_of_line(&mut self, right: i32) -> Result<()> { self.curses.mv(self.curses.get_cur_y(), self.curses.get_max_x() - right); + Ok(()) } pub(crate) fn def_prog_mode(&self) { @@ -335,7 +346,7 @@ mod tests { &mut test_context.curses, &test_context.config.theme, ); - display.draw_str("Test String"); + display.draw_str("Test String").unwrap(); let output = Curses::get_output(); assert_eq!(output, vec!["Test String"]); }); @@ -355,7 +366,7 @@ mod tests { &mut test_context.curses, &test_context.config.theme, ); - display.clear(); + display.clear().unwrap(); assert!(Curses::get_output().is_empty()); assert!(!test_context.curses.is_dimmed()); assert!(!test_context.curses.is_reverse()); @@ -372,7 +383,7 @@ mod tests { &mut test_context.curses, &test_context.config.theme, ); - display.refresh(); + display.refresh().unwrap(); assert_eq!(test_context.curses.get_state(), State::Refreshed); }); } @@ -420,7 +431,7 @@ mod tests { &mut test_context.curses, &test_context.config.theme, ); - display.color(display_color, selected); + display.color(display_color, selected).unwrap(); assert!(test_context.curses.is_color_enabled(expected)); }); } @@ -446,7 +457,7 @@ mod tests { &mut test_context.curses, &test_context.config.theme, ); - display.set_style(dim, underline, reverse); + display.set_style(dim, underline, reverse).unwrap(); assert_eq!(test_context.curses.is_dimmed(), dim); assert_eq!(test_context.curses.is_underline(), underline); assert_eq!(test_context.curses.is_reverse(), reverse); @@ -506,7 +517,7 @@ mod tests { &mut test_context.curses, &test_context.config.theme, ); - display.fill_end_of_line(); + display.fill_end_of_line().unwrap(); assert_eq!(Curses::get_output()[0], "{HLINE| |23}"); }); } @@ -522,7 +533,7 @@ mod tests { &mut test_context.curses, &test_context.config.theme, ); - display.ensure_at_line_start(5); + display.ensure_at_line_start(5).unwrap(); assert_eq!(test_context.curses.get_cur_y(), 5); assert_eq!(test_context.curses.get_cur_x(), 0); }); @@ -539,7 +550,7 @@ mod tests { &mut test_context.curses, &test_context.config.theme, ); - display.move_from_end_of_line(5); + display.move_from_end_of_line(5).unwrap(); assert_eq!(test_context.curses.get_cur_x(), 20); }); } diff --git a/src/display/virtual_curses.rs b/src/display/virtual_curses.rs index 6497de0..decd0ee 100644 --- a/src/display/virtual_curses.rs +++ b/src/display/virtual_curses.rs @@ -114,7 +114,7 @@ impl Curses { } #[allow(clippy::unused_self)] - pub(super) fn erase(&self) { + pub(crate) fn erase(&self) { OUTPUT.lock().unwrap().clear(); } diff --git a/src/process/mod.rs b/src/process/mod.rs index c11bfc3..8e3541b 100644 --- a/src/process/mod.rs +++ b/src/process/mod.rs @@ -48,8 +48,13 @@ impl<'r> Process<'r> { } self.activate(&mut modules, State::List); while self.exit_status.is_none() { - self.view - .render(modules.build_view_data(self.state, &self.view, &self.rebase_todo)); + if let Err(_) = self + .view + .render(modules.build_view_data(self.state, &self.view, &self.rebase_todo)) + { + self.exit_status = Some(ExitStatus::StateError); + continue; + } let result = modules.handle_input(self.state, &self.view, &mut self.rebase_todo); self.handle_process_result(&mut modules, &result); } diff --git a/src/view/mod.rs b/src/view/mod.rs index 629f14d..1458f00 100644 --- a/src/view/mod.rs +++ b/src/view/mod.rs @@ -13,6 +13,7 @@ use crate::input::Input; use crate::view::view_data::ViewData; use crate::view::view_line::ViewLine; use crate::Config; +use anyhow::Result; pub struct View<'v> { config: &'v Config, @@ -39,34 +40,33 @@ impl<'v> View<'v> { } pub(crate) fn end(&self) { - self.display.end(); + self.display.end() } pub(crate) fn get_input(&self, mode: InputMode) -> Input { self.display.get_input(mode) } - pub(crate) fn render(&mut self, view_data: &ViewData) { - self.display.clear(); + pub(crate) fn render(&mut self, view_data: &ViewData) -> Result<()> { + self.display.clear()?; let window_height = self.display.get_window_size().height(); let mut line_index = 0; if view_data.show_title() { - self.display.ensure_at_line_start(line_index); + self.display.ensure_at_line_start(line_index)?; line_index += 1; - self.draw_title(view_data.show_help()); + self.draw_title(view_data.show_help())?; } if let Some(ref prompt) = *view_data.get_prompt() { - self.display.set_style(false, false, false); - self.display.draw_str("\n"); + self.display.set_style(false, false, false)?; + self.display.draw_str("\n")?; self.display.draw_str(&format!( - "{} ({}/{})?", + "{} ({}/{})? ", prompt, self.config.key_bindings.confirm_yes, self.config.key_bindings.confirm_no - )); - self.display.draw_str(" "); - return; + ))?; + return Ok(()); } let leading_lines = view_data.get_leading_lines(); @@ -79,100 +79,100 @@ impl<'v> View<'v> { let scroll_indicator_index = view_data.get_scroll_index(); for line in leading_lines { - self.display.ensure_at_line_start(line_index); + self.display.ensure_at_line_start(line_index)?; line_index += 1; - self.draw_view_line(line); + self.draw_view_line(line)?; } for (index, line) in lines.iter().enumerate() { - self.display.ensure_at_line_start(line_index); - self.draw_view_line(line); + self.display.ensure_at_line_start(line_index)?; + self.draw_view_line(line)?; if show_scroll_bar { - self.display.ensure_at_line_start(line_index); - self.display.move_from_end_of_line(1); - self.display.color(DisplayColor::Normal, false); - self.display.set_style(scroll_indicator_index != index, false, true); - self.display.draw_str(" "); + self.display.ensure_at_line_start(line_index)?; + self.display.move_from_end_of_line(1)?; + self.display.color(DisplayColor::Normal, false)?; + self.display.set_style(scroll_indicator_index != index, false, true)?; + self.display.draw_str(" ")?; } - self.display.color(DisplayColor::Normal, false); - self.display.set_style(false, false, false); + self.display.color(DisplayColor::Normal, false)?; + self.display.set_style(false, false, false)?; line_index += 1; } if view_height > lines.len() { - self.display.color(DisplayColor::Normal, false); - self.display.set_style(false, false, false); + self.display.color(DisplayColor::Normal, false)?; + self.display.set_style(false, false, false)?; let draw_height = view_height - lines.len() - if view_data.show_title() { 1 } else { 0 }; - self.display.ensure_at_line_start(line_index); + self.display.ensure_at_line_start(line_index)?; for _x in 0..draw_height { line_index += 1; self.display - .draw_str(format!("{}\n", self.config.theme.character_vertical_spacing).as_str()); + .draw_str(format!("{}\n", self.config.theme.character_vertical_spacing).as_str())?; } } for line in trailing_lines { - self.display.ensure_at_line_start(line_index); + self.display.ensure_at_line_start(line_index)?; line_index += 1; - self.draw_view_line(line); + self.draw_view_line(line)?; } - self.display.refresh(); + self.display.refresh() } - fn draw_view_line(&mut self, line: &ViewLine) { + fn draw_view_line(&mut self, line: &ViewLine) -> Result<()> { for segment in line.get_segments() { - self.display.color(segment.get_color(), line.get_selected()); + self.display.color(segment.get_color(), line.get_selected())?; self.display - .set_style(segment.is_dimmed(), segment.is_underlined(), segment.is_reversed()); - self.display.draw_str(segment.get_content()); + .set_style(segment.is_dimmed(), segment.is_underlined(), segment.is_reversed())?; + self.display.draw_str(segment.get_content())?; } // reset style - self.display.color(DisplayColor::Normal, false); - self.display.set_style(false, false, false); - self.display.fill_end_of_line(); + self.display.color(DisplayColor::Normal, false)?; + self.display.set_style(false, false, false)?; + self.display.fill_end_of_line() } - fn draw_title(&mut self, show_help: bool) { - self.display.color(DisplayColor::Normal, false); - self.display.set_style(false, true, false); + fn draw_title(&mut self, show_help: bool) -> Result<()> { + self.display.color(DisplayColor::Normal, false)?; + self.display.set_style(false, true, false)?; let window_width = self.display.get_window_size().width(); let title_help_indicator_total_length = TITLE_HELP_INDICATOR_LENGTH + self.config.key_bindings.help.len(); if window_width >= TITLE_LENGTH { - self.display.draw_str(TITLE); + self.display.draw_str(TITLE)?; // only draw help if there is room if window_width > TITLE_LENGTH + title_help_indicator_total_length { if (window_width - TITLE_LENGTH - title_help_indicator_total_length) > 0 { let padding = " ".repeat(window_width - TITLE_LENGTH - title_help_indicator_total_length); - self.display.draw_str(padding.as_str()); + self.display.draw_str(padding.as_str())?; } if show_help { self.display - .draw_str(format!("Help: {}", self.config.key_bindings.help).as_str()); + .draw_str(format!("Help: {}", self.config.key_bindings.help).as_str())?; } else { let padding = " ".repeat(title_help_indicator_total_length); - self.display.draw_str(padding.as_str()); + self.display.draw_str(padding.as_str())?; } } else if (window_width - TITLE_LENGTH) > 0 { let padding = " ".repeat(window_width - TITLE_LENGTH); - self.display.draw_str(padding.as_str()); + self.display.draw_str(padding.as_str())?; } } else { - self.display.draw_str(TITLE_SHORT); + self.display.draw_str(TITLE_SHORT)?; if (window_width - TITLE_SHORT_LENGTH) > 0 { let padding = " ".repeat(window_width - TITLE_SHORT_LENGTH); - self.display.draw_str(padding.as_str()); + self.display.draw_str(padding.as_str())?; } } // reset style - self.display.color(DisplayColor::Normal, false); - self.display.set_style(false, false, false); + self.display.color(DisplayColor::Normal, false)?; + self.display.set_style(false, false, false) } } @@ -210,6 +210,7 @@ mod tests { ); let config = Config::new().unwrap(); let mut curses = Curses::new(); + curses.erase(); curses.resize_term(size.height().try_into().unwrap(), size.width().try_into().unwrap()); let input_handler = InputHandler::new(&config.key_bindings); let display = Display::new(input_handler, &mut curses, &config.theme); @@ -228,7 +229,7 @@ mod tests { fn render_empty() { view_module_test(&Size::new(20, 10), |mut test_context| { let view_data = ViewData::new(); - test_context.view.render(&view_data); + test_context.view.render(&view_data).unwrap(); TestContext::assert_output(&["~\n"; 10]); }); } @@ -238,7 +239,7 @@ mod tests { view_module_test(&Size::new(35, 10), |mut test_context| { let mut view_data = ViewData::new(); view_data.set_show_title(true); - test_context.view.render(&view_data); + test_context.view.render(&view_data).unwrap(); let mut expected = vec!["Git Interactive Rebase Tool "]; expected.extend(vec!["~\n"; 9]); TestContext::assert_output(&expected); @@ -250,7 +251,7 @@ mod tests { view_module_test(&Size::new(26, 10), |mut test_context| { let mut view_data = ViewData::new(); view_data.set_show_title(true); - test_context.view.render(&view_data); + test_context.view.render(&view_data).unwrap(); let mut expected = vec!["Git Rebase "]; expected.extend(vec!["~\n"; 9]); TestContext::assert_output(&expected); @@ -263,7 +264,7 @@ mod tests { let mut view_data = ViewData::new(); view_data.set_show_title(true); view_data.set_show_help(true); - test_context.view.render(&view_data); + test_context.view.render(&view_data).unwrap(); let mut expected = vec!["Git Interactive Rebase Tool Help: ?"]; expected.extend(vec!["~\n"; 9]); TestContext::assert_output(&expected); @@ -276,7 +277,7 @@ mod tests { let mut view_data = ViewData::new(); view_data.set_show_title(true); view_data.set_show_help(true); - test_context.view.render(&view_data); + test_context.view.render(&view_data).unwrap(); let mut expected = vec!["Git Interactive Rebase Tool "]; expected.extend(vec!["~\n"; 9]); TestContext::assert_output(&expected); @@ -287,7 +288,7 @@ mod tests { fn render_prompt() { view_module_test(&Size::new(35, 10), |mut test_context| { let view_data = ViewData::new_confirm("This is a prompt"); - test_context.view.render(&view_data); + test_context.view.render(&view_data).unwrap(); let expected = vec!["Git Interactive Rebase Tool ", "\nThis is a prompt (y/n)? "]; TestContext::assert_output(&expected); }); @@ -299,7 +300,7 @@ mod tests { let mut view_data = ViewData::new(); view_data.push_leading_line(ViewLine::from("This is a leading line")); view_data.set_view_size(30, 10); - test_context.view.render(&view_data); + test_context.view.render(&view_data).unwrap(); let mut expected = vec!["This is a leading line {HLINE| |30}"]; expected.extend(vec!["~\n"; 9]); TestContext::assert_output(&expected); @@ -312,7 +313,7 @@ mod tests { let mut view_data = ViewData::new(); view_data.push_line(ViewLine::from("This is a line")); view_data.set_view_size(30, 10); - test_context.view.render(&view_data); + test_context.view.render(&view_data).unwrap(); let mut expected = vec!["This is a line {HLINE| |30}"]; expected.extend(vec!["~\n"; 9]); TestContext::assert_output(&expected); @@ -325,7 +326,7 @@ mod tests { let mut view_data = ViewData::new(); view_data.push_trailing_line(ViewLine::from("This is a trailing line")); view_data.set_view_size(30, 10); - test_context.view.render(&view_data); + test_context.view.render(&view_data).unwrap(); let mut expected = vec!["~\n"; 9]; expected.push("This is a trailing line {HLINE| |30}"); TestContext::assert_output(&expected); @@ -340,7 +341,7 @@ mod tests { view_data.push_line(ViewLine::from("This is a line")); view_data.push_trailing_line(ViewLine::from("This is a trailing line")); view_data.set_view_size(30, 10); - test_context.view.render(&view_data); + test_context.view.render(&view_data).unwrap(); let mut expected = vec![ "This is a leading line {HLINE| |30}", "This is a line {HLINE| |30}", @@ -362,7 +363,7 @@ mod tests { view_data.push_line(ViewLine::from("This is line 4")); view_data.push_trailing_line(ViewLine::from("This is a trailing line")); view_data.set_view_size(30, 6); - test_context.view.render(&view_data); + test_context.view.render(&view_data).unwrap(); let expected = vec![ "This is a leading line {HLINE| |30}", "This is line 1 {HLINE| |30}", @@ -387,7 +388,7 @@ mod tests { view_data.push_line(ViewLine::from("This is line 5")); view_data.push_trailing_line(ViewLine::from("This is a trailing line")); view_data.set_view_size(30, 6); - test_context.view.render(&view_data); + test_context.view.render(&view_data).unwrap(); let expected = vec![ "This is a leading line {HLINE| |30}", "This is line 1 {HLINE| |30} ", |