use clap_complete::ArgValueCandidates;
use itertools::Itertools as _;
use jj_lib::op_store::LocalRemoteRefTarget;
use jj_lib::op_store::RefTarget;
use jj_lib::op_store::RemoteRef;
use jj_lib::ref_name::RefName;
use jj_lib::repo::Repo as _;
use jj_lib::view::View;
use super::warn_unmatched_local_or_remote_bookmarks;
use crate::cli_util::CommandHelper;
use crate::cli_util::default_ignored_remote_name;
use crate::command_error::CommandError;
use crate::complete;
use crate::revset_util::parse_union_name_patterns;
use crate::ui::Ui;
#[derive(clap::Args, Clone, Debug)]
pub struct BookmarkForgetArgs {
#[arg(long)]
include_remotes: bool,
#[arg(required = true)]
#[arg(add = ArgValueCandidates::new(complete::bookmarks))]
names: Vec<String>,
}
pub async fn cmd_bookmark_forget(
ui: &mut Ui,
command: &CommandHelper,
args: &BookmarkForgetArgs,
) -> Result<(), CommandError> {
let mut workspace_command = command.workspace_helper(ui)?;
let repo = workspace_command.repo().clone();
let ignored_remote = default_ignored_remote_name(repo.store());
let matched_bookmarks = find_forgettable_bookmarks(ui, repo.view(), &args.names)?;
if matched_bookmarks.is_empty() {
writeln!(ui.status(), "No bookmarks to forget.")?;
return Ok(());
}
let mut tx = workspace_command.start_transaction();
let mut forgotten_remote: usize = 0;
for (name, bookmark_target) in &matched_bookmarks {
tx.repo_mut()
.set_local_bookmark_target(name, RefTarget::absent());
for (remote, _) in &bookmark_target.remote_refs {
let symbol = name.to_remote_symbol(remote);
if args.include_remotes {
tx.repo_mut()
.set_remote_bookmark(symbol, RemoteRef::absent());
forgotten_remote += 1;
continue;
}
if ignored_remote.is_some_and(|ignored| symbol.remote == ignored) {
continue;
}
tx.repo_mut().untrack_remote_bookmark(symbol);
}
}
writeln!(
ui.status(),
"Forgot {} local bookmarks.",
matched_bookmarks.len()
)?;
if forgotten_remote != 0 {
writeln!(ui.status(), "Forgot {forgotten_remote} remote bookmarks.")?;
}
let forgotten_bookmarks = matched_bookmarks
.iter()
.map(|(name, _)| name.as_symbol())
.join(", ");
tx.finish(ui, format!("forget bookmark {forgotten_bookmarks}"))
.await?;
Ok(())
}
fn find_forgettable_bookmarks<'a>(
ui: &Ui,
view: &'a View,
name_patterns: &[String],
) -> Result<Vec<(&'a RefName, LocalRemoteRefTarget<'a>)>, CommandError> {
let name_expr = parse_union_name_patterns(ui, name_patterns)?;
let name_matcher = name_expr.to_matcher();
let matched_bookmarks = view
.bookmarks()
.filter(|(name, _)| name_matcher.is_match(name.as_str()))
.collect();
warn_unmatched_local_or_remote_bookmarks(ui, view, &name_expr)?;
Ok(matched_bookmarks)
}