Skip to content

Commit 9baa851

Browse files
committed
Implement Clone for all prompts, fixes console-rs#262
1 parent 5088e87 commit 9baa851

File tree

11 files changed

+173
-72
lines changed

11 files changed

+173
-72
lines changed

CHANGELOG.md

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,17 @@
55
### Enhancements
66

77
* Added `dialouger::Result` and `dialouger::Error`
8-
* Resolve some issues on Windows where pressing shift keys sometimes aborted dialogs.
9-
* Resolve `MultiSelect` checked and unchecked variants looking the same on Windows.
8+
* Added a `BasicHistory` implementation for `History`
9+
* Added vim mode for `FuzzySelect`
10+
* All prompts implement `Clone`
11+
12+
### Bug fixes
13+
14+
* Resolve some issues on Windows where pressing shift keys sometimes aborted dialogs
15+
* Resolve `MultiSelect` checked and unchecked variants looking the same on Windows
16+
* `Input` values that are invalid are now also stored in `History`
17+
* Resolve some issues with cursor positioning in `Input` when using `utf-8` characters
18+
* Correct page is shown when default selected option is not on the first page for `Select`
1019

1120
### Breaking
1221

@@ -16,6 +25,7 @@
1625
* Prompt builder functions now return `Self` instead of `&mut Self`
1726
* Prompt interaction functions now take `self` instead of `&self`
1827
* Prompt interaction functions and other operations now return `dialouger::Result` instead of `std::io::Result`
28+
* Rename `Validator` to `InputValidator`
1929

2030
## 0.10.4
2131

@@ -111,7 +121,7 @@
111121

112122
## 0.6.1
113123

114-
### Bugfixes
124+
### Bug fixes
115125

116126
* `theme::ColorfulTheme` default styles are for stderr
117127

src/history.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ pub trait History<T> {
66
/// be read from history. The `pos` represents the number
77
/// of times the `Up`/`Down` arrow key has been pressed.
88
/// This would normally be used as an index to some sort
9-
/// of vector. If the `pos` does not have an entry, [`None`](Option::None)
9+
/// of vector. If the `pos` does not have an entry, [`None`](Option::None)
1010
/// should be returned.
1111
fn read(&self, pos: usize) -> Option<String>;
1212

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ pub use error::{Error, Result};
4141
#[cfg(feature = "history")]
4242
pub use history::{BasicHistory, History};
4343
use paging::Paging;
44-
pub use validate::Validator;
44+
pub use validate::{InputValidator, PasswordValidator};
4545

4646
#[cfg(feature = "fuzzy-select")]
4747
pub use prompts::fuzzy_select::FuzzySelect;

src/prompts/confirm.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ use crate::{
2727
/// }
2828
/// }
2929
/// ```
30+
#[derive(Clone)]
3031
pub struct Confirm<'a> {
3132
prompt: String,
3233
report: bool,
@@ -262,3 +263,15 @@ impl<'a> Confirm<'a> {
262263
}
263264
}
264265
}
266+
267+
#[cfg(test)]
268+
mod tests {
269+
use super::*;
270+
271+
#[test]
272+
fn test_clone() {
273+
let confirm = Confirm::new().with_prompt("Do you want to continue?");
274+
275+
let _ = confirm.clone();
276+
}
277+
}

src/prompts/fuzzy_select.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use crate::{
3030
/// println!("You chose: {}", items[selection]);
3131
/// }
3232
/// ```
33-
33+
#[derive(Clone)]
3434
pub struct FuzzySelect<'a> {
3535
default: Option<usize>,
3636
items: Vec<String>,
@@ -382,3 +382,15 @@ impl<'a> FuzzySelect<'a> {
382382
}
383383
}
384384
}
385+
386+
#[cfg(test)]
387+
mod tests {
388+
use super::*;
389+
390+
#[test]
391+
fn test_clone() {
392+
let fuzzy_select = FuzzySelect::new().with_prompt("Do you want to continue?");
393+
394+
let _ = fuzzy_select.clone();
395+
}
396+
}

src/prompts/input.rs

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
use std::{cmp::Ordering, fmt::Debug, io, iter, str::FromStr};
1+
use std::{
2+
cmp::Ordering,
3+
fmt::Debug,
4+
io, iter,
5+
str::FromStr,
6+
sync::{Arc, Mutex},
7+
};
28

39
use console::{Key, Term};
410

@@ -8,11 +14,11 @@ use crate::completion::Completion;
814
use crate::history::History;
915
use crate::{
1016
theme::{render::TermThemeRenderer, SimpleTheme, Theme},
11-
validate::Validator,
17+
validate::InputValidator,
1218
Result,
1319
};
1420

15-
type ValidatorCallback<'a, T> = Box<dyn FnMut(&T) -> Option<String> + 'a>;
21+
type InputValidatorCallback<'a, T> = Arc<Mutex<dyn FnMut(&T) -> Option<String> + 'a>>;
1622

1723
/// Renders an input prompt.
1824
///
@@ -45,6 +51,7 @@ type ValidatorCallback<'a, T> = Box<dyn FnMut(&T) -> Option<String> + 'a>;
4551
/// println!("Your name is: {}", name);
4652
/// }
4753
/// ```
54+
#[derive(Clone)]
4855
pub struct Input<'a, T> {
4956
prompt: String,
5057
post_completion_text: Option<String>,
@@ -54,9 +61,9 @@ pub struct Input<'a, T> {
5461
initial_text: Option<String>,
5562
theme: &'a dyn Theme,
5663
permit_empty: bool,
57-
validator: Option<ValidatorCallback<'a, T>>,
64+
validator: Option<InputValidatorCallback<'a, T>>,
5865
#[cfg(feature = "history")]
59-
history: Option<&'a mut dyn History<T>>,
66+
history: Option<Arc<Mutex<&'a mut dyn History<T>>>>,
6067
#[cfg(feature = "completion")]
6168
completion: Option<&'a dyn Completion>,
6269
}
@@ -207,7 +214,7 @@ impl<'a, T> Input<'a, T> {
207214
where
208215
H: History<T>,
209216
{
210-
self.history = Some(history);
217+
self.history = Some(Arc::new(Mutex::new(history)));
211218
self
212219
}
213220

@@ -249,14 +256,14 @@ where
249256
/// ```
250257
pub fn validate_with<V>(mut self, mut validator: V) -> Self
251258
where
252-
V: Validator<T> + 'a,
259+
V: InputValidator<T> + 'a,
253260
V::Err: ToString,
254261
{
255262
let mut old_validator_func = self.validator.take();
256263

257-
self.validator = Some(Box::new(move |value: &T| -> Option<String> {
264+
self.validator = Some(Arc::new(Mutex::new(move |value: &T| -> Option<String> {
258265
if let Some(old) = old_validator_func.as_mut() {
259-
if let Some(err) = old(value) {
266+
if let Some(err) = old.lock().unwrap()(value) {
260267
return Some(err);
261268
}
262269
}
@@ -265,7 +272,7 @@ where
265272
Ok(()) => None,
266273
Err(err) => Some(err.to_string()),
267274
}
268-
}));
275+
})));
269276

270277
self
271278
}
@@ -491,7 +498,7 @@ where
491498
Key::ArrowUp => {
492499
let line_size = term.size().1 as usize;
493500
if let Some(history) = &self.history {
494-
if let Some(previous) = history.read(hist_pos) {
501+
if let Some(previous) = history.lock().unwrap().read(hist_pos) {
495502
hist_pos += 1;
496503
let mut chars_len = chars.len();
497504
while ((prompt_len + chars_len) / line_size) > 0 {
@@ -550,7 +557,7 @@ where
550557
hist_pos = pos;
551558
// Move it back again to get the previous history entry
552559
if let Some(pos) = pos.checked_sub(1) {
553-
if let Some(previous) = history.read(pos) {
560+
if let Some(previous) = history.lock().unwrap().read(pos) {
554561
for ch in previous.chars() {
555562
chars.insert(position, ch);
556563
position += 1;
@@ -574,7 +581,7 @@ where
574581
if chars.is_empty() {
575582
if let Some(ref default) = self.default {
576583
if let Some(ref mut validator) = self.validator {
577-
if let Some(err) = validator(default) {
584+
if let Some(err) = validator.lock().unwrap()(default) {
578585
render.error(&err)?;
579586
continue;
580587
}
@@ -594,11 +601,11 @@ where
594601
Ok(value) => {
595602
#[cfg(feature = "history")]
596603
if let Some(history) = &mut self.history {
597-
history.write(&value);
604+
history.lock().unwrap().write(&value);
598605
}
599606

600607
if let Some(ref mut validator) = self.validator {
601-
if let Some(err) = validator(&value) {
608+
if let Some(err) = validator.lock().unwrap()(&value) {
602609
render.error(&err)?;
603610
continue;
604611
}
@@ -675,7 +682,7 @@ where
675682
if input.is_empty() {
676683
if let Some(ref default) = self.default {
677684
if let Some(ref mut validator) = self.validator {
678-
if let Some(err) = validator(default) {
685+
if let Some(err) = validator.lock().unwrap()(default) {
679686
render.error(&err)?;
680687
continue;
681688
}
@@ -694,7 +701,7 @@ where
694701
match input.parse::<T>() {
695702
Ok(value) => {
696703
if let Some(ref mut validator) = self.validator {
697-
if let Some(err) = validator(&value) {
704+
if let Some(err) = validator.lock().unwrap()(&value) {
698705
render.error(&err)?;
699706
continue;
700707
}
@@ -715,3 +722,15 @@ where
715722
}
716723
}
717724
}
725+
726+
#[cfg(test)]
727+
mod tests {
728+
use super::*;
729+
730+
#[test]
731+
fn test_clone() {
732+
let input = Input::<String>::new().with_prompt("Your name");
733+
734+
let _ = input.clone();
735+
}
736+
}

src/prompts/multi_select.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ use crate::{
3030
/// }
3131
/// }
3232
/// ```
33+
#[derive(Clone)]
3334
pub struct MultiSelect<'a> {
3435
defaults: Vec<bool>,
3536
items: Vec<String>,
@@ -370,3 +371,15 @@ impl<'a> MultiSelect<'a> {
370371
}
371372
}
372373
}
374+
375+
#[cfg(test)]
376+
mod tests {
377+
use super::*;
378+
379+
#[test]
380+
fn test_clone() {
381+
let multi_select = MultiSelect::new().with_prompt("Select your favorite(s)");
382+
383+
let _ = multi_select.clone();
384+
}
385+
}

0 commit comments

Comments
 (0)