girt-core 2.2.1

Core modules for git-interactive-rebase-tool
Documentation
use captur::capture;
use display::DisplayColor;
use input::InputOptions;
use lazy_static::lazy_static;
use todo_file::TodoFile;
use view::{LineSegment, RenderContext, ViewData, ViewLine, ViewSender};

use crate::{
	events::Event,
	module::{Module, ProcessResult, State},
	util::handle_view_data_scroll,
};

lazy_static! {
	pub static ref INPUT_OPTIONS: InputOptions = InputOptions::RESIZE | InputOptions::MOVEMENT;
}

pub(crate) struct Error {
	return_state: State,
	view_data: ViewData,
}

impl Module for Error {
	fn activate(&mut self, _: &TodoFile, previous_state: State) -> ProcessResult {
		self.return_state = previous_state;
		ProcessResult::new()
	}

	fn build_view_data(&mut self, _: &RenderContext, _: &TodoFile) -> &ViewData {
		&self.view_data
	}

	fn input_options(&self) -> &InputOptions {
		&INPUT_OPTIONS
	}

	fn handle_event(&mut self, event: Event, view_sender: &ViewSender, _: &mut TodoFile) -> ProcessResult {
		let mut result = ProcessResult::from(event);
		if handle_view_data_scroll(event, view_sender).is_none() {
			if let Event::Key(_) = event {
				result = result.state(self.return_state);
			}
		}
		result
	}

	fn handle_error(&mut self, error: &anyhow::Error) {
		self.view_data.update_view_data(|updater| {
			capture!(error);
			updater.clear();
			for cause in error.chain() {
				let error_text = format!("{:#}", cause);
				for err in error_text.split('\n') {
					updater.push_line(ViewLine::from(err));
				}
			}
			updater.push_trailing_line(ViewLine::from(LineSegment::new_with_color(
				"Press any key to continue",
				DisplayColor::IndicatorColor,
			)));
		});
	}
}

impl Error {
	pub(crate) fn new() -> Self {
		Self {
			return_state: State::List,
			view_data: ViewData::new(|updater| {
				updater.set_show_title(true);
				updater.set_retain_scroll_position(false);
			}),
		}
	}
}

#[cfg(test)]
mod tests {
	use anyhow::anyhow;
	use input::StandardEvent;
	use view::assert_rendered_output;

	use super::*;
	use crate::{assert_process_result, testutil::module_test};

	#[test]
	fn simple_error() {
		module_test(&[], &[], |test_context| {
			let mut module = Error::new();
			module.handle_error(&anyhow!("Test Error"));
			let view_data = test_context.build_view_data(&mut module);
			assert_rendered_output!(
				view_data,
				"{TITLE}",
				"{BODY}",
				"{Normal}Test Error",
				"{TRAILING}",
				"{IndicatorColor}Press any key to continue"
			);
		});
	}

	#[test]
	fn error_with_contest() {
		module_test(&[], &[], |test_context| {
			let mut module = Error::new();
			module.handle_error(&anyhow!("Test Error").context("Context"));
			let view_data = test_context.build_view_data(&mut module);
			assert_rendered_output!(
				view_data,
				"{TITLE}",
				"{BODY}",
				"{Normal}Context",
				"{Normal}Test Error",
				"{TRAILING}",
				"{IndicatorColor}Press any key to continue"
			);
		});
	}

	#[test]
	fn error_with_newlines() {
		module_test(&[], &[], |test_context| {
			let mut module = Error::new();
			module.handle_error(&anyhow!("Test\nError").context("With\nContext"));
			let view_data = test_context.build_view_data(&mut module);
			assert_rendered_output!(
				view_data,
				"{TITLE}",
				"{BODY}",
				"{Normal}With",
				"{Normal}Context",
				"{Normal}Test",
				"{Normal}Error",
				"{TRAILING}",
				"{IndicatorColor}Press any key to continue"
			);
		});
	}

	#[test]
	fn return_state() {
		module_test(&[], &[Event::from('a')], |mut test_context| {
			let mut module = Error::new();
			let _ = test_context.activate(&mut module, State::ConfirmRebase);
			module.handle_error(&anyhow!("Test Error"));
			assert_process_result!(
				test_context.handle_event(&mut module),
				event = Event::from('a'),
				state = State::ConfirmRebase
			);
		});
	}

	#[test]
	fn resize() {
		module_test(&[], &[Event::Resize(100, 100)], |mut test_context| {
			let mut module = Error::new();
			let _ = test_context.activate(&mut module, State::ConfirmRebase);
			module.handle_error(&anyhow!("Test Error"));
			assert_process_result!(test_context.handle_event(&mut module), event = Event::Resize(100, 100));
		});
	}

	#[test]
	fn scroll_events() {
		module_test(
			&[],
			&[
				Event::from(StandardEvent::ScrollLeft),
				Event::from(StandardEvent::ScrollRight),
				Event::from(StandardEvent::ScrollDown),
				Event::from(StandardEvent::ScrollUp),
				Event::from(StandardEvent::ScrollJumpDown),
				Event::from(StandardEvent::ScrollJumpUp),
			],
			|mut test_context| {
				let mut module = Error::new();
				let _ = test_context.activate(&mut module, State::ConfirmRebase);
				module.handle_error(&anyhow!("Test Error"));
				assert_process_result!(
					test_context.handle_event(&mut module),
					event = Event::from(StandardEvent::ScrollLeft)
				);
				assert_process_result!(
					test_context.handle_event(&mut module),
					event = Event::from(StandardEvent::ScrollRight)
				);
				assert_process_result!(
					test_context.handle_event(&mut module),
					event = Event::from(StandardEvent::ScrollDown)
				);
				assert_process_result!(
					test_context.handle_event(&mut module),
					event = Event::from(StandardEvent::ScrollUp)
				);
				assert_process_result!(
					test_context.handle_event(&mut module),
					event = Event::from(StandardEvent::ScrollJumpDown)
				);
				assert_process_result!(
					test_context.handle_event(&mut module),
					event = Event::from(StandardEvent::ScrollJumpUp)
				);
			},
		);
	}
}