mirror of
https://github.com/gitui-org/gitui
synced 2026-05-22 16:38:28 +00:00
cancel commit search (#2078)
closes #1860 Co-authored-by: StemCll <lydjotj6f@mozmail.com>
This commit is contained in:
parent
762b889b48
commit
5dad9f4adb
3 changed files with 105 additions and 36 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
Loading…
Reference in a new issue