git.delta.rocks / fleet / refs/commits / 0ea4b47ffa04

difftreelog

source

remowt/crates/remowt-ui-prompt/src/lib.rs4.2 KiBsourcehistory
1use core::fmt;2use std::borrow::Cow;3use std::future::Future;4use std::result;56pub mod auto;7pub mod bifrost;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#[derive(serde::Serialize, serde::Deserialize, Clone)]23pub struct Source(pub Cow<'static, str>);24impl fmt::Display for Source {25	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {26		write!(f, "<u>{}</u>", self.0)27	}28}2930pub trait Prompter: Send + Sync {31	fn prompt_radio(32		&self,33		prompt: &str,34		description: &str,35		source: &[Source],36	) -> impl Future<Output = Result<bool>> + Send {37		let fut = self.prompt_enum(prompt, description, &["No", "Yes"], source);38		async { fut.await.map(|v| v == 1) }39	}40	fn prompt_enum(41		&self,42		prompt: &str,43		description: &str,44		variants: &[&str],45		source: &[Source],46	) -> impl Future<Output = Result<u32>> + Send;47	fn prompt_text(48		&self,49		echo: bool,50		prompt: &str,51		description: &str,52		source: &[Source],53	) -> impl Future<Output = Result<String>> + Send;54	fn display_text(55		&self,56		error: bool,57		description: &str,58		source: &[Source],59	) -> impl Future<Output = Result<()>> + Send;60}61pub trait BlockingPrompter {62	fn prompt_radio(&self, prompt: &str, description: &str, source: &[Source]) -> Result<bool> {63		self.prompt_enum(prompt, description, &["No", "Yes"], source)64			.map(|v| v == 1)65	}66	fn prompt_enum(67		&self,68		prompt: &str,69		description: &str,70		variants: &[&str],71		source: &[Source],72	) -> Result<u32>;73	fn prompt_text(74		&self,75		echo: bool,76		prompt: &str,77		description: &str,78		source: &[Source],79	) -> Result<String>;80	fn display_text(&self, error: bool, description: &str, source: &[Source]) -> Result<()>;81}82impl<P> Prompter for &P83where84	P: Prompter,85{86	fn prompt_radio(87		&self,88		prompt: &str,89		description: &str,90		source: &[Source],91	) -> impl Future<Output = Result<bool>> + Send {92		(*self).prompt_radio(prompt, description, source)93	}9495	fn prompt_enum(96		&self,97		prompt: &str,98		description: &str,99		variants: &[&str],100		source: &[Source],101	) -> impl Future<Output = Result<u32>> + Send {102		(*self).prompt_enum(prompt, description, variants, source)103	}104105	fn prompt_text(106		&self,107		echo: bool,108		prompt: &str,109		description: &str,110		source: &[Source],111	) -> impl Future<Output = Result<String>> + Send {112		(*self).prompt_text(echo, prompt, description, source)113	}114115	fn display_text(116		&self,117		error: bool,118		description: &str,119		source: &[Source],120	) -> impl Future<Output = Result<()>> + Send {121		(*self).display_text(error, description, source)122	}123}124125pub struct PrependSourcePrompter<P> {126	pub prompter: P,127	pub source: Vec<Source>,128	pub description: String,129}130impl<P> PrependSourcePrompter<P> {131	fn source(&self, input: &[Source]) -> Vec<Source> {132		let mut out = self.source.clone();133		out.extend(input.iter().cloned());134		out135	}136	fn description(&self, input: &str) -> String {137		if self.description.is_empty() {138			input.to_owned()139		} else if input.is_empty() {140			self.description.to_owned()141		} else {142			format!("{input}\n\n{}", self.description)143		}144	}145}146impl<P> Prompter for PrependSourcePrompter<P>147where148	P: Prompter + Sync,149{150	async fn prompt_radio(151		&self,152		prompt: &str,153		description: &str,154		source: &[Source],155	) -> Result<bool> {156		self.prompter157			.prompt_radio(prompt, &self.description(description), &self.source(source))158			.await159	}160161	async fn prompt_enum(162		&self,163		prompt: &str,164		description: &str,165		variants: &[&str],166		source: &[Source],167	) -> Result<u32> {168		self.prompter169			.prompt_enum(170				prompt,171				&self.description(description),172				variants,173				&self.source(source),174			)175			.await176	}177178	async fn prompt_text(179		&self,180		echo: bool,181		prompt: &str,182		description: &str,183		source: &[Source],184	) -> Result<String> {185		self.prompter186			.prompt_text(187				echo,188				prompt,189				&self.description(description),190				&self.source(source),191			)192			.await193	}194195	async fn display_text(&self, error: bool, description: &str, source: &[Source]) -> Result<()> {196		self.prompter197			.display_text(error, &self.description(description), &self.source(source))198			.await199	}200}