From d1135917b0fb01fa258f9bd8eaf7f105b1ad3d35 Mon Sep 17 00:00:00 2001 From: Antoine Cezar Date: Sun, 29 Oct 2023 22:42:56 +0100 Subject: [PATCH] commands: move next code to next.rs --- cli/src/commands/mod.rs | 111 +-------------------------------- cli/src/commands/next.rs | 131 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+), 108 deletions(-) create mode 100644 cli/src/commands/next.rs diff --git a/cli/src/commands/mod.rs b/cli/src/commands/mod.rs index 1432a47ed..3a9c21714 100644 --- a/cli/src/commands/mod.rs +++ b/cli/src/commands/mod.rs @@ -36,6 +36,7 @@ mod log; mod merge; mod r#move; mod new; +mod next; mod operation; mod rebase; mod resolve; @@ -119,7 +120,7 @@ enum Commands { Merge(new::NewArgs), Move(r#move::MoveArgs), New(new::NewArgs), - Next(NextArgs), + Next(next::NextArgs), Obslog(ObslogArgs), #[command(subcommand)] #[command(visible_alias = "op")] @@ -214,46 +215,6 @@ struct ObslogArgs { diff_format: DiffFormatArgs, } -/// Move the current working copy commit to the next child revision in the -/// repository. -/// -/// -/// The command moves you to the next child in a linear fashion. -/// -/// -/// D D @ -/// | |/ -/// C @ => C -/// |/ | -/// B B -/// -/// -/// If `--edit` is passed, it will move you directly to the child -/// revision. -/// -/// -/// D D -/// | | -/// C C -/// | | -/// B => @ -/// | | -/// @ A -// TODO(#2126): Handle multiple child revisions properly. -#[derive(clap::Args, Clone, Debug)] -#[command(verbatim_doc_comment)] -struct NextArgs { - /// How many revisions to move forward. By default advances to the next - /// child. - #[arg(default_value = "1")] - amount: u64, - /// Instead of creating a new working-copy commit on top of the target - /// commit (like `jj new`), edit the target commit directly (like `jj - /// edit`). - #[arg(long)] - edit: bool, -} - /// Move the working copy commit to the parent of the current revision. /// /// @@ -1018,72 +979,6 @@ fn edit_sparse( .try_collect() } -fn cmd_next(ui: &mut Ui, command: &CommandHelper, args: &NextArgs) -> Result<(), CommandError> { - let mut workspace_command = command.workspace_helper(ui)?; - let edit = args.edit; - let amount = args.amount; - let current_wc_id = workspace_command - .get_wc_commit_id() - .ok_or_else(|| user_error("This command requires a working copy"))?; - let current_wc = workspace_command.repo().store().get_commit(current_wc_id)?; - let current_short = short_commit_hash(current_wc.id()); - // If we're editing, start at the working-copy commit. - // Otherwise start from our direct parent. - let start_id = if edit { - current_wc_id - } else { - match current_wc.parent_ids() { - [parent_id] => parent_id, - _ => return Err(user_error("Cannot run `jj next` on a merge commit")), - } - }; - let descendant_expression = RevsetExpression::commit(start_id.clone()).descendants_at(amount); - let target_expression = if edit { - descendant_expression - } else { - descendant_expression.minus(&RevsetExpression::commit(current_wc_id.clone()).descendants()) - }; - let targets: Vec = target_expression - .resolve(workspace_command.repo().as_ref())? - .evaluate(workspace_command.repo().as_ref())? - .iter() - .commits(workspace_command.repo().store()) - .take(2) - .try_collect()?; - let target = match targets.as_slice() { - [target] => target, - [] => { - // We found no descendant. - return Err(user_error(format!( - "No descendant found {amount} commit{} forward", - if amount > 1 { "s" } else { "" } - ))); - } - _ => { - // TODO(#2126) We currently cannot deal with multiple children, which result - // from branches. Prompt the user for resolution. - return Err(user_error("Ambiguous target commit")); - } - }; - let target_short = short_commit_hash(target.id()); - // We're editing, just move to the target commit. - if edit { - // We're editing, the target must be rewritable. - workspace_command.check_rewritable([target])?; - let mut tx = workspace_command - .start_transaction(&format!("next: {current_short} -> editing {target_short}")); - tx.edit(target)?; - tx.finish(ui)?; - return Ok(()); - } - let mut tx = - workspace_command.start_transaction(&format!("next: {current_short} -> {target_short}")); - // Move the working-copy commit to the new parent. - tx.check_out(target)?; - tx.finish(ui)?; - Ok(()) -} - fn cmd_prev(ui: &mut Ui, command: &CommandHelper, args: &PrevArgs) -> Result<(), CommandError> { let mut workspace_command = command.workspace_helper(ui)?; let edit = args.edit; @@ -1979,8 +1874,8 @@ pub fn run_command(ui: &mut Ui, command_helper: &CommandHelper) -> Result<(), Co Commands::Duplicate(sub_args) => duplicate::cmd_duplicate(ui, command_helper, sub_args), Commands::Abandon(sub_args) => abandon::cmd_abandon(ui, command_helper, sub_args), Commands::Edit(sub_args) => edit::cmd_edit(ui, command_helper, sub_args), - Commands::Next(sub_args) => cmd_next(ui, command_helper, sub_args), Commands::Prev(sub_args) => cmd_prev(ui, command_helper, sub_args), + Commands::Next(sub_args) => next::cmd_next(ui, command_helper, sub_args), Commands::New(sub_args) => new::cmd_new(ui, command_helper, sub_args), Commands::Move(sub_args) => r#move::cmd_move(ui, command_helper, sub_args), Commands::Squash(sub_args) => cmd_squash(ui, command_helper, sub_args), diff --git a/cli/src/commands/next.rs b/cli/src/commands/next.rs new file mode 100644 index 000000000..d6b0e16eb --- /dev/null +++ b/cli/src/commands/next.rs @@ -0,0 +1,131 @@ +// Copyright 2020 The Jujutsu Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use itertools::Itertools; +use jj_lib::commit::Commit; +use jj_lib::repo::Repo; +use jj_lib::revset::{RevsetExpression, RevsetIteratorExt}; + +use crate::cli_util::{short_commit_hash, user_error, CommandError, CommandHelper}; +use crate::ui::Ui; + +/// Move the current working copy commit to the next child revision in the +/// repository. +/// +/// +/// The command moves you to the next child in a linear fashion. +/// +/// +/// D D @ +/// | |/ +/// C @ => C +/// |/ | +/// B B +/// +/// +/// If `--edit` is passed, it will move you directly to the child +/// revision. +/// +/// +/// D D +/// | | +/// C C +/// | | +/// B => @ +/// | | +/// @ A +// TODO(#2126): Handle multiple child revisions properly. +#[derive(clap::Args, Clone, Debug)] +#[command(verbatim_doc_comment)] +pub(crate) struct NextArgs { + /// How many revisions to move forward. By default advances to the next + /// child. + #[arg(default_value = "1")] + amount: u64, + /// Instead of creating a new working-copy commit on top of the target + /// commit (like `jj new`), edit the target commit directly (like `jj + /// edit`). + #[arg(long)] + edit: bool, +} + +pub(crate) fn cmd_next( + ui: &mut Ui, + command: &CommandHelper, + args: &NextArgs, +) -> Result<(), CommandError> { + let mut workspace_command = command.workspace_helper(ui)?; + let edit = args.edit; + let amount = args.amount; + let current_wc_id = workspace_command + .get_wc_commit_id() + .ok_or_else(|| user_error("This command requires a working copy"))?; + let current_wc = workspace_command.repo().store().get_commit(current_wc_id)?; + let current_short = short_commit_hash(current_wc.id()); + // If we're editing, start at the working-copy commit. + // Otherwise start from our direct parent. + let start_id = if edit { + current_wc_id + } else { + match current_wc.parent_ids() { + [parent_id] => parent_id, + _ => return Err(user_error("Cannot run `jj next` on a merge commit")), + } + }; + let descendant_expression = RevsetExpression::commit(start_id.clone()).descendants_at(amount); + let target_expression = if edit { + descendant_expression + } else { + descendant_expression.minus(&RevsetExpression::commit(current_wc_id.clone()).descendants()) + }; + let targets: Vec = target_expression + .resolve(workspace_command.repo().as_ref())? + .evaluate(workspace_command.repo().as_ref())? + .iter() + .commits(workspace_command.repo().store()) + .take(2) + .try_collect()?; + let target = match targets.as_slice() { + [target] => target, + [] => { + // We found no descendant. + return Err(user_error(format!( + "No descendant found {amount} commit{} forward", + if amount > 1 { "s" } else { "" } + ))); + } + _ => { + // TODO(#2126) We currently cannot deal with multiple children, which result + // from branches. Prompt the user for resolution. + return Err(user_error("Ambiguous target commit")); + } + }; + let target_short = short_commit_hash(target.id()); + // We're editing, just move to the target commit. + if edit { + // We're editing, the target must be rewritable. + workspace_command.check_rewritable([target])?; + let mut tx = workspace_command + .start_transaction(&format!("next: {current_short} -> editing {target_short}")); + tx.edit(target)?; + tx.finish(ui)?; + return Ok(()); + } + let mut tx = + workspace_command.start_transaction(&format!("next: {current_short} -> {target_short}")); + // Move the working-copy commit to the new parent. + tx.check_out(target)?; + tx.finish(ui)?; + Ok(()) +}