Skip to content

Commit ed849a3

Browse files
committed
search in commit log
Revert "visualize empty line in diff better (closes #1359)" This reverts commit 6576c7e.
1 parent 809281f commit ed849a3

File tree

12 files changed

+356
-70
lines changed

12 files changed

+356
-70
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

asyncgit/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@ categories = ["concurrency", "asynchronous"]
1212
keywords = ["git"]
1313

1414
[dependencies]
15+
bitflags = "1"
1516
crossbeam-channel = "0.5"
1617
easy-cast = "0.5"
18+
fuzzy-matcher = "0.3"
1719
git2 = "0.17"
1820
log = "0.4"
1921
# git2 = { path = "../../extern/git2-rs", features = ["vendored-openssl"]}

asyncgit/src/revlog.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,12 @@ impl AsyncLog {
7777
Ok(list[min..max].to_vec())
7878
}
7979

80+
///
81+
pub fn get_items(&self) -> Result<Vec<CommitId>> {
82+
let list = self.current.lock()?;
83+
Ok(list.clone())
84+
}
85+
8086
///
8187
pub fn position(&self, id: CommitId) -> Result<Option<usize>> {
8288
let list = self.current.lock()?;

asyncgit/src/sync/logwalker.rs

Lines changed: 166 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
#![allow(dead_code)]
12
use super::CommitId;
23
use crate::{error::Result, sync::commit_files::get_commit_diff};
3-
use git2::{Commit, Oid, Repository};
4+
use bitflags::bitflags;
5+
use fuzzy_matcher::FuzzyMatcher;
6+
use git2::{Commit, Diff, Oid, Repository};
47
use std::{
58
cmp::Ordering,
69
collections::{BinaryHeap, HashSet},
@@ -55,6 +58,123 @@ pub fn diff_contains_file(file_path: String) -> LogWalkerFilter {
5558
))
5659
}
5760

61+
// TODO:
62+
// fuzzy-match:
63+
// message, authors, file-names in diff, diff-content
64+
//
65+
// substr matching:
66+
// commit-sha, date
67+
bitflags! {
68+
///
69+
pub struct FilterSearchOptions: u32 {
70+
///
71+
const MESSAGE = 0b0000_0001;
72+
///
73+
const FILENAMES = 0b0000_0010;
74+
}
75+
}
76+
77+
///
78+
pub struct LogFilterSearch {
79+
///
80+
pub matcher: fuzzy_matcher::skim::SkimMatcherV2,
81+
///
82+
pub search_pattern: String,
83+
///
84+
pub options: FilterSearchOptions,
85+
}
86+
87+
impl LogFilterSearch {
88+
///
89+
pub fn new(
90+
search_pattern: String,
91+
options: FilterSearchOptions,
92+
) -> Self {
93+
Self {
94+
matcher: fuzzy_matcher::skim::SkimMatcherV2::default(),
95+
search_pattern,
96+
options,
97+
}
98+
}
99+
100+
fn match_diff(&self, diff: &Diff<'_>) -> bool {
101+
diff.deltas().any(|delta| {
102+
if delta
103+
.new_file()
104+
.path()
105+
.and_then(|file| file.as_os_str().to_str())
106+
.map(|file| {
107+
self.matcher
108+
.fuzzy_match(
109+
file,
110+
self.search_pattern.as_str(),
111+
)
112+
.is_some()
113+
})
114+
.unwrap_or_default()
115+
{
116+
return true;
117+
}
118+
119+
delta
120+
.old_file()
121+
.path()
122+
.and_then(|file| file.as_os_str().to_str())
123+
.map(|file| {
124+
self.matcher
125+
.fuzzy_match(
126+
file,
127+
self.search_pattern.as_str(),
128+
)
129+
.is_some()
130+
})
131+
.unwrap_or_default()
132+
})
133+
}
134+
}
135+
136+
///
137+
pub fn filter_commit_by_search(
138+
filter: LogFilterSearch,
139+
) -> LogWalkerFilter {
140+
Arc::new(Box::new(
141+
move |repo: &Repository,
142+
commit_id: &CommitId|
143+
-> Result<bool> {
144+
let commit = repo.find_commit((*commit_id).into())?;
145+
146+
let msg_match = filter
147+
.options
148+
.contains(FilterSearchOptions::MESSAGE)
149+
.then(|| {
150+
commit.message().and_then(|msg| {
151+
filter.matcher.fuzzy_match(
152+
msg,
153+
filter.search_pattern.as_str(),
154+
)
155+
})
156+
})
157+
.flatten()
158+
.is_some();
159+
160+
let file_match = filter
161+
.options
162+
.contains(FilterSearchOptions::FILENAMES)
163+
.then(|| {
164+
get_commit_diff(
165+
repo, *commit_id, None, None, None,
166+
)
167+
.ok()
168+
})
169+
.flatten()
170+
.map(|diff| filter.match_diff(&diff))
171+
.unwrap_or_default();
172+
173+
Ok(msg_match || file_match)
174+
},
175+
))
176+
}
177+
58178
///
59179
pub struct LogWalker<'a> {
60180
commits: BinaryHeap<TimeOrderedCommit<'a>>,
@@ -130,11 +250,13 @@ impl<'a> LogWalker<'a> {
130250
mod tests {
131251
use super::*;
132252
use crate::error::Result;
253+
use crate::sync::tests::write_commit_file;
133254
use crate::sync::RepoPath;
134255
use crate::sync::{
135256
commit, get_commits_info, stage_add_file,
136257
tests::repo_init_empty,
137258
};
259+
use fuzzy_matcher::skim::SkimMatcherV2;
138260
use pretty_assertions::assert_eq;
139261
use std::{fs::File, io::Write, path::Path};
140262

@@ -246,4 +368,47 @@ mod tests {
246368

247369
Ok(())
248370
}
371+
372+
#[test]
373+
fn test_logwalker_with_filter_search() {
374+
let (_td, repo) = repo_init_empty().unwrap();
375+
376+
write_commit_file(&repo, "foo", "a", "commit1");
377+
let second_commit_id = write_commit_file(
378+
&repo,
379+
"baz",
380+
"a",
381+
"my commit msg (#2)",
382+
);
383+
write_commit_file(&repo, "foo", "b", "commit3");
384+
385+
let log_filter = filter_commit_by_search(LogFilterSearch {
386+
options: FilterSearchOptions::MESSAGE,
387+
matcher: SkimMatcherV2::default(),
388+
search_pattern: String::from("my msg"),
389+
});
390+
391+
let mut items = Vec::new();
392+
let mut walker = LogWalker::new(&repo, 100)
393+
.unwrap()
394+
.filter(Some(log_filter));
395+
walker.read(&mut items).unwrap();
396+
397+
assert_eq!(items.len(), 1);
398+
assert_eq!(items[0], second_commit_id);
399+
400+
let log_filter = filter_commit_by_search(LogFilterSearch {
401+
options: FilterSearchOptions::FILENAMES,
402+
matcher: SkimMatcherV2::default(),
403+
search_pattern: String::from("fo"),
404+
});
405+
406+
let mut items = Vec::new();
407+
let mut walker = LogWalker::new(&repo, 100)
408+
.unwrap()
409+
.filter(Some(log_filter));
410+
walker.read(&mut items).unwrap();
411+
412+
assert_eq!(items.len(), 2);
413+
}
249414
}

asyncgit/src/sync/mod.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,10 @@ pub use hooks::{
6363
};
6464
pub use hunks::{reset_hunk, stage_hunk, unstage_hunk};
6565
pub use ignore::add_to_ignore;
66-
pub use logwalker::{diff_contains_file, LogWalker, LogWalkerFilter};
66+
pub use logwalker::{
67+
diff_contains_file, filter_commit_by_search, FilterSearchOptions,
68+
LogFilterSearch, LogWalker, LogWalkerFilter,
69+
};
6770
pub use merge::{
6871
abort_pending_rebase, abort_pending_state,
6972
continue_pending_rebase, merge_branch, merge_commit, merge_msg,

0 commit comments

Comments
 (0)