pijul_interaction/input/
mod.rs1mod non_interactive;
3mod terminal;
4
5use crate::{Confirm, Input, Password, Select};
6use crate::{InteractionError, InteractiveContext, PromptType};
7use dialoguer::theme;
8use duplicate::duplicate_item;
9use lazy_static::lazy_static;
10use non_interactive::PseudoInteractive;
11
12lazy_static! {
13 static ref THEME: Box<dyn theme::Theme + Send + Sync> = {
14 use dialoguer::theme;
15 use pijul_config::{self as config, Choice};
16
17 if let Ok((config, _)) = config::Global::load() {
18 let color_choice = config.colors.unwrap_or_default();
19
20 match color_choice {
21 Choice::Auto | Choice::Always => Box::<theme::ColorfulTheme>::default(),
22 Choice::Never => Box::new(theme::SimpleTheme),
23 }
24 } else {
25 Box::<theme::ColorfulTheme>::default()
26 }
27 };
28}
29
30pub trait BasePrompt<T> {
33 fn set_prompt(&mut self, prompt: String);
34 fn interact(&mut self) -> Result<T, InteractionError>;
35}
36
37pub trait DefaultPrompt<T>: BasePrompt<T> {
39 fn set_default(&mut self, value: T);
40}
41
42pub trait ValidationPrompt<T>: BasePrompt<T> {
47 fn allow_empty(&mut self, empty: bool);
48 fn set_validator(&mut self, validator: Box<dyn Fn(&T) -> Result<(), String>>);
49}
50
51pub trait PasswordPrompt<T>: ValidationPrompt<T> {
53 fn set_confirmation(&mut self, confirm_prompt: String, mismatch_err: String);
54}
55
56pub trait TextPrompt<T>: ValidationPrompt<T> + DefaultPrompt<T> {
59 fn set_inital_text(&mut self, text: String);
60}
61
62pub trait SelectionPrompt<T>: DefaultPrompt<T> {
64 fn add_items(&mut self, items: &[String]);
65}
66
67#[duplicate_item(
68 handler prompt_type return_type;
69 [Confirm] [PromptType::Confirm] [bool];
70 [Input] [PromptType::Input] [String];
71 [Select] [PromptType::Select] [usize];
72 [Password] [PromptType::Password] [String];
73)]
74impl handler {
75 pub fn new() -> Result<Self, InteractionError> {
77 Ok(Self(match crate::get_context()? {
78 InteractiveContext::Terminal => Box::new(terminal::handler::with_theme(THEME.as_ref())),
79 InteractiveContext::NotInteractive => Box::new(PseudoInteractive::new(prompt_type)),
80 }))
81 }
82
83 pub fn set_prompt(&mut self, prompt: String) {
85 self.0.set_prompt(prompt);
86 }
87
88 pub fn with_prompt<S: ToString>(&mut self, prompt: S) -> &mut Self {
90 self.set_prompt(prompt.to_string());
91 self
92 }
93
94 pub fn interact(&mut self) -> Result<return_type, InteractionError> {
97 self.0.interact()
98 }
99}
100
101#[duplicate_item(
102 handler return_type;
103 [Confirm] [bool];
104 [Input] [String];
105 [Select] [usize];
106)]
107impl handler {
108 pub fn set_default(&mut self, value: return_type) {
110 self.0.set_default(value);
111 }
112
113 pub fn with_default<I: Into<return_type>>(&mut self, value: I) -> &mut Self {
115 self.set_default(value.into());
116 self
117 }
118}
119
120impl Select {
121 pub fn add_items<S: ToString>(&mut self, items: &[S]) {
123 let string_items: Vec<String> = items.iter().map(ToString::to_string).collect();
124 self.0.add_items(string_items.as_slice());
125 }
126
127 pub fn with_items<S: ToString>(&mut self, items: &[S]) -> &mut Self {
131 self.add_items(items);
132 self
133 }
134}
135
136impl Password {
137 pub fn set_confirmation<S: ToString>(&mut self, confirm_prompt: S, mismatch_err: S) {
139 self.0
140 .set_confirmation(confirm_prompt.to_string(), mismatch_err.to_string());
141 }
142
143 pub fn with_confirmation<S: ToString>(
145 &mut self,
146 confirm_prompt: S,
147 mismatch_err: S,
148 ) -> &mut Self {
149 self.set_confirmation(confirm_prompt, mismatch_err);
150 self
151 }
152}
153
154#[duplicate_item(
155 handler prompt_type;
156 [Input] [PromptType::Input];
157 [Password] [PromptType::Password];
158)]
159impl handler {
160 pub fn set_allow_empty(&mut self, empty: bool) {
162 self.0.allow_empty(empty);
163 }
164
165 pub fn with_allow_empty(&mut self, empty: bool) -> &mut Self {
167 self.set_allow_empty(empty);
168 self
169 }
170
171 pub fn set_validator<V, E>(&mut self, validator: V)
174 where
175 V: Fn(&String) -> Result<(), E> + 'static,
176 E: ToString,
177 {
178 self.0
179 .set_validator(Box::new(move |input| match validator(input) {
180 Ok(()) => Ok(()),
181 Err(e) => Err(e.to_string()),
182 }));
183 }
184
185 pub fn with_validator<V, E>(&mut self, validator: V) -> &mut Self
187 where
188 V: Fn(&String) -> Result<(), E> + 'static,
189 E: ToString,
190 {
191 self.set_validator(validator);
192 self
193 }
194}
195
196impl Input {
197 pub fn set_inital_text<S: ToString>(&mut self, text: S) {
198 self.0.set_inital_text(text.to_string());
199 }
200
201 pub fn with_initial_text<S: ToString>(&mut self, text: S) -> &mut Self {
202 self.set_inital_text(text);
203 self
204 }
205}