• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

MitMaro / git-interactive-rebase-tool / 14340401715

08 Apr 2025 06:00PM UTC coverage: 95.488% (-1.9%) from 97.339%
14340401715

Pull #959

github

web-flow
Merge 755a26246 into aa2157af9
Pull Request #959: WIP: Move Diff to Thread

372 of 483 new or added lines in 31 files covered. (77.02%)

4 existing lines in 2 files now uncovered.

4741 of 4965 relevant lines covered (95.49%)

2.74 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.38
/src/modules/show_commit.rs
1
mod show_commit_state;
2
mod util;
3
mod view_builder;
4

5
#[cfg(test)]
6
mod tests;
7

8
use std::sync::Arc;
9

10
use anyhow::anyhow;
11
use captur::capture;
12
use parking_lot::Mutex;
13

14
use self::{
15
        show_commit_state::ShowCommitState,
16
        util::get_show_commit_help_lines,
17
        view_builder::{ViewBuilder, ViewBuilderOptions},
18
};
19
use crate::{
20
        application::AppData,
21
        components::help::Help,
22
        config::DiffShowWhitespaceSetting,
23
        diff,
24
        input::{Event, InputOptions, KeyBindings, StandardEvent},
25
        module::{Module, State},
26
        process::Results,
27
        select,
28
        todo_file::TodoFile,
29
        util::handle_view_data_scroll,
30
        view::{self, RenderContext, ViewData, ViewLine},
31
};
32

33
// TODO Remove `union` call when bitflags/bitflags#180 is resolved
34
const INPUT_OPTIONS: InputOptions = InputOptions::UNDO_REDO
35
        .union(InputOptions::MOVEMENT)
36
        .union(InputOptions::HELP);
37

38
pub(crate) struct ShowCommit {
39
        diff_state: diff::State,
40
        diff_view_data: ViewData,
41
        help: Help,
42
        overview_view_data: ViewData,
43
        state: ShowCommitState,
44
        view_state: view::State,
45
        todo_file: Arc<Mutex<TodoFile>>,
46
        view_builder: ViewBuilder,
47
}
48

49
impl Module for ShowCommit {
50
        fn activate(&mut self, _: State) -> Results {
1✔
51
                let mut results = Results::new();
1✔
52
                if let Some(selected_line) = self.todo_file.lock().get_selected_line() {
4✔
53
                        {
54
                                // skip loading commit data if the currently loaded commit has not changed, this retains
55
                                // position after returning to the list view or help
56
                                let diff = self.diff_state.diff();
2✔
57
                                if diff.read().commit().hash() == selected_line.get_hash() {
2✔
58
                                        return results;
1✔
59
                                }
60
                        }
61

62
                        self.overview_view_data.update_view_data(|updater| {
2✔
63
                                updater.clear();
1✔
64
                                updater.reset_scroll_position();
1✔
65
                        });
66

67
                        self.diff_view_data.update_view_data(|updater| {
2✔
68
                                updater.clear();
1✔
69
                                updater.reset_scroll_position();
1✔
70
                        });
71

72
                        results.load_diff(selected_line.get_hash())
1✔
73
                }
74
                else {
75
                        results.error_with_return(anyhow!("No valid commit to show"), State::List);
2✔
76
                }
77
                results
1✔
78
        }
79

80
        fn build_view_data(&mut self, context: &RenderContext) -> &ViewData {
2✔
81
                if self.help.is_active() {
2✔
82
                        return self.help.get_view_data();
1✔
83
                }
84

85
                let diff_arc = self.diff_state.diff();
2✔
86
                let diff = diff_arc.read();
4✔
87

88
                // There is a small race condition where sometimes the diff loader is still in the process
89
                // of cancelling the previous diff and still has that diff loaded. In that case, we want to
90
                // show a general loading diff.
91
                let todo_line = self.todo_file.lock();
4✔
92
                let selected_line = todo_line.get_selected_line().map(|l| l.get_hash()).unwrap_or("");
8✔
93
                if self.diff_state.is_cancelled() || selected_line == "" || selected_line != diff.commit().hash() {
4✔
NEW
94
                        self.overview_view_data.update_view_data(|updater| {
×
NEW
95
                                updater.clear();
×
NEW
96
                                updater.push_line(ViewLine::from("Loading Diff"));
×
97
                        });
98
                }
99

100
                let load_status = self.diff_state.load_status().read().clone();
5✔
101
                let state = &self.state;
3✔
102
                let view_builder = &mut self.view_builder;
3✔
103
                let is_full_width = context.is_full_width();
3✔
104

105
                match *state {
3✔
106
                        ShowCommitState::Overview => {
107
                                if self.overview_view_data.is_empty() {
1✔
108
                                        self.overview_view_data.update_view_data(|updater| {
3✔
109
                                                capture!(view_builder, diff);
110
                                                view_builder.build_view_data_for_overview(updater, &diff, load_status, is_full_width);
2✔
111
                                        });
112
                                }
113
                                &self.overview_view_data
2✔
114
                        },
115
                        ShowCommitState::Diff => {
116
                                if self.diff_view_data.is_empty() {
6✔
117
                                        self.diff_view_data.update_view_data(|updater| {
5✔
118
                                                capture!(view_builder, diff);
119
                                                view_builder.build_view_data_diff(updater, &diff, load_status, is_full_width);
1✔
120
                                        });
121
                                }
122
                                &self.diff_view_data
1✔
123
                        },
124
                }
125
        }
126

127
        fn input_options(&self) -> &InputOptions {
1✔
128
                select!(default & INPUT_OPTIONS, self.help.input_options())
3✔
129
        }
130

131
        fn read_event(&self, event: Event, key_bindings: &KeyBindings) -> Event {
2✔
132
                select!(
133
                        default {
134
                                let has_event = key_bindings.show_diff.contains(&event);
2✔
135
                                if has_event {
4✔
136
                                        Event::from(StandardEvent::ShowDiff)
1✔
137
                                }
138
                                else {
139
                                        event
2✔
140
                                }
141
                        },
142
                        self.help.read_event(event)
2✔
143
                )
144
        }
145

146
        fn handle_event(&mut self, event: Event) -> Results {
2✔
147
                select!(
148
                        default {
149
                                let mut results = Results::new();
3✔
150

151
                                let active_view_data = match self.state {
3✔
152
                                        ShowCommitState::Overview => &mut self.overview_view_data,
2✔
153
                                        ShowCommitState::Diff => &mut self.diff_view_data,
1✔
154
                                };
155

156
                                match event {
4✔
157
                                        Event::Standard(StandardEvent::ShowDiff) => {
158
                                                active_view_data.update_view_data(|updater| updater.clear());
5✔
159
                                                self.state = match self.state {
4✔
160
                                                        ShowCommitState::Overview => ShowCommitState::Diff,
1✔
161
                                                        ShowCommitState::Diff => ShowCommitState::Overview,
1✔
162
                                                }
163
                                        },
164
                                        Event::Standard(StandardEvent::DiffUpdate) => {
NEW
165
                                                self.diff_view_data.clear();
×
NEW
166
                                                self.overview_view_data.clear();
×
167
                                        }
168
                                        Event::Standard(StandardEvent::Help) => self.help.set_active(),
2✔
169
                                        Event::Key(_) => {
170
                                                active_view_data.update_view_data(|updater| updater.clear());
6✔
171
                                                if self.state == ShowCommitState::Diff {
3✔
172
                                                        self.state = ShowCommitState::Overview;
1✔
173
                                                }
174
                                                else {
175
                                                        results.cancel_diff();
1✔
176
                                                        results.state(State::List);
1✔
177
                                                }
178
                                        },
179
                                        Event::Resize(..) => active_view_data.update_view_data(|updater| updater.clear()),
4✔
180
                                        _ => {},
181
                                }
182
                                results
1✔
183
                        },
184
                        self.help.handle_event(event, &self.view_state),
3✔
185
                        handle_view_data_scroll(event, &self.view_state)
6✔
186
                )
187
        }
188
}
189

190
impl ShowCommit {
191
        pub(crate) fn new(app_data: &AppData) -> Self {
1✔
192
                let overview_view_data = ViewData::new(|updater| {
2✔
193
                        updater.set_show_title(true);
1✔
194
                        updater.set_show_help(true);
1✔
195
                });
196
                let diff_view_data = ViewData::new(|updater| {
2✔
197
                        updater.set_show_title(true);
1✔
198
                        updater.set_show_help(true);
1✔
199
                });
200
                let config = app_data.config();
2✔
201
                let view_builder_options = ViewBuilderOptions::new(
202
                        config.diff_tab_width as usize,
2✔
203
                        config.diff_tab_symbol.as_str(),
1✔
204
                        config.diff_space_symbol.as_str(),
1✔
205
                        config.diff_show_whitespace == DiffShowWhitespaceSetting::Both
2✔
206
                                || config.diff_show_whitespace == DiffShowWhitespaceSetting::Leading,
2✔
207
                        config.diff_show_whitespace == DiffShowWhitespaceSetting::Both
2✔
208
                                || config.diff_show_whitespace == DiffShowWhitespaceSetting::Trailing,
2✔
209
                );
210

211
                Self {
212
                        diff_state: app_data.diff_state(),
1✔
213
                        diff_view_data,
214
                        help: Help::new_from_keybindings(&get_show_commit_help_lines(&config.key_bindings)),
3✔
215
                        overview_view_data,
216
                        state: ShowCommitState::Overview,
217
                        view_state: app_data.view_state(),
1✔
218
                        todo_file: app_data.todo_file(),
2✔
219
                        view_builder: ViewBuilder::new(view_builder_options),
1✔
220
                }
221
        }
222
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc