mirror of
https://github.com/martinvonz/jj.git
synced 2025-01-30 16:10:23 +00:00
revset: introduce a trait for resolving symbols
I'd like to make the symbol resolution more flexible, both so we can support customizing it (in custom `jj` binaries) and so we can use it for resolving short prefixes within a small revset.
This commit is contained in:
parent
ac31c83e13
commit
5e7c57c527
1 changed files with 86 additions and 59 deletions
|
@ -436,7 +436,9 @@ impl RevsetExpression {
|
||||||
self: Rc<Self>,
|
self: Rc<Self>,
|
||||||
repo: &dyn Repo,
|
repo: &dyn Repo,
|
||||||
) -> Result<ResolvedExpression, RevsetResolutionError> {
|
) -> Result<ResolvedExpression, RevsetResolutionError> {
|
||||||
resolve_symbols(repo, self, None).map(|expression| resolve_visibility(repo, &expression))
|
let symbol_resolver = DefaultSymbolResolver::new(repo, None);
|
||||||
|
resolve_symbols(repo, self, &symbol_resolver)
|
||||||
|
.map(|expression| resolve_visibility(repo, &expression))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_in_workspace(
|
pub fn resolve_in_workspace(
|
||||||
|
@ -444,7 +446,8 @@ impl RevsetExpression {
|
||||||
repo: &dyn Repo,
|
repo: &dyn Repo,
|
||||||
workspace_ctx: &RevsetWorkspaceContext,
|
workspace_ctx: &RevsetWorkspaceContext,
|
||||||
) -> Result<ResolvedExpression, RevsetResolutionError> {
|
) -> Result<ResolvedExpression, RevsetResolutionError> {
|
||||||
resolve_symbols(repo, self, Some(workspace_ctx))
|
let symbol_resolver = DefaultSymbolResolver::new(repo, Some(workspace_ctx.workspace_id));
|
||||||
|
resolve_symbols(repo, self, &symbol_resolver)
|
||||||
.map(|expression| resolve_visibility(repo, &expression))
|
.map(|expression| resolve_visibility(repo, &expression))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1663,14 +1666,31 @@ fn resolve_change_id(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_symbol(
|
pub trait SymbolResolver {
|
||||||
repo: &dyn Repo,
|
fn resolve_symbol(&self, symbol: &str) -> Result<Vec<CommitId>, RevsetResolutionError>;
|
||||||
symbol: &str,
|
}
|
||||||
workspace_id: Option<&WorkspaceId>,
|
|
||||||
) -> Result<Vec<CommitId>, RevsetResolutionError> {
|
/// Resolves the "root" and "@" symbols, branches, remote branches, tags, git
|
||||||
|
/// refs, and full and abbreviated commit and change ids.
|
||||||
|
pub struct DefaultSymbolResolver<'a> {
|
||||||
|
repo: &'a dyn Repo,
|
||||||
|
workspace_id: Option<&'a WorkspaceId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DefaultSymbolResolver<'_> {
|
||||||
|
pub fn new<'a>(
|
||||||
|
repo: &'a dyn Repo,
|
||||||
|
workspace_id: Option<&'a WorkspaceId>,
|
||||||
|
) -> DefaultSymbolResolver<'a> {
|
||||||
|
DefaultSymbolResolver { repo, workspace_id }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SymbolResolver for DefaultSymbolResolver<'_> {
|
||||||
|
fn resolve_symbol(&self, symbol: &str) -> Result<Vec<CommitId>, RevsetResolutionError> {
|
||||||
if symbol.ends_with('@') {
|
if symbol.ends_with('@') {
|
||||||
let target_workspace = if symbol == "@" {
|
let target_workspace = if symbol == "@" {
|
||||||
if let Some(workspace_id) = workspace_id {
|
if let Some(workspace_id) = self.workspace_id {
|
||||||
workspace_id.clone()
|
workspace_id.clone()
|
||||||
} else {
|
} else {
|
||||||
return Err(RevsetResolutionError::NoSuchRevision(symbol.to_owned()));
|
return Err(RevsetResolutionError::NoSuchRevision(symbol.to_owned()));
|
||||||
|
@ -1678,57 +1698,64 @@ pub fn resolve_symbol(
|
||||||
} else {
|
} else {
|
||||||
WorkspaceId::new(symbol.strip_suffix('@').unwrap().to_string())
|
WorkspaceId::new(symbol.strip_suffix('@').unwrap().to_string())
|
||||||
};
|
};
|
||||||
if let Some(commit_id) = repo.view().get_wc_commit_id(&target_workspace) {
|
if let Some(commit_id) = self.repo.view().get_wc_commit_id(&target_workspace) {
|
||||||
Ok(vec![commit_id.clone()])
|
Ok(vec![commit_id.clone()])
|
||||||
} else {
|
} else {
|
||||||
Err(RevsetResolutionError::NoSuchRevision(symbol.to_owned()))
|
Err(RevsetResolutionError::NoSuchRevision(symbol.to_owned()))
|
||||||
}
|
}
|
||||||
} else if symbol == "root" {
|
} else if symbol == "root" {
|
||||||
Ok(vec![repo.store().root_commit_id().clone()])
|
Ok(vec![self.repo.store().root_commit_id().clone()])
|
||||||
} else {
|
} else {
|
||||||
// Try to resolve as a tag
|
// Try to resolve as a tag
|
||||||
if let Some(target) = repo.view().tags().get(symbol) {
|
if let Some(target) = self.repo.view().tags().get(symbol) {
|
||||||
return Ok(target.adds());
|
return Ok(target.adds());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to resolve as a branch
|
// Try to resolve as a branch
|
||||||
if let Some(ids) = resolve_branch(repo, symbol) {
|
if let Some(ids) = resolve_branch(self.repo, symbol) {
|
||||||
return Ok(ids);
|
return Ok(ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to resolve as a git ref
|
// Try to resolve as a git ref
|
||||||
if let Some(ids) = resolve_git_ref(repo, symbol) {
|
if let Some(ids) = resolve_git_ref(self.repo, symbol) {
|
||||||
return Ok(ids);
|
return Ok(ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to resolve as a full commit id.
|
// Try to resolve as a full commit id.
|
||||||
if let Some(ids) = resolve_full_commit_id(repo, symbol)? {
|
if let Some(ids) = resolve_full_commit_id(self.repo, symbol)? {
|
||||||
return Ok(ids);
|
return Ok(ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to resolve as a commit id.
|
// Try to resolve as a commit id.
|
||||||
if let Some(ids) = resolve_short_commit_id(repo, symbol)? {
|
if let Some(ids) = resolve_short_commit_id(self.repo, symbol)? {
|
||||||
return Ok(ids);
|
return Ok(ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to resolve as a change id.
|
// Try to resolve as a change id.
|
||||||
if let Some(ids) = resolve_change_id(repo, symbol)? {
|
if let Some(ids) = resolve_change_id(self.repo, symbol)? {
|
||||||
return Ok(ids);
|
return Ok(ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(RevsetResolutionError::NoSuchRevision(symbol.to_owned()))
|
Err(RevsetResolutionError::NoSuchRevision(symbol.to_owned()))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resolve_symbol(
|
||||||
|
repo: &dyn Repo,
|
||||||
|
symbol: &str,
|
||||||
|
workspace_id: Option<&WorkspaceId>,
|
||||||
|
) -> Result<Vec<CommitId>, RevsetResolutionError> {
|
||||||
|
DefaultSymbolResolver::new(repo, workspace_id).resolve_symbol(symbol)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_commit_ref(
|
fn resolve_commit_ref(
|
||||||
repo: &dyn Repo,
|
repo: &dyn Repo,
|
||||||
commit_ref: &RevsetCommitRef,
|
commit_ref: &RevsetCommitRef,
|
||||||
workspace_ctx: Option<&RevsetWorkspaceContext>,
|
symbol_resolver: &dyn SymbolResolver,
|
||||||
) -> Result<Vec<CommitId>, RevsetResolutionError> {
|
) -> Result<Vec<CommitId>, RevsetResolutionError> {
|
||||||
match commit_ref {
|
match commit_ref {
|
||||||
RevsetCommitRef::Symbol(symbol) => {
|
RevsetCommitRef::Symbol(symbol) => symbol_resolver.resolve_symbol(symbol),
|
||||||
resolve_symbol(repo, symbol, workspace_ctx.map(|ctx| ctx.workspace_id))
|
|
||||||
}
|
|
||||||
RevsetCommitRef::VisibleHeads => Ok(repo.view().heads().iter().cloned().collect_vec()),
|
RevsetCommitRef::VisibleHeads => Ok(repo.view().heads().iter().cloned().collect_vec()),
|
||||||
RevsetCommitRef::Branches(needle) => {
|
RevsetCommitRef::Branches(needle) => {
|
||||||
let mut commit_ids = vec![];
|
let mut commit_ids = vec![];
|
||||||
|
@ -1786,14 +1813,14 @@ fn resolve_commit_ref(
|
||||||
fn resolve_symbols(
|
fn resolve_symbols(
|
||||||
repo: &dyn Repo,
|
repo: &dyn Repo,
|
||||||
expression: Rc<RevsetExpression>,
|
expression: Rc<RevsetExpression>,
|
||||||
workspace_ctx: Option<&RevsetWorkspaceContext>,
|
symbol_resolver: &dyn SymbolResolver,
|
||||||
) -> Result<Rc<RevsetExpression>, RevsetResolutionError> {
|
) -> Result<Rc<RevsetExpression>, RevsetResolutionError> {
|
||||||
Ok(try_transform_expression(
|
Ok(try_transform_expression(
|
||||||
&expression,
|
&expression,
|
||||||
|expression| match expression.as_ref() {
|
|expression| match expression.as_ref() {
|
||||||
// 'present(x)' opens new symbol resolution scope to map error to 'none()'.
|
// 'present(x)' opens new symbol resolution scope to map error to 'none()'.
|
||||||
RevsetExpression::Present(candidates) => {
|
RevsetExpression::Present(candidates) => {
|
||||||
resolve_symbols(repo, candidates.clone(), workspace_ctx)
|
resolve_symbols(repo, candidates.clone(), symbol_resolver)
|
||||||
.or_else(|err| match err {
|
.or_else(|err| match err {
|
||||||
RevsetResolutionError::NoSuchRevision(_) => Ok(RevsetExpression::none()),
|
RevsetResolutionError::NoSuchRevision(_) => Ok(RevsetExpression::none()),
|
||||||
RevsetResolutionError::AmbiguousIdPrefix(_)
|
RevsetResolutionError::AmbiguousIdPrefix(_)
|
||||||
|
@ -1806,7 +1833,7 @@ fn resolve_symbols(
|
||||||
},
|
},
|
||||||
|expression| match expression.as_ref() {
|
|expression| match expression.as_ref() {
|
||||||
RevsetExpression::CommitRef(commit_ref) => {
|
RevsetExpression::CommitRef(commit_ref) => {
|
||||||
let commit_ids = resolve_commit_ref(repo, commit_ref, workspace_ctx)?;
|
let commit_ids = resolve_commit_ref(repo, commit_ref, symbol_resolver)?;
|
||||||
Ok(Some(RevsetExpression::commits(commit_ids)))
|
Ok(Some(RevsetExpression::commits(commit_ids)))
|
||||||
}
|
}
|
||||||
_ => Ok(None),
|
_ => Ok(None),
|
||||||
|
|
Loading…
Reference in a new issue