Skip to content

Commit e96410d

Browse files
authored
Merge pull request #22 from MitMaro/module-refactor
Refactor into modules
2 parents 59c8a52 + c45dd80 commit e96410d

12 files changed

Lines changed: 996 additions & 485 deletions

.travis.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
language: rust
2+
rust:
3+
- stable
4+
- beta
5+
- nightly
6+
matrix:
7+
allow_failures:
8+
- rust: nightly
9+

src/action.rs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
2+
#[derive(PartialEq, Debug)]
3+
pub enum Action {
4+
Pick,
5+
Reword,
6+
Edit,
7+
Squash,
8+
Fixup,
9+
Drop
10+
}
11+
12+
pub fn action_from_str(s: &str) -> Result<Action, String> {
13+
match s {
14+
"pick" | "p" => Ok(Action::Pick),
15+
"reword" | "r" => Ok(Action::Reword),
16+
"edit" | "e" => Ok(Action::Edit),
17+
"squash" | "s" => Ok(Action::Squash),
18+
"fixup" | "f" => Ok(Action::Fixup),
19+
"drop" | "d" => Ok(Action::Drop),
20+
_ => Err(format!("Invalid action: {}", s))
21+
}
22+
}
23+
24+
pub fn action_to_str(action: &Action) -> String {
25+
String::from(match *action {
26+
Action::Pick => "pick",
27+
Action::Reword => "reword",
28+
Action::Edit => "edit",
29+
Action::Squash => "squash",
30+
Action::Fixup => "fixup",
31+
Action::Drop => "drop"
32+
})
33+
}
34+
35+
#[cfg(test)]
36+
mod tests {
37+
use super::{
38+
Action,
39+
action_from_str,
40+
action_to_str
41+
};
42+
43+
#[test]
44+
fn action_to_str_all() {
45+
assert_eq!(action_to_str(&Action::Pick), "pick");
46+
assert_eq!(action_to_str(&Action::Reword), "reword");
47+
assert_eq!(action_to_str(&Action::Edit), "edit");
48+
assert_eq!(action_to_str(&Action::Squash), "squash");
49+
assert_eq!(action_to_str(&Action::Fixup), "fixup");
50+
assert_eq!(action_to_str(&Action::Drop), "drop");
51+
}
52+
53+
#[test]
54+
fn action_from_str_all() {
55+
assert_eq!(action_from_str("pick"), Ok(Action::Pick));
56+
assert_eq!(action_from_str("p"), Ok(Action::Pick));
57+
assert_eq!(action_from_str("reword"), Ok(Action::Reword));
58+
assert_eq!(action_from_str("r"), Ok(Action::Reword));
59+
assert_eq!(action_from_str("edit"), Ok(Action::Edit));
60+
assert_eq!(action_from_str("e"), Ok(Action::Edit));
61+
assert_eq!(action_from_str("squash"), Ok(Action::Squash));
62+
assert_eq!(action_from_str("s"), Ok(Action::Squash));
63+
assert_eq!(action_from_str("fixup"), Ok(Action::Fixup));
64+
assert_eq!(action_from_str("f"), Ok(Action::Fixup));
65+
assert_eq!(action_from_str("drop"), Ok(Action::Drop));
66+
assert_eq!(action_from_str("d"), Ok(Action::Drop));
67+
}
68+
}
69+

src/application.rs

Lines changed: 304 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
1+
use action::Action;
2+
use git_interactive::GitInteractive;
3+
4+
use window::{
5+
Input,
6+
Window
7+
};
8+
9+
const EXIT_CODE_GOOD: i32 = 0;
10+
const EXIT_CODE_WRITE_ERROR: i32 = 8;
11+
12+
pub enum State {
13+
List,
14+
Help
15+
}
16+
17+
pub struct Application {
18+
pub exit_code: Option<i32>,
19+
window: Window,
20+
git_interactive: GitInteractive,
21+
state: State
22+
}
23+
24+
impl Application {
25+
pub fn new(git_interactive: GitInteractive, window: Window) -> Self {
26+
Application {
27+
git_interactive: git_interactive,
28+
window: window,
29+
exit_code: None,
30+
state: State::List
31+
}
32+
}
33+
34+
pub fn process_input(&mut self) {
35+
match self.state {
36+
State::List => self.process_list_input(),
37+
State::Help => self.process_help_input()
38+
}
39+
}
40+
41+
pub fn draw(&self) {
42+
match self.state {
43+
State::List => {
44+
self.window.draw(
45+
self.git_interactive.get_lines(),
46+
self.git_interactive.get_selected_line_index()
47+
);
48+
},
49+
State::Help => {
50+
self.window.draw_help();
51+
}
52+
}
53+
}
54+
55+
fn abort(&mut self) {
56+
self.git_interactive.clear();
57+
self.finish();
58+
}
59+
60+
fn finish(&mut self) {
61+
self.exit_code = Some(EXIT_CODE_GOOD);
62+
}
63+
64+
pub fn end(&mut self) -> Result<(), String>{
65+
self.window.end();
66+
match self.git_interactive.write_file() {
67+
Ok(_) => {},
68+
Err(msg) => {
69+
self.exit_code = Some(EXIT_CODE_WRITE_ERROR);
70+
return Err(msg)
71+
}
72+
}
73+
Ok(())
74+
}
75+
76+
fn process_help_input(&mut self) {
77+
self.window.window.getch();
78+
self.state = State::List;
79+
}
80+
81+
fn process_list_input(&mut self) {
82+
match self.window.window.getch() {
83+
Some(Input::Character(c)) if c == '?' => {
84+
self.state = State::Help;
85+
},
86+
Some(Input::Character(c))
87+
if (c == 'Q') || (c == 'q' && self.window.confirm("Are you sure you want to abort"))
88+
=> self.abort(),
89+
Some(Input::Character(c))
90+
if (c == 'W') || (c == 'w' && self.window.confirm("Are you sure you want to rebase"))
91+
=> self.finish(),
92+
Some(Input::Character(c))
93+
if c == 'p' => self.git_interactive.set_selected_line_action(Action::Pick),
94+
Some(Input::Character(c))
95+
if c == 'r' => self.git_interactive.set_selected_line_action(Action::Reword),
96+
Some(Input::Character(c))
97+
if c == 'e' => self.git_interactive.set_selected_line_action(Action::Edit),
98+
Some(Input::Character(c))
99+
if c == 's' => self.git_interactive.set_selected_line_action(Action::Squash),
100+
Some(Input::Character(c))
101+
if c == 'f' => self.git_interactive.set_selected_line_action(Action::Fixup),
102+
Some(Input::Character(c))
103+
if c == 'd' => self.git_interactive.set_selected_line_action(Action::Drop),
104+
Some(Input::Character(c)) if c == 'j' => {
105+
self.git_interactive.swap_selected_down();
106+
self.reset_top();
107+
},
108+
Some(Input::Character(c)) if c == 'k' => {
109+
self.git_interactive.swap_selected_up();
110+
self.reset_top();
111+
},
112+
Some(Input::KeyDown) => {
113+
self.git_interactive.move_cursor_down(1);
114+
self.reset_top();
115+
},
116+
Some(Input::KeyUp) => {
117+
self.git_interactive.move_cursor_up(1);
118+
self.reset_top();
119+
},
120+
Some(Input::KeyPPage) => {
121+
self.git_interactive.move_cursor_up(5);
122+
self.reset_top();
123+
},
124+
Some(Input::KeyNPage) => {
125+
self.git_interactive.move_cursor_down(5);
126+
self.reset_top();
127+
},
128+
Some(Input::KeyResize) => self.reset_top(),
129+
_ => {}
130+
}
131+
()
132+
}
133+
134+
fn reset_top(&mut self) {
135+
self.window.set_top(
136+
self.git_interactive.get_lines().len(),
137+
*self.git_interactive.get_selected_line_index()
138+
)
139+
}
140+
}
141+
142+
143+
#[cfg(test)]
144+
mod tests {
145+
use super::{
146+
Application,
147+
};
148+
use git_interactive::GitInteractive;
149+
use window::{
150+
Window,
151+
Input
152+
};
153+
use action::Action;
154+
155+
#[test]
156+
fn application_read_all_actions() {
157+
let gi = GitInteractive::new_from_filepath("test/git-rebase-todo-all-actions.in").unwrap();
158+
let window = Window::new();
159+
let mut app = Application::new(gi, window);
160+
assert_eq!(app.git_interactive.get_lines().len(), 12);
161+
}
162+
163+
#[test]
164+
fn application_scroll_basic() {
165+
let gi = GitInteractive::new_from_filepath("test/git-rebase-todo-long.in").unwrap();
166+
let window = Window::new();
167+
let mut app = Application::new(gi, window);
168+
app.window.window.next_char = Input::KeyDown;
169+
app.process_input();
170+
assert_eq!(*app.git_interactive.get_selected_line_index(), 2);
171+
app.window.window.next_char = Input::KeyUp;
172+
app.process_input();
173+
assert_eq!(*app.git_interactive.get_selected_line_index(), 1);
174+
app.window.window.next_char = Input::KeyNPage;
175+
app.process_input();
176+
assert_eq!(*app.git_interactive.get_selected_line_index(), 6);
177+
app.window.window.next_char = Input::KeyPPage;
178+
app.process_input();
179+
assert_eq!(*app.git_interactive.get_selected_line_index(), 1);
180+
}
181+
182+
#[test]
183+
fn application_scroll_limits() {
184+
let gi = GitInteractive::new_from_filepath("test/git-rebase-todo-short.in").unwrap();
185+
let window = Window::new();
186+
let mut app = Application::new(gi, window);
187+
app.window.window.next_char = Input::KeyUp;
188+
app.process_input();
189+
app.process_input();
190+
app.window.window.next_char = Input::KeyPPage;
191+
app.process_input();
192+
assert_eq!(*app.git_interactive.get_selected_line_index(), 1);
193+
app.window.window.next_char = Input::KeyDown;
194+
app.process_input();
195+
app.process_input();
196+
app.process_input();
197+
app.process_input();
198+
app.process_input();
199+
app.window.window.next_char = Input::KeyNPage;
200+
app.process_input();
201+
assert_eq!(*app.git_interactive.get_selected_line_index(), 3);
202+
}
203+
204+
#[test]
205+
fn application_set_pick() {
206+
let gi = GitInteractive::new_from_filepath("test/git-rebase-todo-all-actions.in").unwrap();
207+
let window = Window::new();
208+
let mut app = Application::new(gi, window);
209+
// first item is already pick
210+
app.window.window.next_char = Input::KeyDown;
211+
app.process_input();
212+
app.window.window.next_char = Input::Character('p');
213+
app.process_input();
214+
assert_eq!(*app.git_interactive.get_lines()[1].get_action(), Action::Pick);
215+
}
216+
217+
#[test]
218+
fn application_set_reword() {
219+
let gi = GitInteractive::new_from_filepath("test/git-rebase-todo-all-actions.in").unwrap();
220+
let window = Window::new();
221+
let mut app = Application::new(gi, window);
222+
app.window.window.next_char = Input::Character('r');
223+
app.process_input();
224+
assert_eq!(*app.git_interactive.get_lines()[0].get_action(), Action::Reword);
225+
}
226+
227+
#[test]
228+
fn application_set_edit() {
229+
let gi = GitInteractive::new_from_filepath("test/git-rebase-todo-all-actions.in").unwrap();
230+
let window = Window::new();
231+
let mut app = Application::new(gi, window);
232+
app.window.window.next_char = Input::Character('e');
233+
app.process_input();
234+
assert_eq!(*app.git_interactive.get_lines()[0].get_action(), Action::Edit);
235+
}
236+
237+
#[test]
238+
fn application_set_squash() {
239+
let gi = GitInteractive::new_from_filepath("test/git-rebase-todo-all-actions.in").unwrap();
240+
let window = Window::new();
241+
let mut app = Application::new(gi, window);
242+
app.window.window.next_char = Input::Character('s');
243+
app.process_input();
244+
assert_eq!(*app.git_interactive.get_lines()[0].get_action(), Action::Squash);
245+
}
246+
247+
#[test]
248+
fn application_set_drop() {
249+
let gi = GitInteractive::new_from_filepath("test/git-rebase-todo-all-actions.in").unwrap();
250+
let window = Window::new();
251+
let mut app = Application::new(gi, window);
252+
app.window.window.next_char = Input::Character('d');
253+
app.process_input();
254+
assert_eq!(*app.git_interactive.get_lines()[0].get_action(), Action::Drop);
255+
}
256+
257+
#[test]
258+
fn application_swap_down() {
259+
let gi = GitInteractive::new_from_filepath("test/git-rebase-todo-all-actions.in").unwrap();
260+
let window = Window::new();
261+
let mut app = Application::new(gi, window);
262+
app.window.window.next_char = Input::Character('j');
263+
app.process_input();
264+
assert_eq!(*app.git_interactive.get_lines()[0].get_hash(), "bbb");
265+
assert_eq!(*app.git_interactive.get_lines()[1].get_hash(), "aaa");
266+
assert_eq!(*app.git_interactive.get_selected_line_index(), 2);
267+
}
268+
269+
#[test]
270+
fn application_swap_up() {
271+
let gi = GitInteractive::new_from_filepath("test/git-rebase-todo-all-actions.in").unwrap();
272+
let window = Window::new();
273+
let mut app = Application::new(gi, window);
274+
app.window.window.next_char = Input::KeyDown;
275+
app.process_input();
276+
app.window.window.next_char = Input::Character('k');
277+
app.process_input();
278+
assert_eq!(*app.git_interactive.get_lines()[0].get_hash(), "bbb");
279+
assert_eq!(*app.git_interactive.get_lines()[1].get_hash(), "aaa");
280+
assert_eq!(*app.git_interactive.get_selected_line_index(), 1);
281+
}
282+
283+
#[test]
284+
fn application_quit() {
285+
let gi = GitInteractive::new_from_filepath("test/git-rebase-todo-all-actions.in").unwrap();
286+
let window = Window::new();
287+
let mut app = Application::new(gi, window);
288+
app.window.window.next_char = Input::Character('Q');
289+
app.process_input();
290+
assert_eq!(app.exit_code.unwrap(), 0);
291+
assert!(app.git_interactive.get_lines().is_empty());
292+
}
293+
294+
#[test]
295+
fn application_finish() {
296+
let gi = GitInteractive::new_from_filepath("test/git-rebase-todo-all-actions.in").unwrap();
297+
let window = Window::new();
298+
let mut app = Application::new(gi, window);
299+
app.window.window.next_char = Input::Character('W');
300+
app.process_input();
301+
assert_eq!(app.exit_code.unwrap(), 0);
302+
assert!(!app.git_interactive.get_lines().is_empty());
303+
}
304+
}

0 commit comments

Comments
 (0)