Skip to content

Commit

Permalink
lib: add case_sensitive option to some revsets
Browse files Browse the repository at this point in the history
Add support for case‐insensitive matching to `description(pattern)`,
`author(pattern)`, and `committer(pattern)`, partially resolving
a 1.5‐year‐old TODO comment, and make `mine()` use it
unconditionally.

Case‐insensitivity is on by default; a casual search for commit names
or descriptions is unlikely to care about specific case distinctions,
the domain part of email addresses is de jure case‐insensitive,
and the local‐part is case‐insensitive in practice too. This
could be changed at a later date if it turns out to be undesirable
default for any of these functions (`description("FIXME")`?).

This currently only handles ASCII case folding, due to the complexities
of case‐insensitive Unicode comparison and the `glob` crate’s lack
of support for it. This is unlikely to matter for email addresses,
which very rarely contain non‐ASCII characters, but is unfortunate
for names and descriptions. However, the current matching behaviour is
already seriously deficient for non‐ASCII text due to the lack of any
normalization, so this hopefully shouldn’t be a blocker to adding the
interface. An expository comment has been left in the code for anyone
who wants to try and address this (perhaps a future version of myself).
  • Loading branch information
emilazy committed Jun 29, 2024
1 parent e21e5e6 commit c552f69
Show file tree
Hide file tree
Showing 6 changed files with 421 additions and 75 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
move` to ensure that the target branch already exists.
[#3584](https://github.com/martinvonz/jj/issues/3584)

* The `description(pattern)`, `author(pattern)` and `committer(pattern)` revsets
now match case‐insensitively by default; to override this, pass
`case_sensitive=true`. `mine()` uses case‐insensitive matching
unconditionally. Only ASCII case folding is currently implemented, but this
will likely change in the future.

### Deprecations

* Replacing `-l` shorthand for `--limit` with `-n` in `jj log`, `jj op log` and `jj obslog`.
Expand Down
12 changes: 6 additions & 6 deletions docs/revsets.md
Original file line number Diff line number Diff line change
Expand Up @@ -245,17 +245,17 @@ revsets (expressions) as arguments.

* `merges()`: Merge commits.

* `description(pattern)`: Commits that have a description matching the given
[string pattern](#string-patterns).
* `description(pattern, [case_sensitive=false])`: Commits that have a
description matching the given [string pattern](#string-patterns).

* `author(pattern)`: Commits with the author's name or email matching the given
[string pattern](#string-patterns).
* `author(pattern, [case_sensitive=false])`: Commits with the author's name or
email matching the given [string pattern](#string-patterns).

* `mine()`: Commits where the author's email matches the email of the current
user.

* `committer(pattern)`: Commits with the committer's name or email matching the
given [string pattern](#string-patterns).
* `committer(pattern, [case_sensitive=false])`: Commits with the committer's
name or email matching the given [string pattern](#string-patterns).

* `empty()`: Commits modifying no files. This also includes `merges()` without
user modifications and `root()`.
Expand Down
21 changes: 12 additions & 9 deletions lib/src/default_index/revset_engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1041,32 +1041,35 @@ fn build_predicate_fn(
parent_count_range.contains(&entry.num_parents())
})
}
RevsetFilterPredicate::Description(pattern) => {
RevsetFilterPredicate::Description(pattern, case_sensitivity) => {
let pattern = pattern.clone();
let &case_sensitivity = case_sensitivity;
box_pure_predicate_fn(move |index, pos| {
let entry = index.entry_by_pos(pos);
let commit = store.get_commit(&entry.commit_id()).unwrap();
pattern.matches(commit.description())
pattern.matches_with(commit.description(), case_sensitivity)
})
}
RevsetFilterPredicate::Author(pattern) => {
RevsetFilterPredicate::Author(pattern, case_sensitivity) => {
let pattern = pattern.clone();
let &case_sensitivity = case_sensitivity;
// 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
// case-sensitive.
// syntax for specifying whether it's a regex.
box_pure_predicate_fn(move |index, pos| {
let entry = index.entry_by_pos(pos);
let commit = store.get_commit(&entry.commit_id()).unwrap();
pattern.matches(&commit.author().name) || pattern.matches(&commit.author().email)
pattern.matches_with(&commit.author().name, case_sensitivity)
|| pattern.matches_with(&commit.author().email, case_sensitivity)
})
}
RevsetFilterPredicate::Committer(pattern) => {
RevsetFilterPredicate::Committer(pattern, case_sensitivity) => {
let pattern = pattern.clone();
let &case_sensitivity = case_sensitivity;
box_pure_predicate_fn(move |index, pos| {
let entry = index.entry_by_pos(pos);
let commit = store.get_commit(&entry.commit_id()).unwrap();
pattern.matches(&commit.committer().name)
|| pattern.matches(&commit.committer().email)
pattern.matches_with(&commit.committer().name, case_sensitivity)
|| pattern.matches_with(&commit.committer().email, case_sensitivity)
})
}
RevsetFilterPredicate::File(expr) => {
Expand Down
Loading

0 comments on commit c552f69

Please sign in to comment.