Skip to content

Commit

Permalink
revsets: add syntax for a particular workspace's checkout (#13)
Browse files Browse the repository at this point in the history
Because we record each workspace's checkout in the repo view, we can
-- unlike other VCSs -- let the user refer to any workspace's checkout
in revsets. This patch adds syntax for that, so you can show the
contents of the checkout in workspace "foo" with `jj show foo@`. That
won't automatically commit that workspace's working copy, however.
  • Loading branch information
martinvonz committed Feb 2, 2022
1 parent 5b46fa3 commit 012b4c4
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 68 deletions.
72 changes: 46 additions & 26 deletions lib/src/revset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ use thiserror::Error;
use crate::backend::{BackendError, BackendResult, CommitId};
use crate::commit::Commit;
use crate::index::{HexPrefix, IndexEntry, IndexPosition, PrefixResolution, RevWalk};
use crate::op_store::WorkspaceId;
use crate::repo::RepoRef;
use crate::revset_graph_iterator::RevsetGraphIterator;
use crate::store::Store;
Expand Down Expand Up @@ -102,7 +103,7 @@ fn resolve_change_id(repo: RepoRef, change_id_prefix: &str) -> Result<Vec<Commit
let mut found_change_id = None;
let mut commit_ids = vec![];
// TODO: Create a persistent lookup from change id to (visible?) commit ids.
for index_entry in RevsetExpression::all().evaluate(repo).unwrap().iter() {
for index_entry in RevsetExpression::all().evaluate(repo, None).unwrap().iter() {
let change_id = index_entry.change_id();
if change_id.hex().starts_with(hex_prefix.hex()) {
if let Some(previous_change_id) = found_change_id.replace(change_id.clone()) {
Expand All @@ -124,9 +125,26 @@ fn resolve_change_id(repo: RepoRef, change_id_prefix: &str) -> Result<Vec<Commit
}
}

pub fn resolve_symbol(repo: RepoRef, symbol: &str) -> Result<Vec<CommitId>, RevsetError> {
if symbol == "@" {
Ok(vec![repo.view().checkout().clone()])
pub fn resolve_symbol(
repo: RepoRef,
symbol: &str,
workspace_id: Option<&WorkspaceId>,
) -> Result<Vec<CommitId>, RevsetError> {
if symbol.ends_with('@') {
let target_workspace = if symbol == "@" {
if let Some(workspace_id) = workspace_id {
workspace_id.clone()
} else {
return Err(RevsetError::NoSuchRevision(symbol.to_owned()));
}
} else {
WorkspaceId::new(symbol.strip_suffix('@').unwrap().to_string())
};
if let Some(commit_id) = repo.view().get_checkout(&target_workspace) {
Ok(vec![commit_id.clone()])
} else {
Err(RevsetError::NoSuchRevision(symbol.to_owned()))
}
} else if symbol == "root" {
Ok(vec![repo.store().root_commit_id().clone()])
} else {
Expand Down Expand Up @@ -387,8 +405,9 @@ impl RevsetExpression {
pub fn evaluate<'repo>(
&self,
repo: RepoRef<'repo>,
workspace_id: Option<&WorkspaceId>,
) -> Result<Box<dyn Revset<'repo> + 'repo>, RevsetError> {
evaluate_expression(repo, self)
evaluate_expression(repo, self, workspace_id)
}
}

Expand Down Expand Up @@ -1069,19 +1088,20 @@ impl<'revset, 'repo> Iterator for DifferenceRevsetIterator<'revset, 'repo> {
pub fn evaluate_expression<'repo>(
repo: RepoRef<'repo>,
expression: &RevsetExpression,
workspace_id: Option<&WorkspaceId>,
) -> Result<Box<dyn Revset<'repo> + 'repo>, RevsetError> {
match expression {
RevsetExpression::None => Ok(Box::new(EagerRevset {
index_entries: vec![],
})),
RevsetExpression::Commits(commit_ids) => Ok(revset_for_commit_ids(repo, commit_ids)),
RevsetExpression::Symbol(symbol) => {
let commit_ids = resolve_symbol(repo, symbol)?;
evaluate_expression(repo, &RevsetExpression::Commits(commit_ids))
let commit_ids = resolve_symbol(repo, symbol, workspace_id)?;
evaluate_expression(repo, &RevsetExpression::Commits(commit_ids), workspace_id)
}
RevsetExpression::Parents(base_expression) => {
// TODO: Make this lazy
let base_set = base_expression.evaluate(repo)?;
let base_set = base_expression.evaluate(repo, workspace_id)?;
let mut parent_entries = base_set
.iter()
.flat_map(|entry| entry.parents())
Expand All @@ -1093,21 +1113,21 @@ pub fn evaluate_expression<'repo>(
}))
}
RevsetExpression::Children(roots) => {
let root_set = roots.evaluate(repo)?;
let root_set = roots.evaluate(repo, workspace_id)?;
let candidates_expression = roots.descendants();
let candidate_set = candidates_expression.evaluate(repo)?;
let candidate_set = candidates_expression.evaluate(repo, workspace_id)?;
Ok(Box::new(ChildrenRevset {
root_set,
candidate_set,
}))
}
RevsetExpression::Ancestors(base_expression) => RevsetExpression::none()
.range(base_expression)
.evaluate(repo),
.evaluate(repo, workspace_id),
RevsetExpression::Range { roots, heads } => {
let root_set = roots.evaluate(repo)?;
let root_set = roots.evaluate(repo, workspace_id)?;
let root_ids = root_set.iter().commit_ids().collect_vec();
let head_set = heads.evaluate(repo)?;
let head_set = heads.evaluate(repo, workspace_id)?;
let head_ids = head_set.iter().commit_ids().collect_vec();
let walk = repo.index().walk_revs(&head_ids, &root_ids);
Ok(Box::new(RevWalkRevset { walk }))
Expand All @@ -1116,8 +1136,8 @@ pub fn evaluate_expression<'repo>(
// reverse
#[allow(clippy::needless_collect)]
RevsetExpression::DagRange { roots, heads } => {
let root_set = roots.evaluate(repo)?;
let candidate_set = heads.ancestors().evaluate(repo)?;
let root_set = roots.evaluate(repo, workspace_id)?;
let candidate_set = heads.ancestors().evaluate(repo, workspace_id)?;
let mut reachable: HashSet<_> = root_set.iter().map(|entry| entry.position()).collect();
let mut result = vec![];
let candidates = candidate_set.iter().collect_vec();
Expand All @@ -1142,7 +1162,7 @@ pub fn evaluate_expression<'repo>(
&repo.view().heads().iter().cloned().collect_vec(),
)),
RevsetExpression::HeadsOf(candidates) => {
let candidate_set = candidates.evaluate(repo)?;
let candidate_set = candidates.evaluate(repo, workspace_id)?;
let candidate_ids = candidate_set.iter().commit_ids().collect_vec();
Ok(revset_for_commit_ids(
repo,
Expand All @@ -1153,7 +1173,7 @@ pub fn evaluate_expression<'repo>(
candidates,
parent_count_range,
} => {
let candidates = candidates.evaluate(repo)?;
let candidates = candidates.evaluate(repo, workspace_id)?;
let parent_count_range = parent_count_range.clone();
Ok(Box::new(FilterRevset {
candidates,
Expand Down Expand Up @@ -1201,7 +1221,7 @@ pub fn evaluate_expression<'repo>(
Ok(revset_for_commit_ids(repo, &commit_ids))
}
RevsetExpression::Description { needle, candidates } => {
let candidates = candidates.evaluate(repo)?;
let candidates = candidates.evaluate(repo, workspace_id)?;
let repo = repo;
let needle = needle.clone();
Ok(Box::new(FilterRevset {
Expand All @@ -1216,7 +1236,7 @@ pub fn evaluate_expression<'repo>(
}))
}
RevsetExpression::Author { needle, candidates } => {
let candidates = candidates.evaluate(repo)?;
let candidates = candidates.evaluate(repo, workspace_id)?;
let repo = repo;
let needle = needle.clone();
// TODO: Make these functions that take a needle to search for accept some
Expand All @@ -1232,7 +1252,7 @@ pub fn evaluate_expression<'repo>(
}))
}
RevsetExpression::Committer { needle, candidates } => {
let candidates = candidates.evaluate(repo)?;
let candidates = candidates.evaluate(repo, workspace_id)?;
let repo = repo;
let needle = needle.clone();
Ok(Box::new(FilterRevset {
Expand All @@ -1245,18 +1265,18 @@ pub fn evaluate_expression<'repo>(
}))
}
RevsetExpression::Union(expression1, expression2) => {
let set1 = expression1.evaluate(repo)?;
let set2 = expression2.evaluate(repo)?;
let set1 = expression1.evaluate(repo, workspace_id)?;
let set2 = expression2.evaluate(repo, workspace_id)?;
Ok(Box::new(UnionRevset { set1, set2 }))
}
RevsetExpression::Intersection(expression1, expression2) => {
let set1 = expression1.evaluate(repo)?;
let set2 = expression2.evaluate(repo)?;
let set1 = expression1.evaluate(repo, workspace_id)?;
let set2 = expression2.evaluate(repo, workspace_id)?;
Ok(Box::new(IntersectionRevset { set1, set2 }))
}
RevsetExpression::Difference(expression1, expression2) => {
let set1 = expression1.evaluate(repo)?;
let set2 = expression2.evaluate(repo)?;
let set1 = expression1.evaluate(repo, workspace_id)?;
let set2 = expression2.evaluate(repo, workspace_id)?;
Ok(Box::new(DifferenceRevset { set1, set2 }))
}
}
Expand Down
4 changes: 2 additions & 2 deletions lib/src/rewrite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,15 +156,15 @@ impl<'settings, 'repo> DescendantRebaser<'settings, 'repo> {
.parents()
.minus(&old_commits_expression);
let heads_to_add = heads_to_add_expression
.evaluate(mut_repo.as_repo_ref())
.evaluate(mut_repo.as_repo_ref(), None)
.unwrap()
.iter()
.commit_ids()
.collect();

let to_visit_expression = old_commits_expression.descendants();
let to_visit_revset = to_visit_expression
.evaluate(mut_repo.as_repo_ref())
.evaluate(mut_repo.as_repo_ref(), None)
.unwrap();
let to_visit_entries = to_visit_revset.iter().collect_vec();
drop(to_visit_revset);
Expand Down
Loading

0 comments on commit 012b4c4

Please sign in to comment.