summaryrefslogtreecommitdiffstats
path: root/src/insert/mod.rs
blob: e78f3d4d96361f2318e7ca4d3ad8357c167dea64 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
mod insert_state;
mod line_type;

#[cfg(all(unix, test))]
mod tests;

use crate::{
	components::{choice::Choice, edit::Edit},
	input::EventHandler,
	insert::{insert_state::InsertState, line_type::LineType},
	process::{Module, ProcessResult, State},
	todo_file::{Line, TodoFile},
	view::{RenderContext, ViewData, ViewLine, ViewSender},
};

pub struct Insert {
	action_choices: Choice<LineType>,
	edit: Edit,
	line_type: LineType,
	state: InsertState,
}

impl Module for Insert {
	fn activate(&mut self, _: &TodoFile, _: State) -> ProcessResult {
		self.state = InsertState::Prompt;
		self.edit.clear();
		ProcessResult::new()
	}

	fn build_view_data(&mut self, _: &RenderContext, _: &TodoFile) -> &ViewData {
		match self.state {
			InsertState::Prompt => self.action_choices.get_view_data(),
			InsertState::Edit => self.edit.get_view_data(),
		}
	}

	fn handle_events(
		&mut self,
		event_handler: &EventHandler,
		view_sender: &ViewSender,
		rebase_todo: &mut TodoFile,
	) -> ProcessResult {
		match self.state {
			InsertState::Prompt => {
				let (choice, event) = self.action_choices.handle_event(event_handler, view_sender);
				let mut result = ProcessResult::from(event);
				if let Some(action) = choice {
					if action == &LineType::Cancel {
						result = result.state(State::List);
					}
					else {
						self.line_type = action.clone();
						self.edit.set_label(format!("{} ", action.to_string()).as_str());
						self.state = InsertState::Edit;
					}
				}
				result
			},
			InsertState::Edit => {
				let mut result = ProcessResult::from(self.edit.handle_event(event_handler));
				if self.edit.is_finished() {
					let content = self.edit.get_content();
					result = result.state(State::List);
					if !content.is_empty() {
						let line = match self.line_type {
							LineType::Exec => Line::new_exec(content.as_str()),
							LineType::Pick => Line::new_pick(content.as_str()),
							LineType::Label => Line::new_label(content.as_str()),
							LineType::Reset => Line::new_reset(content.as_str()),
							LineType::Merge => Line::new_merge(content.as_str()),
							// this should exit in the prompt state and never get here
							LineType::Cancel => unreachable!(),
						};
						let new_line_index = rebase_todo.get_selected_line_index() + 1;
						rebase_todo.add_line(new_line_index, line);
						rebase_todo.set_selected_line_index(new_line_index);
					}
				}
				result
			},
		}
	}
}

impl Insert {
	pub(crate) fn new() -> Self {
		let mut edit = Edit::new();
		edit.set_description("Enter contents of the new line. Empty content cancels creation of a new line.");

		let mut action_choices = Choice::new(vec![
			(LineType::Exec, 'e', String::from("exec <command>")),
			(LineType::Pick, 'p', String::from("pick <hash>")),
			(LineType::Label, 'l', String::from("label <label>")),
			(LineType::Reset, 'r', String::from("reset <label>")),
			(
				LineType::Merge,
				'm',
				String::from("merge [-C <commit> | -c <commit>] <label> [# <oneline>]"),
			),
			(LineType::Cancel, 'q', String::from("Cancel add line")),
		]);
		action_choices.set_prompt(vec![ViewLine::from("Select the type of line to insert:")]);

		Self {
			state: InsertState::Prompt,
			edit,
			action_choices,
			line_type: LineType::Exec,
		}
	}
}