Skip to content

cancel commit search #2078

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Feb 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
17 changes: 16 additions & 1 deletion asyncgit/src/filter_commits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
};

Expand All @@ -35,6 +38,7 @@ enum JobState {
pub struct AsyncCommitFilterJob {
state: Arc<Mutex<Option<JobState>>>,
filter: SharedCommitFilterFn,
cancellation_flag: Arc<AtomicBool>,
}

///
Expand All @@ -44,13 +48,15 @@ impl AsyncCommitFilterJob {
repo_path: RepoPath,
commits: Vec<CommitId>,
filter: SharedCommitFilterFn,
cancellation_flag: Arc<AtomicBool>,
) -> Self {
Self {
state: Arc::new(Mutex::new(Some(JobState::Request {
repo_path,
commits,
}))),
filter,
cancellation_flag,
}
}

Expand Down Expand Up @@ -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();

Expand All @@ -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(
Expand Down
119 changes: 86 additions & 33 deletions src/tabs/revlog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -47,6 +54,7 @@ enum LogSearch {
AsyncSingleJob<AsyncCommitFilterJob>,
LogFilterSearchOptions,
Option<ProgressPercent>,
Arc<AtomicBool>,
),
Results(LogSearchResult),
}
Expand Down Expand Up @@ -113,7 +121,7 @@ impl Revlog {
}

const fn is_search_pending(&self) -> bool {
matches!(self.search, LogSearch::Searching(_, _, _))
matches!(self.search, LogSearch::Searching(_, _, _, _))
}

///
Expand Down Expand Up @@ -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();
Expand All @@ -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(
Expand All @@ -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!(
"({}%)",
Expand Down Expand Up @@ -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()
}
}

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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:",
Expand All @@ -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| {
Expand All @@ -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| {
Expand All @@ -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| {
Expand All @@ -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
Expand Down Expand Up @@ -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),
Expand All @@ -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,
));

Expand Down Expand Up @@ -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),
Expand Down