git.delta.rocks / remowt / refs/heads / trunk

difftreelog

source

crates/remowt-ui-prompt/src/lib.rs4.3 KiBsourcehistory
1use core::fmt;2use std::borrow::Cow;3use std::future::Future;4use std::result;56pub mod auto;7pub mod bifrost;8pub mod dbus;9pub mod rofi;1011#[derive(thiserror::Error, Debug, serde::Serialize, serde::Deserialize)]12pub enum Error {13	#[error("user has cancelled input")]14	Cancel,15	#[error("input error: {0}")]16	InputError(String),17	#[error("unknown remote error: {0}")]18	Remote(String),19}2021pub type Result<T, E = Error> = result::Result<T, E>;2223#[cfg_attr(feature = "dbus", derive(zbus::zvariant::Type))]24#[derive(serde::Serialize, serde::Deserialize, Clone)]25pub struct Source(pub Cow<'static, str>);26impl fmt::Display for Source {27	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {28		write!(f, "<u>{}</u>", self.0)29	}30}3132pub trait Prompter: Send + Sync {33	fn prompt_radio(34		&self,35		prompt: &str,36		description: &str,37		source: &[Source],38	) -> impl Future<Output = Result<bool>> + Send {39		let fut = self.prompt_enum(prompt, description, &["No", "Yes"], source);40		async { fut.await.map(|v| v == 1) }41	}42	fn prompt_enum(43		&self,44		prompt: &str,45		description: &str,46		variants: &[&str],47		source: &[Source],48	) -> impl Future<Output = Result<u32>> + Send;49	fn prompt_text(50		&self,51		echo: bool,52		prompt: &str,53		description: &str,54		source: &[Source],55	) -> impl Future<Output = Result<String>> + Send;56	fn display_text(57		&self,58		error: bool,59		description: &str,60		source: &[Source],61	) -> impl Future<Output = Result<()>> + Send;62}63pub trait BlockingPrompter {64	fn prompt_radio(&self, prompt: &str, description: &str, source: &[Source]) -> Result<bool> {65		self.prompt_enum(prompt, description, &["No", "Yes"], source)66			.map(|v| v == 1)67	}68	fn prompt_enum(69		&self,70		prompt: &str,71		description: &str,72		variants: &[&str],73		source: &[Source],74	) -> Result<u32>;75	fn prompt_text(76		&self,77		echo: bool,78		prompt: &str,79		description: &str,80		source: &[Source],81	) -> Result<String>;82	fn display_text(&self, error: bool, description: &str, source: &[Source]) -> Result<()>;83}84impl<P> Prompter for &P85where86	P: Prompter,87{88	fn prompt_radio(89		&self,90		prompt: &str,91		description: &str,92		source: &[Source],93	) -> impl Future<Output = Result<bool>> + Send {94		(*self).prompt_radio(prompt, description, source)95	}9697	fn prompt_enum(98		&self,99		prompt: &str,100		description: &str,101		variants: &[&str],102		source: &[Source],103	) -> impl Future<Output = Result<u32>> + Send {104		(*self).prompt_enum(prompt, description, variants, source)105	}106107	fn prompt_text(108		&self,109		echo: bool,110		prompt: &str,111		description: &str,112		source: &[Source],113	) -> impl Future<Output = Result<String>> + Send {114		(*self).prompt_text(echo, prompt, description, source)115	}116117	fn display_text(118		&self,119		error: bool,120		description: &str,121		source: &[Source],122	) -> impl Future<Output = Result<()>> + Send {123		(*self).display_text(error, description, source)124	}125}126127pub struct PrependSourcePrompter<P> {128	pub prompter: P,129	pub source: Vec<Source>,130	pub description: String,131}132impl<P> PrependSourcePrompter<P> {133	fn source(&self, input: &[Source]) -> Vec<Source> {134		let mut out = self.source.clone();135		out.extend(input.iter().cloned());136		out137	}138	fn description(&self, input: &str) -> String {139		if self.description.is_empty() {140			input.to_owned()141		} else if input.is_empty() {142			self.description.to_owned()143		} else {144			format!("{input}\n\n{}", self.description)145		}146	}147}148impl<P> Prompter for PrependSourcePrompter<P>149where150	P: Prompter + Sync,151{152	async fn prompt_radio(153		&self,154		prompt: &str,155		description: &str,156		source: &[Source],157	) -> Result<bool> {158		self.prompter159			.prompt_radio(prompt, &self.description(description), &self.source(source))160			.await161	}162163	async fn prompt_enum(164		&self,165		prompt: &str,166		description: &str,167		variants: &[&str],168		source: &[Source],169	) -> Result<u32> {170		self.prompter171			.prompt_enum(172				prompt,173				&self.description(description),174				variants,175				&self.source(source),176			)177			.await178	}179180	async fn prompt_text(181		&self,182		echo: bool,183		prompt: &str,184		description: &str,185		source: &[Source],186	) -> Result<String> {187		self.prompter188			.prompt_text(189				echo,190				prompt,191				&self.description(description),192				&self.source(source),193			)194			.await195	}196197	async fn display_text(&self, error: bool, description: &str, source: &[Source]) -> Result<()> {198		self.prompter199			.display_text(error, &self.description(description), &self.source(source))200			.await201	}202}