git.delta.rocks / remowt / refs/commits / 42e2f16609cb

difftreelog

source

crates/ui-prompt/src/lib.rs4.3 KiBsourcehistory
1use core::fmt;2use std::borrow::Cow;3use std::future::Future;4use std::result;56pub mod bifrost;7pub mod dbus;8pub mod rofi;910#[derive(thiserror::Error, Debug, serde::Serialize, serde::Deserialize)]11pub enum Error {12	#[error("user has cancelled input")]13	Cancel,14	#[error("input error: {0}")]15	InputError(String),16	#[error("unknown remote error: {0}")]17	Remote(String),18}1920pub type Result<T, E = Error> = result::Result<T, E>;2122#[cfg_attr(feature = "dbus", derive(zbus::zvariant::Type))]23#[derive(serde::Serialize, serde::Deserialize, Clone)]24pub struct Source(pub Cow<'static, str>);25impl fmt::Display for Source {26	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {27		write!(f, "<u>{}</u>", self.0)28	}29}3031pub trait Prompter: Send + Sync {32	fn prompt_radio(33		&self,34		prompt: &str,35		description: &str,36		source: &[Source],37	) -> impl Future<Output = Result<bool>> + Send {38		let fut = self.prompt_enum(prompt, description, &["No", "Yes"], source);39		async { fut.await.map(|v| v == 1) }40	}41	fn prompt_enum(42		&self,43		prompt: &str,44		description: &str,45		variants: &[&str],46		source: &[Source],47	) -> impl Future<Output = Result<u32>> + Send;48	fn prompt_text(49		&self,50		echo: bool,51		prompt: &str,52		description: &str,53		source: &[Source],54	) -> impl Future<Output = Result<String>> + Send;55	fn display_text(56		&self,57		error: bool,58		description: &str,59		source: &[Source],60	) -> impl Future<Output = Result<()>> + Send;61}62pub trait BlockingPrompter {63	fn prompt_radio(&self, prompt: &str, description: &str, source: &[Source]) -> Result<bool> {64		self.prompt_enum(prompt, description, &["No", "Yes"], source)65			.map(|v| v == 1)66	}67	fn prompt_enum(68		&self,69		prompt: &str,70		description: &str,71		variants: &[&str],72		source: &[Source],73	) -> Result<u32>;74	fn prompt_text(75		&self,76		echo: bool,77		prompt: &str,78		description: &str,79		source: &[Source],80	) -> Result<String>;81	fn display_text(&self, error: bool, description: &str, source: &[Source]) -> Result<()>;82}83impl<P> Prompter for &P84where85	P: Prompter,86{87	fn prompt_radio(88		&self,89		prompt: &str,90		description: &str,91		source: &[Source],92	) -> impl Future<Output = Result<bool>> + Send {93		(*self).prompt_radio(prompt, description, source)94	}9596	fn prompt_enum(97		&self,98		prompt: &str,99		description: &str,100		variants: &[&str],101		source: &[Source],102	) -> impl Future<Output = Result<u32>> + Send {103		(*self).prompt_enum(prompt, description, variants, source)104	}105106	fn prompt_text(107		&self,108		echo: bool,109		prompt: &str,110		description: &str,111		source: &[Source],112	) -> impl Future<Output = Result<String>> + Send {113		(*self).prompt_text(echo, prompt, description, source)114	}115116	fn display_text(117		&self,118		error: bool,119		description: &str,120		source: &[Source],121	) -> impl Future<Output = Result<()>> + Send {122		(*self).display_text(error, description, source)123	}124}125126pub struct PrependSourcePrompter<P> {127	pub prompter: P,128	pub source: Vec<Source>,129	pub description: String,130}131impl<P> PrependSourcePrompter<P> {132	fn source(&self, input: &[Source]) -> Vec<Source> {133		let mut out = self.source.clone();134		out.extend(input.iter().cloned());135		out136	}137	fn description(&self, input: &str) -> String {138		if self.description.is_empty() {139			input.to_owned()140		} else if input.is_empty() {141			self.description.to_owned()142		} else {143			format!("{input}\n\n{}", self.description)144		}145	}146}147impl<P> Prompter for PrependSourcePrompter<P>148where149	P: Prompter + Sync,150{151	async fn prompt_radio(152		&self,153		prompt: &str,154		description: &str,155		source: &[Source],156	) -> Result<bool> {157		self.prompter158			.prompt_radio(prompt, &self.description(description), &self.source(source))159			.await160	}161162	async fn prompt_enum(163		&self,164		prompt: &str,165		description: &str,166		variants: &[&str],167		source: &[Source],168	) -> Result<u32> {169		self.prompter170			.prompt_enum(171				prompt,172				&self.description(description),173				variants,174				&self.source(source),175			)176			.await177	}178179	async fn prompt_text(180		&self,181		echo: bool,182		prompt: &str,183		description: &str,184		source: &[Source],185	) -> Result<String> {186		self.prompter187			.prompt_text(188				echo,189				prompt,190				&self.description(description),191				&self.source(source),192			)193			.await194	}195196	async fn display_text(&self, error: bool, description: &str, source: &[Source]) -> Result<()> {197		self.prompter198			.display_text(error, &self.description(description), &self.source(source))199			.await200	}201}