diff_tool/app/
mod.rs

1pub mod state;
2
3use self::state::{DiffState, RunningState};
4use crate::{
5    services::{config::Config, git::Diff, logger::Logs},
6    update::{keys::Key, message::Message},
7};
8use anyhow::Result;
9use crossterm::event::{self, Event, KeyEventKind};
10use ratatui::widgets::ListState;
11use std::{cell::RefCell, cmp, time::Duration};
12
13#[derive(Debug)]
14pub struct App {
15    running_state: RunningState,
16    // TODO: Model could do with a colours / styling section that can load a config for theming
17    config: Config,
18    diff: Diff,
19    diff_state: DiffState,
20    logs: Logs,
21    console_state: RefCell<ListState>,
22    /// Default value is 250 millis
23    tick_rate: Duration,
24}
25
26impl App {
27    pub fn new(logs: Logs) -> Self {
28        let mut new = Self {
29            running_state: Default::default(),
30            // TODO: This should be handled with a default config probably
31            config: Config::new().expect("A config"),
32            diff: Default::default(),
33            diff_state: Default::default(),
34            logs,
35            console_state: Default::default(),
36            tick_rate: Duration::from_millis(250),
37        };
38
39        new.handle_console();
40
41        return new;
42    }
43
44    pub fn console_state(&self) -> &RefCell<ListState> {
45        &self.console_state
46    }
47
48    pub fn handle_console(&mut self) {
49        let console_length = self.console().len();
50        let console_state_index = cmp::max(1, console_length) - 1;
51
52        self.console_state
53            .borrow_mut()
54            .select(Some(console_state_index));
55    }
56
57    pub fn update(&mut self, msg: Message) -> Option<Message> {
58        log::info!("{}", msg);
59        self.handle_console();
60
61        match msg {
62            Message::PrevRow => {
63                self.previous_row();
64            }
65            Message::NextRow => {
66                self.next_row();
67            }
68            Message::LastRow => {
69                self.go_to_last_row();
70            }
71            Message::FirstRow => {
72                self.diff_state().reset_row_state();
73            }
74            Message::Quit => {
75                // Handle some exit stuff
76                self.quit();
77            }
78        }
79
80        None
81    }
82
83    pub fn handle_event(&self) -> Result<Option<Message>> {
84        if event::poll(self.tick_rate)? {
85            if let Event::Key(key) = event::read()? {
86                if key.kind == KeyEventKind::Press {
87                    // Converts Crossterm::Event::Key into our update::Key
88                    return Ok(self.handle_key(key.into()));
89                }
90            }
91        }
92        Ok(None)
93    }
94
95    fn handle_key(&self, key: Key) -> Option<Message> {
96        let key_string = key.to_string();
97        let key = self.config.keymap().get(&key_string);
98        key.cloned()
99    }
100
101    pub fn console(&self) -> Vec<String> {
102        return self.logs.lock().unwrap().clone();
103    }
104
105    pub fn config(&self) -> &Config {
106        &self.config
107    }
108
109    pub fn diff_state(&self) -> &DiffState {
110        &self.diff_state
111    }
112
113    pub fn diff(&self) -> Option<&Diff> {
114        if self.diff.old_diff().len() != 0 && self.diff.current_diff().len() != 0 {
115            return Some(&self.diff);
116        }
117        None
118    }
119
120    pub fn set_diff(&mut self, diff_string: &str) {
121        self.diff = Diff::parse_diff(diff_string)
122    }
123
124    pub fn running_state(&self) -> &RunningState {
125        &self.running_state
126    }
127
128    fn quit(&mut self) {
129        self.running_state = RunningState::Done
130    }
131
132    fn go_to_last_row(&self) {
133        let last_row = self.diff.longest_diff_len();
134        self.diff_state
135            .old_diff()
136            .borrow_mut()
137            .select(Some(last_row));
138        self.diff_state
139            .current_diff()
140            .borrow_mut()
141            .select(Some(last_row));
142    }
143
144    fn next_row(&self) {
145        let old_diff_row_index = match self.diff_state.old_diff().borrow().selected() {
146            Some(i) => {
147                if i >= self.diff.old_diff().len() - 1 {
148                    0
149                } else {
150                    i + 1
151                }
152            }
153            None => 0,
154        };
155
156        let current_diff_row_index = match self.diff_state.current_diff().borrow().selected() {
157            Some(j) => {
158                if j >= self.diff.current_diff().len() - 1 {
159                    0
160                } else {
161                    j + 1
162                }
163            }
164            None => 0,
165        };
166
167        self.diff_state
168            .old_diff()
169            .borrow_mut()
170            .select(Some(old_diff_row_index));
171        self.diff_state
172            .current_diff()
173            .borrow_mut()
174            .select(Some(current_diff_row_index));
175    }
176
177    fn previous_row(&self) {
178        let old_diff_row_index = match self.diff_state.old_diff().borrow().selected() {
179            Some(i) => {
180                if i == 0 {
181                    self.diff.old_diff().len() - 1
182                } else {
183                    i - 1
184                }
185            }
186            None => 0,
187        };
188
189        let current_diff_row_index = match self.diff_state.current_diff().borrow().selected() {
190            Some(j) => {
191                if j == 0 {
192                    self.diff.current_diff().len() - 1
193                } else {
194                    j - 1
195                }
196            }
197            None => 0,
198        };
199
200        self.diff_state
201            .old_diff()
202            .borrow_mut()
203            .select(Some(old_diff_row_index));
204        self.diff_state
205            .current_diff()
206            .borrow_mut()
207            .select(Some(current_diff_row_index));
208    }
209}