Skip to content

Commit 9ce0d51

Browse files
extrawurstStemCll
authored andcommitted
cancel commit search (gitui-org#2078)
closes gitui-org#1860 Co-authored-by: StemCll <[email protected]>
1 parent 1d56deb commit 9ce0d51

File tree

3 files changed

+105
-36
lines changed

3 files changed

+105
-36
lines changed

CHANGELOG.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,13 @@ Both commands can be overwritten via `newline` and `commit` in the key bindings.
2121
These defaults require some adoption from existing users but feel more natural to new users.
2222

2323
### Added
24+
* support for new-line in text-input (e.g. commit message editor) [[@pm100]](https://github/pm100) ([#1662](https://github.com/extrawurst/gitui/issues/1662)).
25+
* add syntax highlighting for blame view [[@tdtrung17693](https://github.com/tdtrung17693)] ([#745](https://github.com/extrawurst/gitui/issues/745))
26+
* allow aborting pending commit log search [[@StemCll](https://github.com/StemCll)] ([#1860](https://github.com/extrawurst/gitui/issues/1860))
2427
* `theme.ron` now supports customizing line break symbol ([#1894](https://github.com/extrawurst/gitui/issues/1894))
2528
* add confirmation for dialog for undo commit [[@TeFiLeDo](https://github.com/TeFiLeDo)] ([#1912](https://github.com/extrawurst/gitui/issues/1912))
2629
* support `prepare-commit-msg` hook ([#1873](https://github.com/extrawurst/gitui/issues/1873))
27-
* support for new-line in text-input (e.g. commit message editor) [[@pm100]](https://github/pm100) ([#1662](https://github.com/extrawurst/gitui/issues/1662)).
2830
* new style `block_title_focused` to allow customizing title text of focused frame/block ([#2052](https://github.com/extrawurst/gitui/issues/2052)).
29-
* add syntax highlighting for blame view [[@tdtrung17693](https://github.com/tdtrung17693)] ([#745](https://github.com/extrawurst/gitui/issues/745))
3031
* allow `fetch` command in both tabs of branchlist popup ([#2067](https://github.com/extrawurst/gitui/issues/2067))
3132

3233
### Changed

asyncgit/src/filter_commits.rs

+16-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ use crate::{
1010
AsyncGitNotification, ProgressPercent,
1111
};
1212
use std::{
13-
sync::{atomic::AtomicUsize, Arc, Mutex},
13+
sync::{
14+
atomic::{AtomicBool, AtomicUsize, Ordering},
15+
Arc, Mutex,
16+
},
1417
time::{Duration, Instant},
1518
};
1619

@@ -35,6 +38,7 @@ enum JobState {
3538
pub struct AsyncCommitFilterJob {
3639
state: Arc<Mutex<Option<JobState>>>,
3740
filter: SharedCommitFilterFn,
41+
cancellation_flag: Arc<AtomicBool>,
3842
}
3943

4044
///
@@ -44,13 +48,15 @@ impl AsyncCommitFilterJob {
4448
repo_path: RepoPath,
4549
commits: Vec<CommitId>,
4650
filter: SharedCommitFilterFn,
51+
cancellation_flag: Arc<AtomicBool>,
4752
) -> Self {
4853
Self {
4954
state: Arc::new(Mutex::new(Some(JobState::Request {
5055
repo_path,
5156
commits,
5257
}))),
5358
filter,
59+
cancellation_flag,
5460
}
5561
}
5662

@@ -90,6 +96,8 @@ impl AsyncCommitFilterJob {
9096
commits: Vec<CommitId>,
9197
params: &RunParams<AsyncGitNotification, ProgressPercent>,
9298
) -> Result<(Instant, Vec<CommitId>)> {
99+
scopetime::scope_time!("filter_commits");
100+
93101
let total_amount = commits.len();
94102
let start = Instant::now();
95103

@@ -115,6 +123,13 @@ impl AsyncCommitFilterJob {
115123
std::sync::atomic::Ordering::Relaxed,
116124
);
117125

126+
if self
127+
.cancellation_flag
128+
.load(Ordering::Relaxed)
129+
{
130+
return None;
131+
}
132+
118133
Self::update_progress(
119134
params,
120135
ProgressPercent::new(

src/tabs/revlog.rs

+86-33
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,14 @@ use ratatui::{
3232
widgets::{Block, Borders, Paragraph},
3333
Frame,
3434
};
35-
use std::{rc::Rc, time::Duration};
35+
use std::{
36+
rc::Rc,
37+
sync::{
38+
atomic::{AtomicBool, Ordering},
39+
Arc,
40+
},
41+
time::Duration,
42+
};
3643
use sync::CommitTags;
3744

3845
struct LogSearchResult {
@@ -47,6 +54,7 @@ enum LogSearch {
4754
AsyncSingleJob<AsyncCommitFilterJob>,
4855
LogFilterSearchOptions,
4956
Option<ProgressPercent>,
57+
Arc<AtomicBool>,
5058
),
5159
Results(LogSearchResult),
5260
}
@@ -113,7 +121,7 @@ impl Revlog {
113121
}
114122

115123
const fn is_search_pending(&self) -> bool {
116-
matches!(self.search, LogSearch::Searching(_, _, _))
124+
matches!(self.search, LogSearch::Searching(_, _, _, _))
117125
}
118126

119127
///
@@ -247,23 +255,48 @@ impl Revlog {
247255
LogFilterSearch::new(options.clone()),
248256
);
249257

258+
let cancellation_flag = Arc::new(AtomicBool::new(false));
259+
250260
let mut job = AsyncSingleJob::new(self.sender.clone());
251261
job.spawn(AsyncCommitFilterJob::new(
252262
self.repo.borrow().clone(),
253263
self.list.copy_items(),
254264
filter,
265+
Arc::clone(&cancellation_flag),
255266
));
256267

257-
self.search = LogSearch::Searching(job, options, None);
268+
self.search = LogSearch::Searching(
269+
job,
270+
options,
271+
None,
272+
Arc::clone(&cancellation_flag),
273+
);
274+
275+
self.list.set_highlighting(None);
276+
}
277+
}
258278

279+
fn cancel_search(&mut self) -> bool {
280+
if let LogSearch::Searching(_, _, _, cancellation_flag) =
281+
&self.search
282+
{
283+
cancellation_flag.store(true, Ordering::Relaxed);
259284
self.list.set_highlighting(None);
285+
return true;
260286
}
287+
288+
false
261289
}
262290

263291
fn update_search_state(&mut self) {
264292
match &mut self.search {
265293
LogSearch::Off | LogSearch::Results(_) => (),
266-
LogSearch::Searching(search, options, progress) => {
294+
LogSearch::Searching(
295+
search,
296+
options,
297+
progress,
298+
cancel,
299+
) => {
267300
if search.is_pending() {
268301
//update progress
269302
*progress = search.progress();
@@ -273,20 +306,26 @@ impl Revlog {
273306
{
274307
match search {
275308
Ok(search) => {
276-
self.list.set_highlighting(Some(
277-
Rc::new(
278-
search
279-
.result
280-
.into_iter()
281-
.collect::<IndexSet<_>>(),
282-
),
283-
));
309+
let was_aborted =
310+
cancel.load(Ordering::Relaxed);
311+
312+
self.search = if was_aborted {
313+
LogSearch::Off
314+
} else {
315+
self.list.set_highlighting(Some(
316+
Rc::new(
317+
search
318+
.result
319+
.into_iter()
320+
.collect::<IndexSet<_>>(),
321+
),
322+
));
284323

285-
self.search =
286324
LogSearch::Results(LogSearchResult {
287325
options: options.clone(),
288326
duration: search.duration,
289-
});
327+
})
328+
};
290329
}
291330
Err(err) => {
292331
self.queue.push(
@@ -309,7 +348,7 @@ impl Revlog {
309348

310349
fn draw_search(&self, f: &mut Frame, area: Rect) {
311350
let (text, title) = match &self.search {
312-
LogSearch::Searching(_, options, progress) => (
351+
LogSearch::Searching(_, options, progress, _) => (
313352
format!("'{}'", options.search_pattern.clone()),
314353
format!(
315354
"({}%)",
@@ -357,12 +396,12 @@ impl Revlog {
357396
);
358397
}
359398

360-
fn can_leave_search(&self) -> bool {
399+
fn can_close_search(&self) -> bool {
361400
self.is_in_search_mode() && !self.is_search_pending()
362401
}
363402

364403
fn can_start_search(&self) -> bool {
365-
!self.git_log.is_pending()
404+
!self.git_log.is_pending() && !self.is_search_pending()
366405
}
367406
}
368407

@@ -425,11 +464,13 @@ impl Component for Revlog {
425464
k,
426465
self.key_config.keys.exit_popup,
427466
) {
428-
if self.can_leave_search() {
429-
self.search = LogSearch::Off;
467+
if self.is_search_pending() {
468+
self.cancel_search();
469+
} else if self.can_close_search() {
430470
self.list.set_highlighting(None);
431-
return Ok(EventState::Consumed);
471+
self.search = LogSearch::Off;
432472
}
473+
return Ok(EventState::Consumed);
433474
} else if key_match(k, self.key_config.keys.copy) {
434475
try_or_popup!(
435476
self,
@@ -462,13 +503,15 @@ impl Component for Revlog {
462503
} else if key_match(
463504
k,
464505
self.key_config.keys.select_branch,
465-
) {
506+
) && !self.is_search_pending()
507+
{
466508
self.queue.push(InternalEvent::SelectBranch);
467509
return Ok(EventState::Consumed);
468510
} else if key_match(
469511
k,
470512
self.key_config.keys.status_reset_item,
471-
) {
513+
) && !self.is_search_pending()
514+
{
472515
try_or_popup!(
473516
self,
474517
"revert error:",
@@ -479,7 +522,8 @@ impl Component for Revlog {
479522
} else if key_match(
480523
k,
481524
self.key_config.keys.open_file_tree,
482-
) {
525+
) && !self.is_search_pending()
526+
{
483527
return self.selected_commit().map_or(
484528
Ok(EventState::NotConsumed),
485529
|id| {
@@ -499,7 +543,8 @@ impl Component for Revlog {
499543
} else if key_match(
500544
k,
501545
self.key_config.keys.log_reset_comit,
502-
) {
546+
) && !self.is_search_pending()
547+
{
503548
return self.selected_commit().map_or(
504549
Ok(EventState::NotConsumed),
505550
|id| {
@@ -512,7 +557,8 @@ impl Component for Revlog {
512557
} else if key_match(
513558
k,
514559
self.key_config.keys.log_reword_comit,
515-
) {
560+
) && !self.is_search_pending()
561+
{
516562
return self.selected_commit().map_or(
517563
Ok(EventState::NotConsumed),
518564
|id| {
@@ -532,6 +578,7 @@ impl Component for Revlog {
532578
k,
533579
self.key_config.keys.compare_commits,
534580
) && self.list.marked_count() > 0
581+
&& !self.is_search_pending()
535582
{
536583
if self.list.marked_count() == 1 {
537584
// compare against head
@@ -577,7 +624,9 @@ impl Component for Revlog {
577624
CommandInfo::new(
578625
strings::commands::log_close_search(&self.key_config),
579626
true,
580-
(self.visible && self.can_leave_search())
627+
(self.visible
628+
&& (self.can_close_search()
629+
|| self.is_search_pending()))
581630
|| force_all,
582631
)
583632
.order(order::PRIORITY),
@@ -601,20 +650,24 @@ impl Component for Revlog {
601650
&self.key_config,
602651
),
603652
true,
604-
self.visible || force_all,
653+
(self.visible && !self.is_search_pending()) || force_all,
605654
));
606655

607656
out.push(CommandInfo::new(
608657
strings::commands::compare_with_head(&self.key_config),
609658
self.list.marked_count() == 1,
610-
(self.visible && self.list.marked_count() <= 1)
659+
(self.visible
660+
&& !self.is_search_pending()
661+
&& self.list.marked_count() <= 1)
611662
|| force_all,
612663
));
613664

614665
out.push(CommandInfo::new(
615666
strings::commands::compare_commits(&self.key_config),
616667
true,
617-
(self.visible && self.list.marked_count() == 2)
668+
(self.visible
669+
&& !self.is_search_pending()
670+
&& self.list.marked_count() == 2)
618671
|| force_all,
619672
));
620673

@@ -651,24 +704,24 @@ impl Component for Revlog {
651704
out.push(CommandInfo::new(
652705
strings::commands::inspect_file_tree(&self.key_config),
653706
self.selected_commit().is_some(),
654-
self.visible || force_all,
707+
(self.visible && !self.is_search_pending()) || force_all,
655708
));
656709

657710
out.push(CommandInfo::new(
658711
strings::commands::revert_commit(&self.key_config),
659712
self.selected_commit().is_some(),
660-
self.visible || force_all,
713+
(self.visible && !self.is_search_pending()) || force_all,
661714
));
662715

663716
out.push(CommandInfo::new(
664717
strings::commands::log_reset_commit(&self.key_config),
665718
self.selected_commit().is_some(),
666-
self.visible || force_all,
719+
(self.visible && !self.is_search_pending()) || force_all,
667720
));
668721
out.push(CommandInfo::new(
669722
strings::commands::log_reword_commit(&self.key_config),
670723
self.selected_commit().is_some(),
671-
self.visible || force_all,
724+
(self.visible && !self.is_search_pending()) || force_all,
672725
));
673726
out.push(CommandInfo::new(
674727
strings::commands::log_find_commit(&self.key_config),

0 commit comments

Comments
 (0)