Skip to content

Commit 29c9295

Browse files
committed
WIP
1 parent bd01b09 commit 29c9295

File tree

11 files changed

+142
-124
lines changed

11 files changed

+142
-124
lines changed

src/application.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ use crate::{
1111
Args,
1212
Exit,
1313
config::{Config, DiffIgnoreWhitespaceSetting},
14-
diff,
14+
diff::{self, CommitDiffLoader, CommitDiffLoaderOptions},
1515
display::Display,
16-
git::{CommitDiffLoader, CommitDiffLoaderOptions, ConfigLoader, open_repository_from_env},
16+
git::{ConfigLoader, open_repository_from_env},
1717
help::build_help,
1818
input::{Event, EventHandler, EventReaderFn, KeyBindings, StandardEvent},
1919
module::{self, ExitStatus, ModuleHandler, State},

src/diff.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
11
mod action;
2+
mod commit_diff;
3+
mod commit_diff_loader;
4+
mod commit_diff_loader_options;
25
mod state;
36
mod thread;
47
mod update_handler;
58

6-
pub(crate) use self::{action::Action, state::State, thread::Thread, update_handler::UpdateHandlerFn};
9+
pub(crate) use self::{
10+
action::Action,
11+
commit_diff::CommitDiff,
12+
commit_diff_loader::CommitDiffLoader,
13+
commit_diff_loader_options::CommitDiffLoaderOptions,
14+
state::{LoadStatus, State},
15+
thread::Thread,
16+
update_handler::UpdateHandlerFn,
17+
};

src/git/commit_diff.rs renamed to src/diff/commit_diff.rs

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,8 @@
11
use crate::git::{Commit, FileStatus};
22

3-
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
4-
pub(crate) enum LoadedStatus {
5-
New,
6-
StartQuickDiff,
7-
QuickDiff(usize, usize),
8-
CompleteQuickDiff,
9-
Diff(usize, usize),
10-
DiffComplete,
11-
Canceled,
12-
}
13-
143
/// Represents a commit with a diff
154
#[derive(Debug)]
165
pub(crate) struct CommitDiff {
17-
loaded_status: LoadedStatus,
186
commit: Commit,
197
parent: Option<Commit>,
208
file_statuses: Vec<FileStatus>,
@@ -33,7 +21,6 @@ impl CommitDiff {
3321
number_deletions: usize,
3422
) -> Self {
3523
CommitDiff {
36-
loaded_status: LoadedStatus::New,
3724
commit,
3825
parent,
3926
file_statuses,
@@ -80,14 +67,8 @@ impl CommitDiff {
8067
self.number_deletions
8168
}
8269

83-
#[must_use]
84-
pub(crate) fn status(&self) -> LoadedStatus {
85-
self.loaded_status
86-
}
87-
8870
/// Reset the diff back to an empty state
8971
pub(crate) fn reset(&mut self, commit: Commit, parent: Option<Commit>) {
90-
self.loaded_status = LoadedStatus::New;
9172
self.commit = commit;
9273
self.parent = parent;
9374
self.file_statuses.clear();
@@ -109,10 +90,6 @@ impl CommitDiff {
10990
self.number_insertions = number_insertions;
11091
self.number_deletions = number_deletions;
11192
}
112-
113-
pub(crate) fn update_status(&mut self, status: LoadedStatus) {
114-
self.loaded_status = status;
115-
}
11693
}
11794

11895
#[cfg(test)]

src/git/commit_diff_loader.rs renamed to src/diff/commit_diff_loader.rs

Lines changed: 50 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,25 @@ use std::{
88
use git2::{Diff, DiffFindOptions, DiffOptions, Repository};
99
use parking_lot::{Mutex, RwLock};
1010

11-
use crate::git::{
12-
Commit,
13-
CommitDiff,
14-
CommitDiffLoaderOptions,
15-
Delta,
16-
DiffLine,
17-
FileMode,
18-
FileStatus,
19-
FileStatusBuilder,
20-
GitError,
21-
Status,
22-
commit_diff::LoadedStatus,
11+
use crate::{
12+
diff::{CommitDiff, CommitDiffLoaderOptions, LoadStatus},
13+
git::{Commit, Delta, DiffLine, FileMode, FileStatus, FileStatusBuilder, GitError, Status},
2314
};
2415

2516
static UNKNOWN_PATH: LazyLock<PathBuf> = LazyLock::new(|| PathBuf::from("unknown"));
26-
const LONG_DIFF_TIME: Duration = Duration::from_millis(100);
2717

28-
pub(crate) trait UpdateHandlerFn: Fn() -> bool + Sync + Send {}
18+
pub(crate) trait DiffUpdateHandlerFn: Fn(LoadStatus) -> bool + Sync + Send {}
2919

30-
impl<FN: Fn() -> bool + Sync + Send> UpdateHandlerFn for FN {}
20+
impl<FN: Fn(LoadStatus) -> bool + Sync + Send> DiffUpdateHandlerFn for FN {}
21+
22+
fn create_status_update(quick: bool, processed_files: usize, total_files: usize) -> LoadStatus {
23+
if quick {
24+
LoadStatus::QuickDiff(processed_files, total_files)
25+
}
26+
else {
27+
LoadStatus::Diff(processed_files, total_files)
28+
}
29+
}
3130

3231
pub(crate) struct CommitDiffLoader {
3332
config: CommitDiffLoaderOptions,
@@ -91,7 +90,7 @@ impl CommitDiffLoader {
9190
fn diff<'r>(
9291
repository: &'r Repository,
9392
config: &CommitDiffLoaderOptions,
94-
commit: &git2::Commit,
93+
commit: &git2::Commit<'_>,
9594
diff_options: &mut DiffOptions,
9695
) -> Result<Diff<'r>, GitError> {
9796
_ = diff_options
@@ -118,12 +117,13 @@ impl CommitDiffLoader {
118117
.map_err(|e| GitError::DiffLoad { cause: e })
119118
}
120119

121-
pub(crate) fn load_diff(&mut self, hash: &str, update_notifier: impl UpdateHandlerFn) -> Result<(), GitError> {
122-
let mut commit_diff = self.commit_diff.write();
123-
commit_diff.reset(self.find_commit(hash)?, self.find_first_parent(hash)?);
124-
drop(commit_diff);
125-
if update_notifier() {
126-
return Ok(());
120+
pub(crate) fn load_diff(&mut self, hash: &str, update_notifier: impl DiffUpdateHandlerFn) -> Result<(), GitError> {
121+
{
122+
let mut commit_diff = self.commit_diff.write();
123+
commit_diff.reset(self.find_commit(hash)?, self.find_first_parent(hash)?);
124+
if update_notifier(LoadStatus::New) {
125+
return Ok(());
126+
}
127127
}
128128

129129
// TODO, duplicated with find_commit function
@@ -144,20 +144,23 @@ impl CommitDiffLoader {
144144

145145
let stats = diff.stats().map_err(|e| GitError::DiffLoad { cause: e })?;
146146

147-
std::thread::sleep(std::time::Duration::from_millis(3_000));
148-
// when a diff contains a lot of track files, collecting the diff information can take upwards
149-
// of a minute. This performs a quicker diff, that does not detect copies and renames against
150-
// unmodified files.
147+
// std::thread::sleep(std::time::Duration::from_millis(3_000));
148+
// when a diff contains a lot of untracked files, collecting the diff information can take
149+
// upwards of a minute. This performs a quicker diff, that does not detect copies and
150+
// renames against unmodified files.
151151
if self.config.copies && stats.files_changed() > 1 {
152152
// self.config.quick_diff_threshold {
153-
let mut diff_options = DiffOptions::new();
154-
let quick_diff = Self::diff(&self.repository, &self.config, &commit, &mut diff_options)?;
155-
self.collect(&quick_diff, LoadedStatus::Partial)?;
156-
if update_notifier() {
153+
self.collect(
154+
&Self::diff(&self.repository, &self.config, &commit, &mut DiffOptions::new())?,
155+
&update_notifier,
156+
true,
157+
)?;
158+
159+
if update_notifier(LoadStatus::CompleteQuickDiff) {
157160
return Ok(());
158161
}
159162
}
160-
std::thread::sleep(std::time::Duration::from_millis(3_000));
163+
// std::thread::sleep(std::time::Duration::from_millis(3_000));
161164

162165
let mut diff_find_options = DiffFindOptions::new();
163166
_ = diff_find_options
@@ -170,9 +173,10 @@ impl CommitDiffLoader {
170173

171174
diff.find_similar(Some(&mut diff_find_options))
172175
.map_err(|e| GitError::DiffLoad { cause: e })?;
173-
self.collect(&diff, LoadedStatus::Complete)?;
176+
self.collect(&diff, &update_notifier, false)?;
174177

175-
if update_notifier() {
178+
if update_notifier(LoadStatus::DiffComplete) {
179+
_ = update_notifier(LoadStatus::Canceled);
176180
return Ok(());
177181
}
178182
Ok(())
@@ -183,7 +187,8 @@ impl CommitDiffLoader {
183187
pub(crate) fn collect(
184188
&self,
185189
diff: &Diff<'_>,
186-
update_handler: UpdateHandlerFn,
190+
update_handler: &impl DiffUpdateHandlerFn,
191+
quick: bool,
187192
) -> Result<(), GitError> {
188193
let file_stats_builder = Mutex::new(FileStatusBuilder::new());
189194
let mut unmodified_file_count: usize = 0;
@@ -192,6 +197,11 @@ impl CommitDiffLoader {
192197
let stats = diff.stats().map_err(|e| GitError::DiffLoad { cause: e })?;
193198
let total_files_changed = stats.files_changed();
194199

200+
if update_handler(create_status_update(quick, 0, total_files_changed)) {
201+
return Ok(());
202+
}
203+
let mut time = Instant::now();
204+
195205
let collect_result = diff.foreach(
196206
&mut |diff_delta, _| {
197207
change_count += 1;
@@ -200,11 +210,10 @@ impl CommitDiffLoader {
200210
unmodified_file_count += 1;
201211
return true;
202212
}
203-
if change_count % 10 == 0 {
204-
let mut commit_diff = self.commit_diff.write();
205-
commit_diff.update_status(LoadedStatus::Partial(change_count, total_files_changed))
206-
// early exit
207-
if update_handler() {
213+
if time.elapsed() > Duration::from_millis(10) {
214+
time = Instant::now();
215+
// std::thread::sleep(std::time::Duration::from_millis(500));
216+
if update_handler(create_status_update(quick, change_count, total_files_changed)) {
208217
return false;
209218
}
210219
}
@@ -247,23 +256,16 @@ impl CommitDiffLoader {
247256

248257
// error caused by early return
249258
if collect_result.is_err() {
250-
commit_diff.update_status(LoadedStatus::Canceled);
251-
update_handler();
259+
_ = update_handler(LoadStatus::Canceled);
252260
return Ok(());
253261
}
254262

255263
let number_files_changed = total_files_changed - unmodified_file_count;
256264
let number_insertions = stats.insertions();
257265
let number_deletions = stats.deletions();
258266

259-
eprintln!("Changes: {} {}", change_count, stats.files_changed());
260267
let fsb = file_stats_builder.into_inner();
261-
commit_diff.update(
262-
fsb.build(),
263-
number_files_changed,
264-
number_insertions,
265-
number_deletions,
266-
);
268+
commit_diff.update(fsb.build(), number_files_changed, number_insertions, number_deletions);
267269
Ok(())
268270
}
269271
}

src/diff/state.rs

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,26 @@
1-
use std::{
2-
sync::{
3-
Arc,
4-
atomic::{AtomicBool, Ordering},
5-
},
6-
time::Duration,
1+
use std::sync::{
2+
Arc,
3+
atomic::{AtomicBool, Ordering},
74
};
85

96
use parking_lot::RwLock;
107

11-
use crate::{diff::Action, git::CommitDiff};
8+
use crate::diff::{Action, CommitDiff};
129

13-
const RECEIVE_TIMEOUT: Duration = Duration::from_millis(500);
10+
// TODO move
11+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
12+
pub(crate) enum LoadStatus {
13+
New,
14+
QuickDiff(usize, usize),
15+
CompleteQuickDiff,
16+
Diff(usize, usize),
17+
DiffComplete,
18+
Canceled,
19+
}
1420

1521
#[derive(Clone, Debug)]
1622
pub(crate) struct State {
23+
load_status: Arc<RwLock<LoadStatus>>,
1724
diff: Arc<RwLock<CommitDiff>>,
1825
ended: Arc<AtomicBool>,
1926
paused: Arc<AtomicBool>,
@@ -25,6 +32,7 @@ impl State {
2532
pub(crate) fn new(diff: Arc<RwLock<CommitDiff>>) -> Self {
2633
let (update_sender, update_receiver) = crossbeam_channel::unbounded();
2734
Self {
35+
load_status: Arc::new(RwLock::new(LoadStatus::New)),
2836
diff,
2937
ended: Arc::new(AtomicBool::from(false)),
3038
paused: Arc::new(AtomicBool::from(false)),
@@ -33,6 +41,10 @@ impl State {
3341
}
3442
}
3543

44+
pub(crate) fn load_status(&self) -> Arc<RwLock<LoadStatus>> {
45+
Arc::clone(&self.load_status)
46+
}
47+
3648
pub(crate) fn diff(&self) -> Arc<RwLock<CommitDiff>> {
3749
Arc::clone(&self.diff)
3850
}

src/diff/thread.rs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,12 @@ use captur::capture;
88
use parking_lot::Mutex;
99

1010
use crate::{
11-
diff::{Action, State, UpdateHandlerFn},
12-
git::CommitDiffLoader,
11+
diff::{Action, CommitDiffLoader, State, UpdateHandlerFn, state::LoadStatus},
1312
runtime::{Installer, RuntimeError, Threadable},
1413
};
1514

1615
pub(crate) const THREAD_NAME: &str = "diff";
1716
const MINIMUM_PAUSE_RATE: Duration = Duration::from_millis(50);
18-
const LONG_DIFF_TIME: Duration = Duration::from_millis(100);
19-
20-
fn should_process_intermediate_diff(time: Instant) -> bool {
21-
time.saturating_duration_since(Instant::now()) >= LONG_DIFF_TIME
22-
}
2317

2418
#[derive(Debug)]
2519
pub(crate) struct Thread<UpdateHandler: UpdateHandlerFn> {
@@ -36,10 +30,11 @@ where UpdateHandler: UpdateHandlerFn + 'static
3630

3731
installer.spawn(THREAD_NAME, |notifier| {
3832
let update_handler = Arc::clone(&self.update_handler);
39-
let mut commit_diff_loader = Arc::clone(&self.commit_diff_loader);
33+
let commit_diff_loader = Arc::clone(&self.commit_diff_loader);
4034
move || {
4135
capture!(notifier, state);
4236

37+
let load_status = state.load_status();
4338
notifier.wait();
4439
let mut time = Instant::now();
4540

@@ -59,9 +54,10 @@ where UpdateHandler: UpdateHandlerFn + 'static
5954
match msg {
6055
Action::Load(hash) => {
6156
time = Instant::now();
62-
if let Err(e) = loader.load_diff(hash.as_str(), || {
57+
if let Err(e) = loader.load_diff(hash.as_str(), |s: LoadStatus| {
6358
eprintln!("Update!");
64-
59+
let mut ls = load_status.write();
60+
*ls = s;
6561
update_handler();
6662
// TODO what about paused
6763
return state.is_ended();

src/git.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,6 @@
99
//! performance, they should only be used in test code.
1010
1111
mod commit;
12-
mod commit_diff;
13-
mod commit_diff_loader;
14-
mod commit_diff_loader_options;
1512
mod config_loader;
1613
mod delta;
1714
mod diff_line;
@@ -29,9 +26,6 @@ pub(crate) use git2::{Config, ErrorCode};
2926

3027
pub(crate) use self::{
3128
commit::Commit,
32-
commit_diff::{CommitDiff, LoadedStatus},
33-
commit_diff_loader::CommitDiffLoader,
34-
commit_diff_loader_options::CommitDiffLoaderOptions,
3529
config_loader::{ConfigLoader, open_repository_from_env},
3630
delta::Delta,
3731
diff_line::DiffLine,

0 commit comments

Comments
 (0)