summaryrefslogtreecommitdiff
path: root/src/inquire.rs
blob: 6dd2e3cfcc72582c42fa0886b6978f4d023e5349 (plain)
use std::fmt::Display;

use chrono::Local;
use git2::{Signature, Time};

use crate::Autosave;

pub struct AutosaveFilters<'a> {
	pub signature: &'a Signature<'a>,
	pub branch: &'a str,
	pub earliest_time: Time,
	pub repo_id: &'a str,
	pub all_users: bool,
	pub all_branches: bool,
	pub anytime: bool,
	pub all_devices: bool,
}

struct AutosaveOption {
	text: String,
	value: Autosave,
}

impl Display for AutosaveOption {
	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
		self.text.fmt(f)
	}
}

pub fn filter_autosaves(
	autosaves: impl IntoIterator<Item = Autosave>,
	filters: AutosaveFilters<'_>,
) -> impl Iterator<Item = Autosave> {
	let AutosaveFilters {
		all_users,
		signature,
		all_branches,
		branch,
		anytime,
		earliest_time,
		all_devices,
		repo_id,
	} = filters;
	autosaves
		.into_iter()
		.filter(move |autosave| {
			all_users
				|| signature
					.name()
					.zip(autosave.author.clone())
					.is_some_and(|(a, b)| a == b)
				|| signature
					.email()
					.zip(autosave.email.clone())
					.is_some_and(|(a, b)| a == b)
		})
		.filter(move |autosave| all_branches || autosave.branch_name == branch)
		.filter(move |autosave| anytime || autosave.time > earliest_time)
		.filter(move |autosave| all_devices || autosave.repo_id.as_bytes() != repo_id.as_bytes())
}

pub fn select_autosave(
	mut autosaves: Vec<Autosave>,
	all_branches: bool,
	all_users: bool,
) -> Result<Autosave, inquire::InquireError> {
	if autosaves.len() > 1 {
		let autosaves = autosaves
			.into_iter()
			.map(|autosave| {
				let device = autosave.host_name.as_ref().unwrap_or(&autosave.repo_id);
				let time = chrono::DateTime::from_timestamp(autosave.time.seconds(), 0)
					.map(|time| time.with_timezone(&Local))
					.map(|time| time.to_rfc2822())
					.unwrap_or(autosave.time.seconds().to_string());
				let branch = if all_branches {
					format!(" on {}", &autosave.branch_name)
				} else {
					String::new()
				};
				let author = if let Some(author) =
					autosave.author.as_ref().or(autosave.email.as_ref())
					&& all_users
				{
					format!(" by {author}")
				} else {
					String::new()
				};
				AutosaveOption {
					text: format!("{device} ({time}{branch}{author})"),
					value: autosave,
				}
			})
			.collect();
		Ok(inquire::Select::new("Select an autosave:", autosaves)
			.prompt()?
			.value)
	} else {
		Ok(autosaves
			.pop()
			.expect("There should be an autosave to select but there isn't. This is a bug!"))
	}
}