forked from mirrors/jj
revset: rename literal:"" prefix to exact:""
Per discussion in #2107, I believe "exact" is preferred. We can also change the default to exact match, but it doesn't always make sense. Exact match would be useful for branches(), but not for description(). We could define default per predicate function, but I'm pretty sure I cannot remember which one is which.
This commit is contained in:
parent
ebdc22a65e
commit
b6794ca04a
4 changed files with 29 additions and 38 deletions
|
@ -82,11 +82,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
description was empty on the input commit.
|
||||
|
||||
* `branches()`/`remote_branches()`/`author()`/`committer()`/`description()`
|
||||
revsets now support literal matching. For example, `branch(literal:main)`
|
||||
selects the branch named "main", but not "maint". `description(literal:"")`
|
||||
revsets now support exact matching. For example, `branch(exact:main)`
|
||||
selects the branch named "main", but not "maint". `description(exact:"")`
|
||||
selects commits whose description is empty.
|
||||
|
||||
* Revsets gained a new function `mine()` that aliases `author([literal:"your_email"])`.
|
||||
* Revsets gained a new function `mine()` that aliases `author(exact:"your_email")`.
|
||||
|
||||
### Fixed bugs
|
||||
|
||||
|
|
|
@ -142,7 +142,7 @@ revsets (expressions) as arguments.
|
|||
Functions that perform string matching support the following pattern syntax.
|
||||
|
||||
* `"string"`, `substring:"string"`: Matches strings that contain `string`.
|
||||
* `literal:"string"`: Matches strings exactly equal to `string`.
|
||||
* `exact:"string"`: Matches strings exactly equal to `string`.
|
||||
|
||||
## Aliases
|
||||
|
||||
|
|
|
@ -212,7 +212,7 @@ pub const GENERATION_RANGE_EMPTY: Range<u64> = 0..0;
|
|||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub enum StringPattern {
|
||||
/// Matches strings exactly equal to `string`.
|
||||
Literal(String),
|
||||
Exact(String),
|
||||
/// Matches strings that contain `substring`.
|
||||
Substring(String),
|
||||
}
|
||||
|
@ -226,17 +226,17 @@ impl StringPattern {
|
|||
/// Returns true if this pattern matches the `haystack`.
|
||||
pub fn matches(&self, haystack: &str) -> bool {
|
||||
match self {
|
||||
StringPattern::Literal(literal) => haystack == literal,
|
||||
StringPattern::Exact(literal) => haystack == literal,
|
||||
StringPattern::Substring(needle) => haystack.contains(needle),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a literal string if this pattern is of that kind.
|
||||
/// Returns a literal pattern if this should match input strings exactly.
|
||||
///
|
||||
/// This can be used to optimize map lookup by exact key.
|
||||
pub fn as_literal(&self) -> Option<&str> {
|
||||
pub fn as_exact(&self) -> Option<&str> {
|
||||
match self {
|
||||
StringPattern::Literal(literal) => Some(literal),
|
||||
StringPattern::Exact(literal) => Some(literal),
|
||||
StringPattern::Substring(_) => None,
|
||||
}
|
||||
}
|
||||
|
@ -1093,7 +1093,7 @@ static BUILTIN_FUNCTION_MAP: Lazy<HashMap<&'static str, RevsetFunction>> = Lazy:
|
|||
map.insert("mine", |name, arguments_pair, state| {
|
||||
expect_no_arguments(name, arguments_pair)?;
|
||||
Ok(RevsetExpression::filter(RevsetFilterPredicate::Author(
|
||||
StringPattern::Literal(state.user_email.to_owned()),
|
||||
StringPattern::Exact(state.user_email.to_owned()),
|
||||
)))
|
||||
});
|
||||
map.insert("committer", |name, arguments_pair, state| {
|
||||
|
@ -1323,7 +1323,7 @@ fn parse_function_argument_to_string_pattern(
|
|||
return Err(make_type_error());
|
||||
};
|
||||
match kind.as_ref() {
|
||||
"literal" => StringPattern::Literal(needle.clone()),
|
||||
"exact" => StringPattern::Exact(needle.clone()),
|
||||
"substring" => StringPattern::Substring(needle.clone()),
|
||||
_ => {
|
||||
// TODO: error span can be narrowed to the lhs node
|
||||
|
@ -1796,7 +1796,7 @@ fn filter_map_values_by_key_pattern<'a: 'b, 'b, V>(
|
|||
map: &'a BTreeMap<String, V>,
|
||||
pattern: &'b StringPattern,
|
||||
) -> impl Iterator<Item = &'a V> + 'b {
|
||||
if let Some(key) = pattern.as_literal() {
|
||||
if let Some(key) = pattern.as_exact() {
|
||||
Either::Left(map.get(key).into_iter())
|
||||
} else {
|
||||
Either::Right(
|
||||
|
@ -2694,8 +2694,8 @@ mod tests {
|
|||
)))
|
||||
);
|
||||
assert_eq!(
|
||||
parse(r#"branches(literal:"foo")"#),
|
||||
Ok(RevsetExpression::branches(StringPattern::Literal(
|
||||
parse(r#"branches(exact:"foo")"#),
|
||||
Ok(RevsetExpression::branches(StringPattern::Exact(
|
||||
"foo".to_owned()
|
||||
)))
|
||||
);
|
||||
|
@ -2706,9 +2706,9 @@ mod tests {
|
|||
)))
|
||||
);
|
||||
assert_eq!(
|
||||
parse(r#"branches("literal:foo")"#),
|
||||
parse(r#"branches("exact:foo")"#),
|
||||
Ok(RevsetExpression::branches(StringPattern::Substring(
|
||||
"literal:foo".to_owned()
|
||||
"exact:foo".to_owned()
|
||||
)))
|
||||
);
|
||||
assert_eq!(
|
||||
|
@ -2719,7 +2719,7 @@ mod tests {
|
|||
})
|
||||
);
|
||||
assert_eq!(
|
||||
parse(r#"branches(literal::"foo")"#),
|
||||
parse(r#"branches(exact::"foo")"#),
|
||||
Err(RevsetParseErrorKind::InvalidFunctionArguments {
|
||||
name: "branches".to_owned(),
|
||||
message: "Expected function argument of string pattern".to_owned()
|
||||
|
@ -2868,7 +2868,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
parse("mine()"),
|
||||
Ok(RevsetExpression::filter(RevsetFilterPredicate::Author(
|
||||
StringPattern::Literal("test.user@example.com".to_string())
|
||||
StringPattern::Exact("test.user@example.com".to_string())
|
||||
)))
|
||||
);
|
||||
assert_eq!(
|
||||
|
@ -2974,12 +2974,12 @@ mod tests {
|
|||
parse("author(a)").unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
parse_with_aliases("author(A)", [("A", "literal:a")]).unwrap(),
|
||||
parse("author(literal:a)").unwrap()
|
||||
parse_with_aliases("author(A)", [("A", "exact:a")]).unwrap(),
|
||||
parse("author(exact:a)").unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
parse_with_aliases("author(literal:A)", [("A", "a")]).unwrap(),
|
||||
parse("author(literal:a)").unwrap()
|
||||
parse_with_aliases("author(exact:A)", [("A", "a")]).unwrap(),
|
||||
parse("author(exact:a)").unwrap()
|
||||
);
|
||||
|
||||
// Multi-level substitution.
|
||||
|
|
|
@ -1717,13 +1717,13 @@ fn test_evaluate_expression_branches(use_git: bool) {
|
|||
vec![commit2.id().clone(), commit1.id().clone()]
|
||||
);
|
||||
assert_eq!(
|
||||
resolve_commit_ids(mut_repo, "branches(literal:branch1)"),
|
||||
resolve_commit_ids(mut_repo, "branches(exact:branch1)"),
|
||||
vec![commit1.id().clone()]
|
||||
);
|
||||
// Can silently resolve to an empty set if there's no matches
|
||||
assert_eq!(resolve_commit_ids(mut_repo, "branches(branch3)"), vec![]);
|
||||
assert_eq!(
|
||||
resolve_commit_ids(mut_repo, "branches(literal:ranch1)"),
|
||||
resolve_commit_ids(mut_repo, "branches(exact:ranch1)"),
|
||||
vec![]
|
||||
);
|
||||
// Two branches pointing to the same commit does not result in a duplicate in
|
||||
|
@ -1797,7 +1797,7 @@ fn test_evaluate_expression_remote_branches(use_git: bool) {
|
|||
vec![commit2.id().clone(), commit1.id().clone()]
|
||||
);
|
||||
assert_eq!(
|
||||
resolve_commit_ids(mut_repo, "remote_branches(literal:branch1)"),
|
||||
resolve_commit_ids(mut_repo, "remote_branches(exact:branch1)"),
|
||||
vec![commit1.id().clone()]
|
||||
);
|
||||
// Can get branches from matching remotes
|
||||
|
@ -1810,7 +1810,7 @@ fn test_evaluate_expression_remote_branches(use_git: bool) {
|
|||
vec![commit2.id().clone(), commit1.id().clone()]
|
||||
);
|
||||
assert_eq!(
|
||||
resolve_commit_ids(mut_repo, r#"remote_branches("", literal:origin)"#),
|
||||
resolve_commit_ids(mut_repo, r#"remote_branches("", exact:origin)"#),
|
||||
vec![commit1.id().clone()]
|
||||
);
|
||||
// Can get branches with matching names from matching remotes
|
||||
|
@ -1823,10 +1823,7 @@ fn test_evaluate_expression_remote_branches(use_git: bool) {
|
|||
vec![commit2.id().clone()]
|
||||
);
|
||||
assert_eq!(
|
||||
resolve_commit_ids(
|
||||
mut_repo,
|
||||
r#"remote_branches(literal:branch1, literal:origin)"#
|
||||
),
|
||||
resolve_commit_ids(mut_repo, r#"remote_branches(exact:branch1, exact:origin)"#),
|
||||
vec![commit1.id().clone()]
|
||||
);
|
||||
// Can silently resolve to an empty set if there's no matches
|
||||
|
@ -1843,17 +1840,11 @@ fn test_evaluate_expression_remote_branches(use_git: bool) {
|
|||
vec![]
|
||||
);
|
||||
assert_eq!(
|
||||
resolve_commit_ids(
|
||||
mut_repo,
|
||||
r#"remote_branches(literal:ranch1, literal:origin)"#
|
||||
),
|
||||
resolve_commit_ids(mut_repo, r#"remote_branches(exact:ranch1, exact:origin)"#),
|
||||
vec![]
|
||||
);
|
||||
assert_eq!(
|
||||
resolve_commit_ids(
|
||||
mut_repo,
|
||||
r#"remote_branches(literal:branch1, literal:orig)"#
|
||||
),
|
||||
resolve_commit_ids(mut_repo, r#"remote_branches(exact:branch1, exact:orig)"#),
|
||||
vec![]
|
||||
);
|
||||
// Two branches pointing to the same commit does not result in a duplicate in
|
||||
|
|
Loading…
Reference in a new issue