cli: abandon, describe: parse -rREV option properly

I often do "jj log -rREV" to preview the commits to abandon, and it's annoying
that I have to remove -r or insert space to "jj abandon ..".

The implementation is basically the same as b0c7d0a7e2.
This commit is contained in:
Yuya Nishihara 2024-12-23 18:58:19 +09:00
parent 5bd669e892
commit 6374dd0cfe
5 changed files with 31 additions and 33 deletions

View file

@ -36,19 +36,17 @@ use crate::ui::Ui;
/// commit. This is true in general; it is not specific to this command. /// commit. This is true in general; it is not specific to this command.
#[derive(clap::Args, Clone, Debug)] #[derive(clap::Args, Clone, Debug)]
pub(crate) struct AbandonArgs { pub(crate) struct AbandonArgs {
/// The revision(s) to abandon /// The revision(s) to abandon (default: @)
#[arg( #[arg(
default_value = "@",
value_name = "REVSETS", value_name = "REVSETS",
add = ArgValueCandidates::new(complete::mutable_revisions) add = ArgValueCandidates::new(complete::mutable_revisions)
)] )]
revisions: Vec<RevisionArg>, revisions_pos: Vec<RevisionArg>,
#[arg(short = 'r', hide = true, value_name = "REVSETS")]
revisions_opt: Vec<RevisionArg>,
/// Do not print every abandoned commit on a separate line /// Do not print every abandoned commit on a separate line
#[arg(long, short)] #[arg(long, short)]
summary: bool, summary: bool,
/// Ignored (but lets you pass `-r` for consistency with other commands)
#[arg(short = 'r', hide = true, action = clap::ArgAction::Count)]
unused_revision: u8,
/// Do not modify the content of the children of the abandoned commits /// Do not modify the content of the children of the abandoned commits
#[arg(long)] #[arg(long)]
restore_descendants: bool, restore_descendants: bool,
@ -61,10 +59,14 @@ pub(crate) fn cmd_abandon(
args: &AbandonArgs, args: &AbandonArgs,
) -> Result<(), CommandError> { ) -> Result<(), CommandError> {
let mut workspace_command = command.workspace_helper(ui)?; let mut workspace_command = command.workspace_helper(ui)?;
let to_abandon: Vec<_> = workspace_command let to_abandon: Vec<_> = if !args.revisions_pos.is_empty() || !args.revisions_opt.is_empty() {
.parse_union_revsets(ui, &args.revisions)? workspace_command
.evaluate_to_commits()? .parse_union_revsets(ui, &[&*args.revisions_pos, &*args.revisions_opt].concat())?
.try_collect()?; } else {
workspace_command.parse_revset(ui, &RevisionArg::AT)?
}
.evaluate_to_commits()?
.try_collect()?;
if to_abandon.is_empty() { if to_abandon.is_empty() {
writeln!(ui.status(), "No revisions to abandon.")?; writeln!(ui.status(), "No revisions to abandon.")?;
return Ok(()); return Ok(());

View file

@ -43,16 +43,14 @@ use crate::ui::Ui;
#[derive(clap::Args, Clone, Debug)] #[derive(clap::Args, Clone, Debug)]
#[command(visible_aliases = &["desc"])] #[command(visible_aliases = &["desc"])]
pub(crate) struct DescribeArgs { pub(crate) struct DescribeArgs {
/// The revision(s) whose description to edit /// The revision(s) whose description to edit (default: @)
#[arg( #[arg(
default_value = "@",
value_name = "REVSETS", value_name = "REVSETS",
add = ArgValueCandidates::new(complete::mutable_revisions) add = ArgValueCandidates::new(complete::mutable_revisions)
)] )]
revisions: Vec<RevisionArg>, revisions_pos: Vec<RevisionArg>,
/// Ignored (but lets you pass `-r` for consistency with other commands) #[arg(short = 'r', hide = true, value_name = "REVSETS")]
#[arg(short = 'r', hide = true, action = clap::ArgAction::Count)] revisions_opt: Vec<RevisionArg>,
unused_revision: u8,
/// The change description to use (don't open editor) /// The change description to use (don't open editor)
/// ///
/// If multiple revisions are specified, the same description will be used /// If multiple revisions are specified, the same description will be used
@ -99,10 +97,14 @@ pub(crate) fn cmd_describe(
args: &DescribeArgs, args: &DescribeArgs,
) -> Result<(), CommandError> { ) -> Result<(), CommandError> {
let mut workspace_command = command.workspace_helper(ui)?; let mut workspace_command = command.workspace_helper(ui)?;
let commits: Vec<_> = workspace_command let commits: Vec<_> = if !args.revisions_pos.is_empty() || !args.revisions_opt.is_empty() {
.parse_union_revsets(ui, &args.revisions)? workspace_command
.evaluate_to_commits()? .parse_union_revsets(ui, &[&*args.revisions_pos, &*args.revisions_opt].concat())?
.try_collect()?; // in reverse topological order } else {
workspace_command.parse_revset(ui, &RevisionArg::AT)?
}
.evaluate_to_commits()?
.try_collect()?; // in reverse topological order
if commits.is_empty() { if commits.is_empty() {
writeln!(ui.status(), "No revisions to describe.")?; writeln!(ui.status(), "No revisions to describe.")?;
return Ok(()); return Ok(());

View file

@ -214,9 +214,7 @@ If a working-copy commit gets abandoned, it will be given a new, empty commit. T
###### **Arguments:** ###### **Arguments:**
* `<REVSETS>` — The revision(s) to abandon * `<REVSETS>` — The revision(s) to abandon (default: @)
Default value: `@`
###### **Options:** ###### **Options:**
@ -650,9 +648,7 @@ Starts an editor to let you edit the description of changes. The editor will be
###### **Arguments:** ###### **Arguments:**
* `<REVSETS>` — The revision(s) whose description to edit * `<REVSETS>` — The revision(s) whose description to edit (default: @)
Default value: `@`
###### **Options:** ###### **Options:**

View file

@ -120,7 +120,7 @@ fn test_basics() {
// Test abandoning the same commit twice directly // Test abandoning the same commit twice directly
test_env.jj_cmd_ok(&repo_path, &["undo"]); test_env.jj_cmd_ok(&repo_path, &["undo"]);
let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["abandon", "b", "b"]); let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["abandon", "-rb", "b"]);
insta::assert_snapshot!(stdout, @""); insta::assert_snapshot!(stdout, @"");
insta::assert_snapshot!(stderr, @r###" insta::assert_snapshot!(stderr, @r###"
Abandoned commit zsuskuln 1394f625 b | b Abandoned commit zsuskuln 1394f625 b | b
@ -377,10 +377,8 @@ fn test_abandon_restore_descendants() {
std::fs::write(repo_path.join("file"), "baz\n").unwrap(); std::fs::write(repo_path.join("file"), "baz\n").unwrap();
// Remove the commit containing "bar" // Remove the commit containing "bar"
let (stdout, stderr) = test_env.jj_cmd_ok( let (stdout, stderr) =
&repo_path, test_env.jj_cmd_ok(&repo_path, &["abandon", "-r@-", "--restore-descendants"]);
&["abandon", "-r", "@-", "--restore-descendants"],
);
insta::assert_snapshot!(stdout, @""); insta::assert_snapshot!(stdout, @"");
insta::assert_snapshot!(stderr, @r#" insta::assert_snapshot!(stderr, @r#"
Abandoned commit rlvkpnrz 225adef1 (no description set) Abandoned commit rlvkpnrz 225adef1 (no description set)

View file

@ -204,7 +204,7 @@ fn test_describe_multiple_commits() {
// Set the description of multiple commits using `-m` flag // Set the description of multiple commits using `-m` flag
let (stdout, stderr) = test_env.jj_cmd_ok( let (stdout, stderr) = test_env.jj_cmd_ok(
&repo_path, &repo_path,
&["describe", "@", "@--", "-m", "description from CLI"], &["describe", "-r@", "-r@--", "-m", "description from CLI"],
); );
insta::assert_snapshot!(stdout, @""); insta::assert_snapshot!(stdout, @"");
insta::assert_snapshot!(stderr, @r###" insta::assert_snapshot!(stderr, @r###"
@ -224,7 +224,7 @@ fn test_describe_multiple_commits() {
// each commit and doesn't update commits if no changes are made. // each commit and doesn't update commits if no changes are made.
// Commit descriptions are edited in topological order // Commit descriptions are edited in topological order
std::fs::write(&edit_script, "dump editor0").unwrap(); std::fs::write(&edit_script, "dump editor0").unwrap();
let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["describe", "@", "@-"]); let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["describe", "-r@", "@-"]);
insta::assert_snapshot!(stdout, @""); insta::assert_snapshot!(stdout, @"");
insta::assert_snapshot!(stderr, @r###" insta::assert_snapshot!(stderr, @r###"
Nothing changed. Nothing changed.