use clap_complete::ArgValueCandidates;
use itertools::Itertools as _;
use jj_lib::object_id::ObjectId as _;
use jj_lib::operation::Operation;
use jj_lib::repo::Repo as _;
use super::DEFAULT_REVERT_WHAT;
use super::RevertWhatToRestore;
use super::view_with_desired_portions_restored;
use crate::cli_util::CommandHelper;
use crate::command_error::CommandError;
use crate::command_error::user_error;
use crate::complete;
use crate::ui::Ui;
#[derive(clap::Args, Clone, Debug)]
pub struct OperationRevertArgs {
#[arg(default_value = "@")]
#[arg(add = ArgValueCandidates::new(complete::operations))]
operation: String,
#[arg(long, value_enum, default_values_t = DEFAULT_REVERT_WHAT)]
what: Vec<RevertWhatToRestore>,
}
fn tx_description(op: &Operation) -> String {
format!("revert operation {}", op.id().hex())
}
pub async fn cmd_op_revert(
ui: &mut Ui,
command: &CommandHelper,
args: &OperationRevertArgs,
) -> Result<(), CommandError> {
let mut workspace_command = command.workspace_helper(ui)?;
let bad_op = workspace_command.resolve_single_op(&args.operation)?;
let parent_of_bad_op = match bad_op.parents().await?.into_iter().at_most_one() {
Ok(Some(parent_of_bad_op)) => parent_of_bad_op,
Ok(None) => return Err(user_error("Cannot revert root operation")),
Err(_) => return Err(user_error("Cannot revert a merge operation")),
};
let mut tx = workspace_command.start_transaction();
let repo_loader = tx.base_repo().loader();
let bad_repo = repo_loader.load_at(&bad_op).await?;
let parent_repo = repo_loader.load_at(&parent_of_bad_op).await?;
tx.repo_mut().merge(&bad_repo, &parent_repo).await?;
let new_view = view_with_desired_portions_restored(
tx.repo().view().store_view(),
tx.base_repo().view().store_view(),
&args.what,
);
tx.repo_mut().set_view(new_view);
if let Some(mut formatter) = ui.status_formatter() {
write!(formatter, "Reverted operation: ")?;
let template = tx.base_workspace_helper().operation_summary_template();
template.format(&bad_op, formatter.as_mut())?;
writeln!(formatter)?;
}
tx.finish(ui, tx_description(&bad_op)).await?;
Ok(())
}