summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorextrawurst <776816+extrawurst@users.noreply.github.com>2024-02-20 19:07:25 +0100
committerGitHub <noreply@github.com>2024-02-20 19:07:25 +0100
commit5dad9f4adbd29ab33a839d74a1267d744437f032 (patch)
treefda79e57465f24f5605051e0710794e52e4e585d
parent762b889b4848f6bf12515cc1ad74da7d71f52334 (diff)
cancel commit search (#2078)
closes #1860 Co-authored-by: StemCll <lydjotj6f@mozmail.com>
-rw-r--r--CHANGELOG.md5
-rw-r--r--asyncgit/src/filter_commits.rs17
-rw-r--r--src/tabs/revlog.rs119
3 files changed, 105 insertions, 36 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1251adee..e4062836 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -21,12 +21,13 @@ Both commands can be overwritten via `newline` and `commit` in the key bindings.
These defaults require some adoption from existing users but feel more natural to new users.
### Added
+* support for new-line in text-input (e.g. commit message editor) [[@pm100]](https://github/pm100) ([#1662](https://github.com/extrawurst/gitui/issues/1662)).
+* add syntax highlighting for blame view [[@tdtrung17693](https://github.com/tdtrung17693)] ([#745](https://github.com/extrawurst/gitui/issues/745))
+* allow aborting pending commit log search [[@StemCll](https://github.com/StemCll)] ([#1860](https://github.com/extrawurst/gitui/issues/1860))
* `theme.ron` now supports customizing line break symbol ([#1894](https://github.com/extrawurst/gitui/issues/1894))
* add confirmation for dialog for undo commit [[@TeFiLeDo](https://github.com/TeFiLeDo)] ([#1912](https://github.com/extrawurst/gitui/issues/1912))
* support `prepare-commit-msg` hook ([#1873](https://github.com/extrawurst/gitui/issues/1873))
-* support for new-line in text-input (e.g. commit message editor) [[@pm100]](https://github/pm100) ([#1662](https://github.com/extrawurst/gitui/issues/1662)).
* new style `block_title_focused` to allow customizing title text of focused frame/block ([#2052](https://github.com/extrawurst/gitui/issues/2052)).
-* add syntax highlighting for blame view [[@tdtrung17693](https://github.com/tdtrung17693)] ([#745](https://github.com/extrawurst/gitui/issues/745))
* allow `fetch` command in both tabs of branchlist popup ([#2067](https://github.com/extrawurst/gitui/issues/2067))
### Changed
diff --git a/asyncgit/src/filter_commits.rs b/asyncgit/src/filter_commits.rs
index 3746b250..1b484126 100644
--- a/asyncgit/src/filter_commits.rs
+++ b/asyncgit/src/filter_commits.rs
@@ -10,7 +10,10 @@ use crate::{
AsyncGitNotification, ProgressPercent,
};
use std::{
- sync::{atomic::AtomicUsize, Arc, Mutex},
+ sync::{
+ atomic::{AtomicBool, AtomicUsize, Ordering},
+ Arc, Mutex,
+ },
time::{Duration, Instant},
};
@@ -35,6 +38,7 @@ enum JobState {
pub struct AsyncCommitFilterJob {
state: Arc<Mutex<Option<JobState>>>,
filter: SharedCommitFilterFn,
+ cancellation_flag: Arc<AtomicBool>,
}
///
@@ -44,6 +48,7 @@ impl AsyncCommitFilterJob {
repo_path: RepoPath,
commits: Vec<CommitId>,
filter: SharedCommitFilterFn,
+ cancellation_flag: Arc<AtomicBool>,
) -> Self {
Self {
state: Arc::new(Mutex::new(Some(JobState::Request {
@@ -51,6 +56,7 @@ impl AsyncCommitFilterJob {
commits,
}))),
filter,
+ cancellation_flag,
}
}
@@ -90,6 +96,8 @@ impl AsyncCommitFilterJob {
commits: Vec<CommitId>,
params: &RunParams<AsyncGitNotification, ProgressPercent>,
) -> Result<(Instant, Vec<CommitId>)> {
+ scopetime::scope_time!("filter_commits");
+
let total_amount = commits.len();
let start = Instant::now();
@@ -115,6 +123,13 @@ impl AsyncCommitFilterJob {
std::sync::atomic::Ordering::Relaxed,
);
+ if self
+ .cancellation_flag
+ .load(Ordering::Relaxed)
+ {
+ return None;
+ }
+
Self::update_progress(
params,
ProgressPercent::new(
diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs
index 2d135000..41694862 100644
--- a/src/tabs/revlog.rs
+++ b/src/tabs/revlog.rs
@@ -32,7 +32,14 @@ use ratatui::{
widgets::{Block, Borders, Paragraph},
Frame,
};
-use std::{rc::Rc, time::Duration};
+use std::{
+ rc::Rc,
+ sync::{
+ atomic::{AtomicBool, Ordering},
+ Arc,
+ },
+ time::Duration,
+};
use sync::CommitTags;
struct LogSearchResult {
@@ -47,6 +54,7 @@ enum LogSearch {
AsyncSingleJob<AsyncCommitFilterJob>,
LogFilterSearchOptions,
Option<ProgressPercent>,
+ Arc<AtomicBool>,
),
Results(LogSearchResult),
}
@@ -113,7 +121,7 @@ impl Revlog {
}
const fn is_search_pending(&self) -> bool {
- matches!(self.search, LogSearch::Searching(_, _, _))
+ matches!(self.search, LogSearch::Searching(_, _, _, _))
}
///
@@ -247,23 +255,48 @@ impl Revlog {
LogFilterSearch::new(options.clone()),
);
+ let cancellation_flag = Arc::new(AtomicBool::new(false));
+
let mut job = AsyncSingleJob::new(self.sender.clone());
job.spawn(AsyncCommitFilterJob::new(
self.repo.borrow().clone(),
self.list.copy_items(),
filter,
+ Arc::clone(&cancellation_flag),
));
- self.search = LogSearch::Searching(job, options, None);
+ self.search = LogSearch::Searching(
+ job,
+ options,
+ None,
+ Arc::clone(&cancellation_flag),
+ );
+
+ self.list.set_highlighting(None);
+ }
+ }
+ fn cancel_search(&mut self) -> bool {
+ if let LogSearch::Searching(_, _, _, cancellation_flag) =
+ &self.search
+ {
+ cancellation_flag.store(true, Ordering::Relaxed);
self.list.set_highlighting(None);
+ return true;
}
+
+ false
}
fn update_search_state(&mut self) {
match &mut self.search {
LogSearch::Off | LogSearch::Results(_) => (),
- LogSearch::Searching(search, options, progress) => {
+ LogSearch::Searching(
+ search,
+ options,
+ progress,
+ cancel,
+ ) => {
if search.is_pending() {
//update progress
*progress = search.progress();
@@ -273,20 +306,26 @@ impl Revlog {
{
match search {
Ok(search) => {
- self.list.set_highlighting(Some(
- Rc::new(
- search
- .result
- .into_iter()
- .collect::<IndexSet<_>>(),
- ),
- ));
+ let was_aborted =
+ cancel.load(Ordering::Relaxed);
+
+ self.search = if was_aborted {
+ LogSearch::Off
+ } else {
+ self.list.set_highlighting(Some(
+ Rc::new(
+ search
+ .result
+ .into_iter()
+ .collect::<IndexSet<_>>(),
+ ),
+ ));
- self.search =
LogSearch::Results(LogSearchResult {
options: options.clone(),
duration: search.duration,
- });
+ })
+ };
}
Err(err) => {
self.queue.push(
@@ -309,7 +348,7 @@ impl Revlog {
fn draw_search(&self, f: &mut Frame, area: Rect) {
let (text, title) = match &self.search {
- LogSearch::Searching(_, options, progress) => (
+ LogSearch::Searching(_, options, progress, _) => (
format!("'{}'", options.search_pattern.clone()),
format!(
"({}%)",
@@ -357,12 +396,12 @@ impl Revlog {
);
}
- fn can_leave_search(&self) -> bool {
+ fn can_close_search(&self) -> bool {
self.is_in_search_mode() && !self.is_search_pending()
}
fn can_start_search(&self) -> bool {
- !self.git_log.is_pending()
+ !self.git_log.is_pending() && !self.is_search_pending()
}
}
@@ -425,11 +464,13 @@ impl Component for Revlog {
k,
self.key_config.keys.exit_popup,
) {
- if self.can_leave_search() {
- self.search = LogSearch::Off;
+ if self.is_search_pending() {
+ self.cancel_search();
+ } else if self.can_close_search() {
self.list.set_highlighting(None);
- return Ok(EventState::Consumed);
+ self.search = LogSearch::Off;
}
+ return Ok(EventState::Consumed);
} else if key_match(k, self.key_config.keys.copy) {
try_or_popup!(
self,
@@ -462,13 +503,15 @@ impl Component for Revlog {
} else if key_match(
k,
self.key_config.keys.select_branch,
- ) {
+ ) && !self.is_search_pending()
+ {
self.queue.push(InternalEvent::SelectBranch);
return Ok(EventState::Consumed);
} else if key_match(
k,
self.key_config.keys.status_reset_item,
- ) {
+ ) && !self.is_search_pending()
+ {
try_or_popup!(
self,
"revert error:",
@@ -479,7 +522,8 @@ impl Component for Revlog {
} else if key_match(
k,
self.key_config.keys.open_file_tree,
- ) {
+ ) && !self.is_search_pending()
+ {
return self.selected_commit().map_or(
Ok(EventState::NotConsumed),
|id| {
@@ -499,7 +543,8 @@ impl Component for Revlog {
} else if key_match(
k,
self.key_config.keys.log_reset_comit,
- ) {
+ ) && !self.is_search_pending()
+ {
return self.selected_commit().map_or(
Ok(EventState::NotConsumed),
|id| {
@@ -512,7 +557,8 @@ impl Component for Revlog {
} else if key_match(
k,
self.key_config.keys.log_reword_comit,
- ) {
+ ) && !self.is_search_pending()
+ {
return self.selected_commit().map_or(
Ok(EventState::NotConsumed),
|id| {
@@ -532,6 +578,7 @@ impl Component for Revlog {
k,
self.key_config.keys.compare_commits,
) && self.list.marked_count() > 0
+ && !self.is_search_pending()
{
if self.list.marked_count() == 1 {
// compare against head
@@ -577,7 +624,9 @@ impl Component for Revlog {
CommandInfo::new(
strings::commands::log_close_search(&self.key_config),
true,
- (self.visible && self.can_leave_search())
+ (self.visible
+ && (self.can_close_search()
+ || self.is_search_pending()))
|| force_all,
)
.order(order::PRIORITY),
@@ -601,20 +650,24 @@ impl Component for Revlog {
&self.key_config,
),
true,
- self.visible || force_all,
+ (self.visible && !self.is_search_pending()) || force_all,
));
out.push(CommandInfo::new(
strings::commands::compare_with_head(&self.key_config),
self.list.marked_count() == 1,
- (self.visible && self.list.marked_count() <= 1)
+ (self.visible
+ && !self.is_search_pending()
+ && self.list.marked_count() <= 1)
|| force_all,
));
out.push(CommandInfo::new(
strings::commands::compare_commits(&self.key_config),
true,
- (self.visible && self.list.marked_count() == 2)
+ (self.visible
+ && !self.is_search_pending()
+ && self.list.marked_count() == 2)
|| force_all,
));
@@ -651,24 +704,24 @@ impl Component for Revlog {
out.push(CommandInfo::new(
strings::commands::inspect_file_tree(&self.key_config),
self.selected_commit().is_some(),
- self.visible || force_all,
+ (self.visible && !self.is_search_pending()) || force_all,
));
out.push(CommandInfo::new(
strings::commands::revert_commit(&self.key_config),
self.selected_commit().is_some(),
- self.visible || force_all,
+ (self.visible && !self.is_search_pending()) || force_all,
));
out.push(CommandInfo::new(
strings::commands::log_reset_commit(&self.key_config),
self.selected_commit().is_some(),
- self.visible || force_all,
+ (self.visible && !self.is_search_pending()) || force_all,
));
out.push(CommandInfo::new(
strings::commands::log_reword_commit(&self.key_config),
self.selected_commit().is_some(),
- self.visible || force_all,
+ (self.visible && !self.is_search_pending()) || force_all,
));
out.push(CommandInfo::new(
strings::commands::log_find_commit(&self.key_config),