forked from mirrors/jj
revset: unify FilterRevset variants at RevsetExpression level
This helps to match '(filter, _) | (_, filter)' to rewrite the expression tree. Only one predicate is allowed for now, but I think it can be extended to internalize 'f(c) & g(c)' as '(g*f)(c)' to eliminate redundant lookup of commit object.
This commit is contained in:
parent
030e0069f6
commit
4337a997cf
1 changed files with 91 additions and 104 deletions
|
@ -205,6 +205,15 @@ pub enum RevsetParseError {
|
||||||
InvalidFunctionArguments { name: String, message: String },
|
InvalidFunctionArguments { name: String, message: String },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
pub enum RevsetFilterPredicate {
|
||||||
|
ParentCount(Range<u32>),
|
||||||
|
Description(String),
|
||||||
|
Author(String), // Matches against both name and email
|
||||||
|
Committer(String), // Matches against both name and email
|
||||||
|
File(String),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
pub enum RevsetExpression {
|
pub enum RevsetExpression {
|
||||||
None,
|
None,
|
||||||
|
@ -232,27 +241,9 @@ pub enum RevsetExpression {
|
||||||
Tags,
|
Tags,
|
||||||
GitRefs,
|
GitRefs,
|
||||||
GitHead,
|
GitHead,
|
||||||
ParentCount {
|
Filter {
|
||||||
candidates: Rc<RevsetExpression>,
|
|
||||||
parent_count_range: Range<u32>,
|
|
||||||
},
|
|
||||||
Description {
|
|
||||||
needle: String,
|
|
||||||
candidates: Rc<RevsetExpression>,
|
|
||||||
},
|
|
||||||
Author {
|
|
||||||
// Matches against both name and email
|
|
||||||
needle: String,
|
|
||||||
candidates: Rc<RevsetExpression>,
|
|
||||||
},
|
|
||||||
Committer {
|
|
||||||
// Matches against both name and email
|
|
||||||
needle: String,
|
|
||||||
candidates: Rc<RevsetExpression>,
|
|
||||||
},
|
|
||||||
File {
|
|
||||||
pattern: String,
|
|
||||||
candidates: Rc<RevsetExpression>,
|
candidates: Rc<RevsetExpression>,
|
||||||
|
predicate: RevsetFilterPredicate,
|
||||||
},
|
},
|
||||||
Union(Rc<RevsetExpression>, Rc<RevsetExpression>),
|
Union(Rc<RevsetExpression>, Rc<RevsetExpression>),
|
||||||
Intersection(Rc<RevsetExpression>, Rc<RevsetExpression>),
|
Intersection(Rc<RevsetExpression>, Rc<RevsetExpression>),
|
||||||
|
@ -372,41 +363,41 @@ impl RevsetExpression {
|
||||||
self: &Rc<RevsetExpression>,
|
self: &Rc<RevsetExpression>,
|
||||||
parent_count_range: Range<u32>,
|
parent_count_range: Range<u32>,
|
||||||
) -> Rc<RevsetExpression> {
|
) -> Rc<RevsetExpression> {
|
||||||
Rc::new(RevsetExpression::ParentCount {
|
Rc::new(RevsetExpression::Filter {
|
||||||
candidates: self.clone(),
|
candidates: self.clone(),
|
||||||
parent_count_range,
|
predicate: RevsetFilterPredicate::ParentCount(parent_count_range),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Commits in `self` with description containing `needle`.
|
/// Commits in `self` with description containing `needle`.
|
||||||
pub fn with_description(self: &Rc<RevsetExpression>, needle: String) -> Rc<RevsetExpression> {
|
pub fn with_description(self: &Rc<RevsetExpression>, needle: String) -> Rc<RevsetExpression> {
|
||||||
Rc::new(RevsetExpression::Description {
|
Rc::new(RevsetExpression::Filter {
|
||||||
candidates: self.clone(),
|
candidates: self.clone(),
|
||||||
needle,
|
predicate: RevsetFilterPredicate::Description(needle),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Commits in `self` with author's name or email containing `needle`.
|
/// Commits in `self` with author's name or email containing `needle`.
|
||||||
pub fn with_author(self: &Rc<RevsetExpression>, needle: String) -> Rc<RevsetExpression> {
|
pub fn with_author(self: &Rc<RevsetExpression>, needle: String) -> Rc<RevsetExpression> {
|
||||||
Rc::new(RevsetExpression::Author {
|
Rc::new(RevsetExpression::Filter {
|
||||||
candidates: self.clone(),
|
candidates: self.clone(),
|
||||||
needle,
|
predicate: RevsetFilterPredicate::Author(needle),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Commits in `self` with committer's name or email containing `needle`.
|
/// Commits in `self` with committer's name or email containing `needle`.
|
||||||
pub fn with_committer(self: &Rc<RevsetExpression>, needle: String) -> Rc<RevsetExpression> {
|
pub fn with_committer(self: &Rc<RevsetExpression>, needle: String) -> Rc<RevsetExpression> {
|
||||||
Rc::new(RevsetExpression::Committer {
|
Rc::new(RevsetExpression::Filter {
|
||||||
candidates: self.clone(),
|
candidates: self.clone(),
|
||||||
needle,
|
predicate: RevsetFilterPredicate::Committer(needle),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Commits in `self` modifying the paths specified by the `pattern`.
|
/// Commits in `self` modifying the paths specified by the `pattern`.
|
||||||
pub fn with_file(self: &Rc<RevsetExpression>, pattern: String) -> Rc<RevsetExpression> {
|
pub fn with_file(self: &Rc<RevsetExpression>, pattern: String) -> Rc<RevsetExpression> {
|
||||||
Rc::new(RevsetExpression::File {
|
Rc::new(RevsetExpression::Filter {
|
||||||
candidates: self.clone(),
|
candidates: self.clone(),
|
||||||
pattern,
|
predicate: RevsetFilterPredicate::File(pattern),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1304,20 +1295,22 @@ pub fn evaluate_expression<'repo>(
|
||||||
let commit_ids = repo.view().git_head().into_iter().collect_vec();
|
let commit_ids = repo.view().git_head().into_iter().collect_vec();
|
||||||
Ok(revset_for_commit_ids(repo, &commit_ids))
|
Ok(revset_for_commit_ids(repo, &commit_ids))
|
||||||
}
|
}
|
||||||
RevsetExpression::ParentCount {
|
RevsetExpression::Filter {
|
||||||
candidates,
|
candidates,
|
||||||
parent_count_range,
|
predicate,
|
||||||
} => {
|
} => {
|
||||||
let candidates = candidates.evaluate(repo, workspace_ctx)?;
|
let candidates = candidates.evaluate(repo, workspace_ctx)?;
|
||||||
|
match predicate {
|
||||||
|
RevsetFilterPredicate::ParentCount(parent_count_range) => {
|
||||||
let parent_count_range = parent_count_range.clone();
|
let parent_count_range = parent_count_range.clone();
|
||||||
Ok(Box::new(FilterRevset {
|
Ok(Box::new(FilterRevset {
|
||||||
candidates,
|
candidates,
|
||||||
predicate: Box::new(move |entry| parent_count_range.contains(&entry.num_parents())),
|
predicate: Box::new(move |entry| {
|
||||||
|
parent_count_range.contains(&entry.num_parents())
|
||||||
|
}),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
RevsetExpression::Description { needle, candidates } => {
|
RevsetFilterPredicate::Description(needle) => {
|
||||||
let candidates = candidates.evaluate(repo, workspace_ctx)?;
|
|
||||||
let repo = repo;
|
|
||||||
let needle = needle.clone();
|
let needle = needle.clone();
|
||||||
Ok(Box::new(FilterRevset {
|
Ok(Box::new(FilterRevset {
|
||||||
candidates,
|
candidates,
|
||||||
|
@ -1330,9 +1323,7 @@ pub fn evaluate_expression<'repo>(
|
||||||
}),
|
}),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
RevsetExpression::Author { needle, candidates } => {
|
RevsetFilterPredicate::Author(needle) => {
|
||||||
let candidates = candidates.evaluate(repo, workspace_ctx)?;
|
|
||||||
let repo = repo;
|
|
||||||
let needle = needle.clone();
|
let needle = needle.clone();
|
||||||
// TODO: Make these functions that take a needle to search for accept some
|
// TODO: Make these functions that take a needle to search for accept some
|
||||||
// syntax for specifying whether it's a regex and whether it's
|
// syntax for specifying whether it's a regex and whether it's
|
||||||
|
@ -1346,9 +1337,7 @@ pub fn evaluate_expression<'repo>(
|
||||||
}),
|
}),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
RevsetExpression::Committer { needle, candidates } => {
|
RevsetFilterPredicate::Committer(needle) => {
|
||||||
let candidates = candidates.evaluate(repo, workspace_ctx)?;
|
|
||||||
let repo = repo;
|
|
||||||
let needle = needle.clone();
|
let needle = needle.clone();
|
||||||
Ok(Box::new(FilterRevset {
|
Ok(Box::new(FilterRevset {
|
||||||
candidates,
|
candidates,
|
||||||
|
@ -1359,20 +1348,18 @@ pub fn evaluate_expression<'repo>(
|
||||||
}),
|
}),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
RevsetExpression::File {
|
RevsetFilterPredicate::File(pattern) => {
|
||||||
pattern,
|
|
||||||
candidates,
|
|
||||||
} => {
|
|
||||||
if let Some(ctx) = workspace_ctx {
|
if let Some(ctx) = workspace_ctx {
|
||||||
// TODO: Add support for globs and other formats
|
// TODO: Add support for globs and other formats
|
||||||
let path = RepoPath::parse_fs_path(ctx.cwd, ctx.workspace_root, pattern)?;
|
let path = RepoPath::parse_fs_path(ctx.cwd, ctx.workspace_root, pattern)?;
|
||||||
let matcher: Box<dyn Matcher> = Box::new(PrefixMatcher::new(&[path]));
|
let matcher: Box<dyn Matcher> = Box::new(PrefixMatcher::new(&[path]));
|
||||||
let candidates = candidates.evaluate(repo, workspace_ctx)?;
|
|
||||||
Ok(filter_by_diff(repo, matcher, candidates))
|
Ok(filter_by_diff(repo, matcher, candidates))
|
||||||
} else {
|
} else {
|
||||||
Err(RevsetError::FsPathWithoutWorkspace)
|
Err(RevsetError::FsPathWithoutWorkspace)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
RevsetExpression::Union(expression1, expression2) => {
|
RevsetExpression::Union(expression1, expression2) => {
|
||||||
let set1 = expression1.evaluate(repo, workspace_ctx)?;
|
let set1 = expression1.evaluate(repo, workspace_ctx)?;
|
||||||
let set2 = expression2.evaluate(repo, workspace_ctx)?;
|
let set2 = expression2.evaluate(repo, workspace_ctx)?;
|
||||||
|
@ -1499,37 +1486,37 @@ mod tests {
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
foo_symbol.with_parent_count(3..5),
|
foo_symbol.with_parent_count(3..5),
|
||||||
Rc::new(RevsetExpression::ParentCount {
|
Rc::new(RevsetExpression::Filter {
|
||||||
candidates: foo_symbol.clone(),
|
candidates: foo_symbol.clone(),
|
||||||
parent_count_range: 3..5
|
predicate: RevsetFilterPredicate::ParentCount(3..5),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
foo_symbol.with_description("needle".to_string()),
|
foo_symbol.with_description("needle".to_string()),
|
||||||
Rc::new(RevsetExpression::Description {
|
Rc::new(RevsetExpression::Filter {
|
||||||
candidates: foo_symbol.clone(),
|
candidates: foo_symbol.clone(),
|
||||||
needle: "needle".to_string()
|
predicate: RevsetFilterPredicate::Description("needle".to_string()),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
foo_symbol.with_author("needle".to_string()),
|
foo_symbol.with_author("needle".to_string()),
|
||||||
Rc::new(RevsetExpression::Author {
|
Rc::new(RevsetExpression::Filter {
|
||||||
candidates: foo_symbol.clone(),
|
candidates: foo_symbol.clone(),
|
||||||
needle: "needle".to_string()
|
predicate: RevsetFilterPredicate::Author("needle".to_string()),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
foo_symbol.with_committer("needle".to_string()),
|
foo_symbol.with_committer("needle".to_string()),
|
||||||
Rc::new(RevsetExpression::Committer {
|
Rc::new(RevsetExpression::Filter {
|
||||||
candidates: foo_symbol.clone(),
|
candidates: foo_symbol.clone(),
|
||||||
needle: "needle".to_string()
|
predicate: RevsetFilterPredicate::Committer("needle".to_string()),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
foo_symbol.with_file("pattern".to_string()),
|
foo_symbol.with_file("pattern".to_string()),
|
||||||
Rc::new(RevsetExpression::File {
|
Rc::new(RevsetExpression::Filter {
|
||||||
candidates: foo_symbol.clone(),
|
candidates: foo_symbol.clone(),
|
||||||
pattern: "pattern".to_string(),
|
predicate: RevsetFilterPredicate::File("pattern".to_string()),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
Loading…
Reference in a new issue