mirror of
https://github.com/martinvonz/jj.git
synced 2025-02-12 07:24:11 +00:00
revset: resolve file path at parse() stage
Baby step towards embedding matcher in RevsetExpression. If we had a fileset language or regex pattern, we would probably want to parse it at this stage so the syntax error can be reported without evaluation.
This commit is contained in:
parent
78c0cf81bf
commit
fba6741c23
1 changed files with 38 additions and 19 deletions
|
@ -46,10 +46,6 @@ pub enum RevsetError {
|
||||||
AmbiguousCommitIdPrefix(String),
|
AmbiguousCommitIdPrefix(String),
|
||||||
#[error("Change id prefix \"{0}\" is ambiguous")]
|
#[error("Change id prefix \"{0}\" is ambiguous")]
|
||||||
AmbiguousChangeIdPrefix(String),
|
AmbiguousChangeIdPrefix(String),
|
||||||
#[error("Invalid file pattern: {0}")]
|
|
||||||
FsPathParseError(#[from] FsPathParseError),
|
|
||||||
#[error("Cannot resolve file pattern without workspace")]
|
|
||||||
FsPathWithoutWorkspace,
|
|
||||||
#[error("Unexpected error from store: {0}")]
|
#[error("Unexpected error from store: {0}")]
|
||||||
StoreError(#[from] BackendError),
|
StoreError(#[from] BackendError),
|
||||||
}
|
}
|
||||||
|
@ -203,6 +199,10 @@ pub enum RevsetParseError {
|
||||||
NoSuchFunction(String),
|
NoSuchFunction(String),
|
||||||
#[error("Invalid arguments to revset function \"{name}\": {message}")]
|
#[error("Invalid arguments to revset function \"{name}\": {message}")]
|
||||||
InvalidFunctionArguments { name: String, message: String },
|
InvalidFunctionArguments { name: String, message: String },
|
||||||
|
#[error("Invalid file pattern: {0}")]
|
||||||
|
FsPathParseError(#[from] FsPathParseError),
|
||||||
|
#[error("Cannot resolve file pattern without workspace")]
|
||||||
|
FsPathWithoutWorkspace,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
@ -211,7 +211,7 @@ pub enum RevsetFilterPredicate {
|
||||||
Description(String),
|
Description(String),
|
||||||
Author(String), // Matches against both name and email
|
Author(String), // Matches against both name and email
|
||||||
Committer(String), // Matches against both name and email
|
Committer(String), // Matches against both name and email
|
||||||
File(String),
|
File(RepoPath),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
|
@ -395,7 +395,7 @@ impl RevsetExpression {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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: RepoPath) -> Rc<RevsetExpression> {
|
||||||
Rc::new(RevsetExpression::Filter {
|
Rc::new(RevsetExpression::Filter {
|
||||||
candidates: self.clone(),
|
candidates: self.clone(),
|
||||||
predicate: RevsetFilterPredicate::File(pattern),
|
predicate: RevsetFilterPredicate::File(pattern),
|
||||||
|
@ -786,7 +786,7 @@ fn parse_function_expression(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"description" | "author" | "committer" | "file" => {
|
"description" | "author" | "committer" => {
|
||||||
if arg_count != 1 {
|
if arg_count != 1 {
|
||||||
return Err(RevsetParseError::InvalidFunctionArguments {
|
return Err(RevsetParseError::InvalidFunctionArguments {
|
||||||
name,
|
name,
|
||||||
|
@ -802,12 +802,29 @@ fn parse_function_expression(
|
||||||
"description" => Ok(candidates.with_description(needle)),
|
"description" => Ok(candidates.with_description(needle)),
|
||||||
"author" => Ok(candidates.with_author(needle)),
|
"author" => Ok(candidates.with_author(needle)),
|
||||||
"committer" => Ok(candidates.with_committer(needle)),
|
"committer" => Ok(candidates.with_committer(needle)),
|
||||||
"file" => Ok(candidates.with_file(needle)),
|
|
||||||
_ => {
|
_ => {
|
||||||
panic!("unexpected function name: {}", name)
|
panic!("unexpected function name: {}", name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
"file" => {
|
||||||
|
if arg_count != 1 {
|
||||||
|
return Err(RevsetParseError::InvalidFunctionArguments {
|
||||||
|
name,
|
||||||
|
message: "Expected 1 argument".to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if let Some(ctx) = workspace_ctx {
|
||||||
|
let needle = parse_function_argument_to_string(
|
||||||
|
&name,
|
||||||
|
argument_pairs.next().unwrap().into_inner(),
|
||||||
|
)?;
|
||||||
|
let path = RepoPath::parse_fs_path(ctx.cwd, ctx.workspace_root, &needle)?;
|
||||||
|
Ok(RevsetExpression::all().with_file(path))
|
||||||
|
} else {
|
||||||
|
Err(RevsetParseError::FsPathWithoutWorkspace)
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => Err(RevsetParseError::NoSuchFunction(name)),
|
_ => Err(RevsetParseError::NoSuchFunction(name)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1565,14 +1582,10 @@ pub fn evaluate_expression<'repo>(
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
RevsetFilterPredicate::File(pattern) => {
|
RevsetFilterPredicate::File(pattern) => {
|
||||||
if let Some(ctx) = workspace_ctx {
|
// TODO: Add support for globs and other formats
|
||||||
// TODO: Add support for globs and other formats
|
let matcher: Box<dyn Matcher> =
|
||||||
let path = RepoPath::parse_fs_path(ctx.cwd, ctx.workspace_root, pattern)?;
|
Box::new(PrefixMatcher::new(std::slice::from_ref(pattern)));
|
||||||
let matcher: Box<dyn Matcher> = Box::new(PrefixMatcher::new(&[path]));
|
Ok(filter_by_diff(repo, matcher, candidates))
|
||||||
Ok(filter_by_diff(repo, matcher, candidates))
|
|
||||||
} else {
|
|
||||||
Err(RevsetError::FsPathWithoutWorkspace)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1645,7 +1658,13 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
fn parse(revset_str: &str) -> Result<Rc<RevsetExpression>, RevsetParseError> {
|
fn parse(revset_str: &str) -> Result<Rc<RevsetExpression>, RevsetParseError> {
|
||||||
super::parse(revset_str, None)
|
// Set up pseudo context to resolve file(path)
|
||||||
|
let workspace_ctx = RevsetWorkspaceContext {
|
||||||
|
cwd: Path::new("/"),
|
||||||
|
workspace_id: &WorkspaceId::default(),
|
||||||
|
workspace_root: Path::new("/"),
|
||||||
|
};
|
||||||
|
super::parse(revset_str, Some(&workspace_ctx))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1733,10 +1752,10 @@ mod tests {
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
foo_symbol.with_file("pattern".to_string()),
|
foo_symbol.with_file(RepoPath::from_internal_string("pattern")),
|
||||||
Rc::new(RevsetExpression::Filter {
|
Rc::new(RevsetExpression::Filter {
|
||||||
candidates: foo_symbol.clone(),
|
candidates: foo_symbol.clone(),
|
||||||
predicate: RevsetFilterPredicate::File("pattern".to_string()),
|
predicate: RevsetFilterPredicate::File(RepoPath::from_internal_string("pattern")),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
Loading…
Reference in a new issue