git.delta.rocks / remowt / refs/commits / d819a0103251

difftreelog

source

crates/ui-prompt/src/lib.rs4.0 KiBsourcehistory
1use core::fmt;2use std::borrow::Cow;3use std::future::Future;4use std::result;56pub mod dbus;7pub mod rofi;89#[derive(thiserror::Error, Debug)]10pub enum Error {11    #[error("user has cancelled input")]12    Cancel,13    #[error("input error: {0}")]14    InputError(String),15}1617pub type Result<T, E = Error> = result::Result<T, E>;1819#[cfg_attr(feature = "dbus", derive(zbus::zvariant::Type))]20#[derive(serde::Serialize, serde::Deserialize, Clone)]21pub struct Source(pub Cow<'static, str>);22impl fmt::Display for Source {23    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {24        write!(f, "<u>{}</u>", self.0)25    }26}2728pub trait Prompter {29    fn prompt_radio(30        &self,31        prompt: &str,32        description: &str,33        source: &[Source],34    ) -> impl Future<Output = Result<bool>> + Send {35        let fut = self.prompt_enum(prompt, description, &["No", "Yes"], source);36        async { fut.await.map(|v| v == 1) }37    }38    fn prompt_enum(39        &self,40        prompt: &str,41        description: &str,42        variants: &[&str],43        source: &[Source],44    ) -> impl Future<Output = Result<u32>> + Send;45    fn prompt_text(46        &self,47        echo: bool,48        prompt: &str,49        description: &str,50        source: &[Source],51    ) -> impl Future<Output = Result<String>> + Send;52    fn display_text(53        &self,54        error: bool,55        description: &str,56        source: &[Source],57    ) -> impl Future<Output = Result<()>> + Send;58}59pub trait BlockingPrompter {60    fn prompt_radio(&self, prompt: &str, description: &str, source: &[Source]) -> Result<bool> {61        self.prompt_enum(prompt, description, &["No", "Yes"], source)62            .map(|v| v == 1)63    }64    fn prompt_enum(65        &self,66        prompt: &str,67        description: &str,68        variants: &[&str],69        source: &[Source],70    ) -> Result<u32>;71    fn prompt_text(72        &self,73        echo: bool,74        prompt: &str,75        description: &str,76        source: &[Source],77    ) -> Result<String>;78    fn display_text(&self, error: bool, description: &str, source: &[Source]) -> Result<()>;79}8081pub struct PrependSourcePrompter<P> {82    pub prompter: P,83    pub source: Vec<Source>,84    pub description: String,85}86impl<P> PrependSourcePrompter<P> {87    fn source(&self, input: &[Source]) -> Vec<Source> {88        let mut out = self.source.clone();89        out.extend(input.iter().cloned());90        out91    }92    fn description(&self, input: &str) -> String {93        if self.description.is_empty() {94            input.to_owned()95        } else if input.is_empty() {96            self.description.to_owned()97        } else {98            format!("{input}\n\n{}", self.description)99        }100    }101}102impl<P> Prompter for PrependSourcePrompter<P>103where104    P: Prompter + Sync,105{106    async fn prompt_radio(107        &self,108        prompt: &str,109        description: &str,110        source: &[Source],111    ) -> Result<bool> {112        self.prompter113            .prompt_radio(prompt, &self.description(description), &self.source(source))114            .await115    }116117    async fn prompt_enum(118        &self,119        prompt: &str,120        description: &str,121        variants: &[&str],122        source: &[Source],123    ) -> Result<u32> {124        self.prompter125            .prompt_enum(126                prompt,127                dbg!(&self.description(description)),128                variants,129                &self.source(source),130            )131            .await132    }133134    async fn prompt_text(135        &self,136        echo: bool,137        prompt: &str,138        description: &str,139        source: &[Source],140    ) -> Result<String> {141        self.prompter142            .prompt_text(143                echo,144                prompt,145                &self.description(description),146                &self.source(source),147            )148            .await149    }150151    async fn display_text(&self, error: bool, description: &str, source: &[Source]) -> Result<()> {152        self.prompter153            .display_text(error, &self.description(description), &self.source(source))154            .await155    }156}