forked from mirrors/jj
cli: if enabled, parse path arguments as fileset expressions
If this doesn't work out, maybe we can try one of these: a. fall back to bare file name if expression doesn't contain any operator-like characters (e.g. "f(x" is an error, but "f x" can be parsed as bare string) b. introduce command-line flag to opt in (e.g. -e FILESET) c. introduce pattern prefix to opt in (e.g. set:FILESET) Closes #3239, #2915, #2286
This commit is contained in:
parent
a9694cba27
commit
30984dae4a
5 changed files with 33 additions and 25 deletions
|
@ -31,8 +31,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
* `jj status` now supports filtering by paths. For example, `jj status .` will
|
||||
only list changed files that are descendants of the current directory.
|
||||
|
||||
* A new config option `ui.allow-filesets` has been added to enable [file pattern
|
||||
syntax](docs/filesets.md#file-patterns).
|
||||
* A new config option `ui.allow-filesets` has been added to enable ["fileset"
|
||||
expressions](docs/filesets.md). Note that filesets are currently experimental,
|
||||
but will be enabled by default in a future release.
|
||||
|
||||
* `jj prev` and `jj next` now work when the working copy revision is a merge.
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ use indexmap::{IndexMap, IndexSet};
|
|||
use itertools::Itertools;
|
||||
use jj_lib::backend::{ChangeId, CommitId, MergedTreeId, TreeValue};
|
||||
use jj_lib::commit::Commit;
|
||||
use jj_lib::fileset::{FilePattern, FilesetExpression, FilesetParseContext};
|
||||
use jj_lib::fileset::{FilesetExpression, FilesetParseContext};
|
||||
use jj_lib::git_backend::GitBackend;
|
||||
use jj_lib::gitignore::{GitIgnoreError, GitIgnoreFile};
|
||||
use jj_lib::hex_util::to_reverse_hex;
|
||||
|
@ -657,14 +657,7 @@ impl WorkspaceCommandHelper {
|
|||
if values.is_empty() {
|
||||
Ok(FilesetExpression::all())
|
||||
} else if self.settings.config().get_bool("ui.allow-filesets")? {
|
||||
let ctx = self.fileset_parse_context();
|
||||
let expressions = values
|
||||
.iter()
|
||||
.map(|v| FilePattern::parse(&ctx, v))
|
||||
.map_ok(FilesetExpression::pattern)
|
||||
.try_collect()
|
||||
.map_err(user_error)?;
|
||||
Ok(FilesetExpression::union_all(expressions))
|
||||
self.parse_union_filesets(values)
|
||||
} else {
|
||||
let expressions = values
|
||||
.iter()
|
||||
|
|
|
@ -825,15 +825,26 @@ fn test_log_filtered_by_path() {
|
|||
// Fileset/pattern syntax is disabled by default.
|
||||
let stderr = test_env.jj_cmd_failure(
|
||||
test_env.env_root(),
|
||||
&["log", "-R", repo_path.to_str().unwrap(), "root:file1"],
|
||||
&["log", "-R", repo_path.to_str().unwrap(), "all()"],
|
||||
);
|
||||
insta::assert_snapshot!(stderr.replace('\\', "/"), @r###"
|
||||
Error: Path "root:file1" is not in the repo "repo"
|
||||
Caused by: Invalid component ".." in repo-relative path "../root:file1"
|
||||
Error: Path "all()" is not in the repo "repo"
|
||||
Caused by: Invalid component ".." in repo-relative path "../all()"
|
||||
"###);
|
||||
|
||||
test_env.add_config("ui.allow-filesets = true");
|
||||
|
||||
// empty revisions are filtered out by "all()" fileset.
|
||||
let stdout = test_env.jj_cmd_success(&repo_path, &["log", "-Tdescription", "-s", "all()"]);
|
||||
insta::assert_snapshot!(stdout, @r###"
|
||||
@ second
|
||||
│ M file1
|
||||
│ A file2
|
||||
◉ first
|
||||
│ A file1
|
||||
~
|
||||
"###);
|
||||
|
||||
// "root:<path>" is resolved relative to the workspace root.
|
||||
let stdout = test_env.jj_cmd_success(
|
||||
test_env.env_root(),
|
||||
|
|
|
@ -42,3 +42,17 @@ You can also specify patterns by using functions.
|
|||
|
||||
* `all()`: Matches everything.
|
||||
* `none()`: Matches nothing.
|
||||
|
||||
## Examples
|
||||
|
||||
Show diff excluding `Cargo.lock`.
|
||||
|
||||
```
|
||||
jj diff '~Cargo.lock'
|
||||
```
|
||||
|
||||
Split a revision in two, putting `foo` into the second commit.
|
||||
|
||||
```
|
||||
jj split '~foo'
|
||||
```
|
||||
|
|
|
@ -60,17 +60,6 @@ pub enum FilePattern {
|
|||
}
|
||||
|
||||
impl FilePattern {
|
||||
/// Parses the given `input` string as a file pattern.
|
||||
// TODO: If we decide to parse any file argument as a fileset expression,
|
||||
// this function can be removed.
|
||||
pub fn parse(ctx: &FilesetParseContext, input: &str) -> Result<Self, FilePatternParseError> {
|
||||
if let Some((kind, pat)) = input.split_once(':') {
|
||||
Self::from_str_kind(ctx, pat, kind)
|
||||
} else {
|
||||
Self::cwd_prefix_path(ctx, input)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parses the given `input` string as pattern of the specified `kind`.
|
||||
pub fn from_str_kind(
|
||||
ctx: &FilesetParseContext,
|
||||
|
|
Loading…
Reference in a new issue