mirror of
https://github.com/gitui-org/gitui
synced 2026-05-23 08:58:21 +00:00
Index of search result (#1840)
This commit is contained in:
parent
c68fa3e87b
commit
2675934027
5 changed files with 64 additions and 37 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -744,6 +744,7 @@ dependencies = [
|
|||
"filetreelist",
|
||||
"fuzzy-matcher",
|
||||
"gh-emoji",
|
||||
"indexmap",
|
||||
"itertools",
|
||||
"log",
|
||||
"notify",
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ easy-cast = "0.5"
|
|||
filetreelist = { path = "./filetreelist", version = "0.5" }
|
||||
fuzzy-matcher = "0.3"
|
||||
gh-emoji = { version = "1.0", optional = true }
|
||||
indexmap = "1.9"
|
||||
itertools = "0.11"
|
||||
log = "0.4"
|
||||
notify = "5.1"
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ use asyncgit::sync::{
|
|||
};
|
||||
use chrono::{DateTime, Local};
|
||||
use crossterm::event::Event;
|
||||
use indexmap::IndexSet;
|
||||
use itertools::Itertools;
|
||||
use ratatui::{
|
||||
backend::Backend,
|
||||
|
|
@ -28,12 +29,8 @@ use ratatui::{
|
|||
Frame,
|
||||
};
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
cell::Cell,
|
||||
cmp,
|
||||
collections::{BTreeMap, HashSet},
|
||||
convert::TryFrom,
|
||||
time::Instant,
|
||||
borrow::Cow, cell::Cell, cmp, collections::BTreeMap,
|
||||
convert::TryFrom, rc::Rc, time::Instant,
|
||||
};
|
||||
|
||||
const ELEMENTS_PER_LINE: usize = 9;
|
||||
|
|
@ -44,8 +41,9 @@ pub struct CommitList {
|
|||
repo: RepoPathRef,
|
||||
title: Box<str>,
|
||||
selection: usize,
|
||||
highlighted_selection: Option<usize>,
|
||||
items: ItemBatch,
|
||||
highlights: Option<HashSet<CommitId>>,
|
||||
highlights: Option<Rc<IndexSet<CommitId>>>,
|
||||
commits: Vec<CommitId>,
|
||||
marked: Vec<(usize, CommitId)>,
|
||||
scroll_state: (Instant, f32),
|
||||
|
|
@ -73,6 +71,7 @@ impl CommitList {
|
|||
items: ItemBatch::default(),
|
||||
marked: Vec::with_capacity(2),
|
||||
selection: 0,
|
||||
highlighted_selection: None,
|
||||
commits: Vec::new(),
|
||||
highlights: None,
|
||||
scroll_state: (Instant::now(), 0_f32),
|
||||
|
|
@ -240,10 +239,11 @@ impl CommitList {
|
|||
///
|
||||
pub fn set_highlighting(
|
||||
&mut self,
|
||||
highlighting: Option<HashSet<CommitId>>,
|
||||
highlighting: Option<Rc<IndexSet<CommitId>>>,
|
||||
) {
|
||||
self.highlights = highlighting;
|
||||
self.select_next_highlight();
|
||||
self.set_highlighted_selection_index();
|
||||
self.fetch_commits();
|
||||
}
|
||||
|
||||
|
|
@ -253,12 +253,32 @@ impl CommitList {
|
|||
|
||||
if let Some(position) = position {
|
||||
self.selection = position;
|
||||
self.set_highlighted_selection_index();
|
||||
Ok(())
|
||||
} else {
|
||||
anyhow::bail!("Could not select commit. It might not be loaded yet or it might be on a different branch.");
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
pub fn highlighted_selection_info(&self) -> (usize, usize) {
|
||||
let amount = self
|
||||
.highlights
|
||||
.as_ref()
|
||||
.map(|highlights| highlights.len())
|
||||
.unwrap_or_default();
|
||||
(self.highlighted_selection.unwrap_or_default(), amount)
|
||||
}
|
||||
|
||||
fn set_highlighted_selection_index(&mut self) {
|
||||
self.highlighted_selection =
|
||||
self.highlights.as_ref().and_then(|highlights| {
|
||||
highlights.iter().position(|entry| {
|
||||
entry == &self.commits[self.selection]
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
const fn selection(&self) -> usize {
|
||||
self.selection
|
||||
}
|
||||
|
|
@ -318,6 +338,7 @@ impl CommitList {
|
|||
self.selection = new_selection;
|
||||
|
||||
if self.selection_highlighted() {
|
||||
self.set_highlighted_selection_index();
|
||||
return Ok(true);
|
||||
}
|
||||
}
|
||||
|
|
@ -703,12 +724,7 @@ impl CommitList {
|
|||
);
|
||||
|
||||
if let Ok(commits) = commits {
|
||||
self.items.set_items(
|
||||
want_min,
|
||||
commits,
|
||||
//TODO: optimize via sharable data (BTreeMap that preserves order and lookup)
|
||||
&self.highlights.clone(),
|
||||
);
|
||||
self.items.set_items(want_min, commits, &self.highlights);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use asyncgit::sync::{CommitId, CommitInfo};
|
||||
use chrono::{DateTime, Duration, Local, NaiveDateTime, Utc};
|
||||
use std::{collections::HashSet, slice::Iter};
|
||||
use indexmap::IndexSet;
|
||||
use std::{rc::Rc, slice::Iter};
|
||||
|
||||
#[cfg(feature = "ghemoji")]
|
||||
use super::emoji::emojifi_string;
|
||||
|
|
@ -111,7 +112,7 @@ impl ItemBatch {
|
|||
&mut self,
|
||||
start_index: usize,
|
||||
commits: Vec<CommitInfo>,
|
||||
highlighted: &Option<HashSet<CommitId>>,
|
||||
highlighted: &Option<Rc<IndexSet<CommitId>>>,
|
||||
) {
|
||||
self.items.clear();
|
||||
self.items.extend(commits.into_iter().map(|c| {
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ use asyncgit::{
|
|||
};
|
||||
use crossbeam_channel::Sender;
|
||||
use crossterm::event::Event;
|
||||
use indexmap::IndexSet;
|
||||
use ratatui::{
|
||||
backend::Backend,
|
||||
layout::{Alignment, Constraint, Direction, Layout, Rect},
|
||||
|
|
@ -30,11 +31,10 @@ use ratatui::{
|
|||
widgets::{Block, Borders, Paragraph},
|
||||
Frame,
|
||||
};
|
||||
use std::{collections::HashSet, rc::Rc, time::Duration};
|
||||
use std::{rc::Rc, time::Duration};
|
||||
use sync::CommitTags;
|
||||
|
||||
struct LogSearchResult {
|
||||
commits: usize,
|
||||
options: LogFilterSearchOptions,
|
||||
duration: Duration,
|
||||
}
|
||||
|
|
@ -280,16 +280,14 @@ impl Revlog {
|
|||
false
|
||||
} else {
|
||||
let results = search.extract_items()?;
|
||||
let commits = results.len();
|
||||
let duration = search.get_last_duration()?;
|
||||
|
||||
self.list.set_highlighting(Some(
|
||||
results.into_iter().collect::<HashSet<_>>(),
|
||||
));
|
||||
self.list.set_highlighting(Some(Rc::new(
|
||||
results.into_iter().collect::<IndexSet<_>>(),
|
||||
)));
|
||||
|
||||
self.search =
|
||||
LogSearch::Results(LogSearchResult {
|
||||
commits,
|
||||
options: options.clone(),
|
||||
duration,
|
||||
});
|
||||
|
|
@ -306,22 +304,28 @@ impl Revlog {
|
|||
}
|
||||
|
||||
fn draw_search<B: Backend>(&self, f: &mut Frame<B>, area: Rect) {
|
||||
let text = match &self.search {
|
||||
LogSearch::Searching(_, options) => {
|
||||
format!(
|
||||
"'{}' (pending results...)",
|
||||
options.search_pattern.clone()
|
||||
)
|
||||
}
|
||||
let (text, title) = match &self.search {
|
||||
LogSearch::Searching(_, options) => (
|
||||
format!("'{}'", options.search_pattern.clone()),
|
||||
String::from("(pending results...)"),
|
||||
),
|
||||
LogSearch::Results(results) => {
|
||||
format!(
|
||||
"'{}' (hits: {}) (duration: {:?})",
|
||||
results.options.search_pattern.clone(),
|
||||
results.commits,
|
||||
results.duration,
|
||||
let info = self.list.highlighted_selection_info();
|
||||
|
||||
(
|
||||
format!(
|
||||
"'{}' (duration: {:?})",
|
||||
results.options.search_pattern.clone(),
|
||||
results.duration,
|
||||
),
|
||||
format!(
|
||||
"({}/{})",
|
||||
(info.0 + 1).min(info.1),
|
||||
info.1
|
||||
),
|
||||
)
|
||||
}
|
||||
LogSearch::Off => String::new(),
|
||||
LogSearch::Off => (String::new(), String::new()),
|
||||
};
|
||||
|
||||
f.render_widget(
|
||||
|
|
@ -329,7 +333,11 @@ impl Revlog {
|
|||
.block(
|
||||
Block::default()
|
||||
.title(Span::styled(
|
||||
strings::POPUP_TITLE_LOG_SEARCH,
|
||||
format!(
|
||||
"{} {}",
|
||||
strings::POPUP_TITLE_LOG_SEARCH,
|
||||
title
|
||||
),
|
||||
self.theme.title(true),
|
||||
))
|
||||
.borders(Borders::ALL)
|
||||
|
|
|
|||
Loading…
Reference in a new issue