Skip to content

Commit 44cf638

Browse files
committed
Introduce error
1 parent 8cbb665 commit 44cf638

File tree

12 files changed

+130
-109
lines changed

12 files changed

+130
-109
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ tempfile = { version = "3", optional = true }
3030
zeroize = { version = "1.1.1", optional = true }
3131
fuzzy-matcher = { version = "0.3.7", optional = true }
3232
shell-words = "1.1.0"
33+
thiserror = "1.0.40"
3334

3435
[[example]]
3536
name = "password"

src/error.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
use std::{io::Error as IoError, result::Result as StdResult};
2+
3+
use thiserror::Error;
4+
5+
/// Possible errors returned by prompts.
6+
#[derive(Error, Debug)]
7+
pub enum Error {
8+
/// Error while executing IO operations.
9+
#[error("IO error: {0}")]
10+
IO(#[from] IoError),
11+
}
12+
13+
/// Result type where errors are of type [Error](crate::error::Error)
14+
pub type Result<T = ()> = StdResult<T, Error>;

src/lib.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,24 +36,24 @@ pub use completion::Completion;
3636
pub use console;
3737
#[cfg(feature = "editor")]
3838
pub use edit::Editor;
39+
pub use error::{Error, Result};
3940
#[cfg(feature = "history")]
4041
pub use history::History;
4142
use paging::Paging;
42-
pub use prompts::{
43-
confirm::Confirm, input::Input, multi_select::MultiSelect, select::Select, sort::Sort,
44-
};
45-
pub use validate::Validator;
46-
4743
#[cfg(feature = "fuzzy-select")]
4844
pub use prompts::fuzzy_select::FuzzySelect;
49-
5045
#[cfg(feature = "password")]
5146
pub use prompts::password::Password;
47+
pub use prompts::{
48+
confirm::Confirm, input::Input, multi_select::MultiSelect, select::Select, sort::Sort,
49+
};
50+
pub use validate::Validator;
5251

5352
#[cfg(feature = "completion")]
5453
mod completion;
5554
#[cfg(feature = "editor")]
5655
mod edit;
56+
mod error;
5757
#[cfg(feature = "history")]
5858
mod history;
5959
mod paging;

src/paging.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ use std::io;
22

33
use console::Term;
44

5+
use crate::Result;
6+
57
/// Creates a paging module
68
///
79
/// The paging module serves as tracking structure to allow paged views
@@ -78,9 +80,9 @@ impl<'a> Paging<'a> {
7880
/// Renders a prompt when the following conditions are met:
7981
/// * Paging is active
8082
/// * Transition of the paging activity happened (active -> inactive / inactive -> active)
81-
pub fn render_prompt<F>(&mut self, mut render_prompt: F) -> io::Result<()>
83+
pub fn render_prompt<F>(&mut self, mut render_prompt: F) -> Result
8284
where
83-
F: FnMut(Option<(usize, usize)>) -> io::Result<()>,
85+
F: FnMut(Option<(usize, usize)>) -> Result,
8486
{
8587
if self.active {
8688
let paging_info = Some((self.current_page + 1, self.pages));

src/prompts/confirm.rs

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
use std::io;
22

3-
use crate::theme::{SimpleTheme, TermThemeRenderer, Theme};
3+
use crate::{
4+
theme::{SimpleTheme, TermThemeRenderer, Theme},
5+
Result,
6+
};
47

58
use console::{Key, Term};
69

@@ -101,7 +104,7 @@ impl Confirm<'_> {
101104
/// Result contains `bool` if user answered "yes" or "no" or `default` (configured in [`default`](Self::default) if pushes enter.
102105
/// This unlike [`interact_opt`](Self::interact_opt) does not allow to quit with 'Esc' or 'q'.
103106
#[inline]
104-
pub fn interact(&self) -> io::Result<bool> {
107+
pub fn interact(&self) -> Result<bool> {
105108
self.interact_on(&Term::stderr())
106109
}
107110

@@ -112,7 +115,7 @@ impl Confirm<'_> {
112115
/// Result contains `Some(bool)` if user answered "yes" or "no" or `Some(default)` (configured in [`default`](Self::default)) if pushes enter,
113116
/// or `None` if user cancelled with 'Esc' or 'q'.
114117
#[inline]
115-
pub fn interact_opt(&self) -> io::Result<Option<bool>> {
118+
pub fn interact_opt(&self) -> Result<Option<bool>> {
116119
self.interact_on_opt(&Term::stderr())
117120
}
118121

@@ -132,9 +135,10 @@ impl Confirm<'_> {
132135
/// # }
133136
/// ```
134137
#[inline]
135-
pub fn interact_on(&self, term: &Term) -> io::Result<bool> {
136-
self._interact_on(term, false)?
137-
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Quit not allowed in this case"))
138+
pub fn interact_on(&self, term: &Term) -> Result<bool> {
139+
Ok(self
140+
._interact_on(term, false)?
141+
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Quit not allowed in this case"))?)
138142
}
139143

140144
/// Like [`interact_opt`](Self::interact_opt) but allows a specific terminal to be set.
@@ -157,11 +161,11 @@ impl Confirm<'_> {
157161
/// }
158162
/// ```
159163
#[inline]
160-
pub fn interact_on_opt(&self, term: &Term) -> io::Result<Option<bool>> {
164+
pub fn interact_on_opt(&self, term: &Term) -> Result<Option<bool>> {
161165
self._interact_on(term, true)
162166
}
163167

164-
fn _interact_on(&self, term: &Term, allow_quit: bool) -> io::Result<Option<bool>> {
168+
fn _interact_on(&self, term: &Term, allow_quit: bool) -> Result<Option<bool>> {
165169
let mut render = TermThemeRenderer::new(term, self.theme);
166170

167171
let default_if_show = if self.show_default {
@@ -210,7 +214,7 @@ impl Confirm<'_> {
210214
return Err(io::Error::new(
211215
io::ErrorKind::NotConnected,
212216
"Not a terminal",
213-
))
217+
))?;
214218
}
215219
_ => {
216220
continue;
@@ -234,7 +238,7 @@ impl Confirm<'_> {
234238
return Err(io::Error::new(
235239
io::ErrorKind::NotConnected,
236240
"Not a terminal",
237-
))
241+
))?;
238242
}
239243
_ => {
240244
continue;

src/prompts/fuzzy_select.rs

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
1-
use crate::theme::{SimpleTheme, TermThemeRenderer, Theme};
1+
use std::{io, ops::Rem};
2+
23
use console::{Key, Term};
34
use fuzzy_matcher::FuzzyMatcher;
4-
use std::{io, ops::Rem};
5+
6+
use crate::{
7+
theme::{SimpleTheme, TermThemeRenderer, Theme},
8+
Result,
9+
};
510

611
/// Renders a selection menu that user can fuzzy match to reduce set.
712
///
@@ -135,7 +140,7 @@ impl FuzzySelect<'_> {
135140
/// Result contains `index` of selected item if user hit 'Enter'.
136141
/// This unlike [interact_opt](#method.interact_opt) does not allow to quit with 'Esc' or 'q'.
137142
#[inline]
138-
pub fn interact(&self) -> io::Result<usize> {
143+
pub fn interact(&self) -> Result<usize> {
139144
self.interact_on(&Term::stderr())
140145
}
141146

@@ -145,25 +150,26 @@ impl FuzzySelect<'_> {
145150
/// The dialog is rendered on stderr.
146151
/// Result contains `Some(index)` if user hit 'Enter' or `None` if user cancelled with 'Esc' or 'q'.
147152
#[inline]
148-
pub fn interact_opt(&self) -> io::Result<Option<usize>> {
153+
pub fn interact_opt(&self) -> Result<Option<usize>> {
149154
self.interact_on_opt(&Term::stderr())
150155
}
151156

152157
/// Like `interact` but allows a specific terminal to be set.
153158
#[inline]
154-
pub fn interact_on(&self, term: &Term) -> io::Result<usize> {
155-
self._interact_on(term, false)?
156-
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Quit not allowed in this case"))
159+
pub fn interact_on(&self, term: &Term) -> Result<usize> {
160+
Ok(self
161+
._interact_on(term, false)?
162+
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Quit not allowed in this case"))?)
157163
}
158164

159165
/// Like `interact` but allows a specific terminal to be set.
160166
#[inline]
161-
pub fn interact_on_opt(&self, term: &Term) -> io::Result<Option<usize>> {
167+
pub fn interact_on_opt(&self, term: &Term) -> Result<Option<usize>> {
162168
self._interact_on(term, true)
163169
}
164170

165171
/// Like `interact` but allows a specific terminal to be set.
166-
fn _interact_on(&self, term: &Term, allow_quit: bool) -> io::Result<Option<usize>> {
172+
fn _interact_on(&self, term: &Term, allow_quit: bool) -> Result<Option<usize>> {
167173
// Place cursor at the end of the search term
168174
let mut position = self.initial_text.len();
169175
let mut search_term = self.initial_text.to_owned();

src/prompts/input.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
use std::{cmp::Ordering, fmt::Debug, io, iter, str::FromStr};
1+
use std::{cmp::Ordering, fmt::Debug, iter, str::FromStr};
2+
3+
use console::{Key, Term};
24

35
#[cfg(feature = "completion")]
46
use crate::completion::Completion;
@@ -7,10 +9,9 @@ use crate::history::History;
79
use crate::{
810
theme::{SimpleTheme, TermThemeRenderer, Theme},
911
validate::Validator,
12+
Result,
1013
};
1114

12-
use console::{Key, Term};
13-
1415
type ValidatorCallback<'a, T> = Box<dyn FnMut(&T) -> Option<String> + 'a>;
1516

1617
/// Renders an input prompt.
@@ -264,12 +265,12 @@ where
264265
/// while [`interact`](#method.interact) allows virtually any character to be used e.g arrow keys.
265266
///
266267
/// The dialog is rendered on stderr.
267-
pub fn interact_text(&mut self) -> io::Result<T> {
268+
pub fn interact_text(&mut self) -> Result<T> {
268269
self.interact_text_on(&Term::stderr())
269270
}
270271

271272
/// Like [`interact_text`](#method.interact_text) but allows a specific terminal to be set.
272-
pub fn interact_text_on(&mut self, term: &Term) -> io::Result<T> {
273+
pub fn interact_text_on(&mut self, term: &Term) -> Result<T> {
273274
let mut render = TermThemeRenderer::new(term, self.theme);
274275

275276
loop {
@@ -615,12 +616,12 @@ where
615616
///
616617
/// If the user confirms the result is `true`, `false` otherwise.
617618
/// The dialog is rendered on stderr.
618-
pub fn interact(&mut self) -> io::Result<T> {
619+
pub fn interact(&mut self) -> Result<T> {
619620
self.interact_on(&Term::stderr())
620621
}
621622

622623
/// Like [`interact`](#method.interact) but allows a specific terminal to be set.
623-
pub fn interact_on(&mut self, term: &Term) -> io::Result<T> {
624+
pub fn interact_on(&mut self, term: &Term) -> Result<T> {
624625
let mut render = TermThemeRenderer::new(term, self.theme);
625626

626627
loop {

src/prompts/multi_select.rs

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
use std::{io, iter::repeat, ops::Rem};
22

3+
use console::{Key, Term};
4+
35
use crate::{
46
theme::{SimpleTheme, TermThemeRenderer, Theme},
5-
Paging,
7+
Paging, Result,
68
};
79

8-
use console::{Key, Term};
9-
1010
/// Renders a multi select prompt.
1111
///
1212
/// ## Example usage
@@ -132,7 +132,7 @@ impl MultiSelect<'_> {
132132
/// Result contains `Vec<index>` if user hit 'Enter'.
133133
/// This unlike [`interact_opt`](Self::interact_opt) does not allow to quit with 'Esc' or 'q'.
134134
#[inline]
135-
pub fn interact(&self) -> io::Result<Vec<usize>> {
135+
pub fn interact(&self) -> Result<Vec<usize>> {
136136
self.interact_on(&Term::stderr())
137137
}
138138

@@ -142,7 +142,7 @@ impl MultiSelect<'_> {
142142
/// The dialog is rendered on stderr.
143143
/// Result contains `Some(Vec<index>)` if user hit 'Enter' or `None` if user cancelled with 'Esc' or 'q'.
144144
#[inline]
145-
pub fn interact_opt(&self) -> io::Result<Option<Vec<usize>>> {
145+
pub fn interact_opt(&self) -> Result<Option<Vec<usize>>> {
146146
self.interact_on_opt(&Term::stderr())
147147
}
148148

@@ -165,9 +165,10 @@ impl MultiSelect<'_> {
165165
/// }
166166
///```
167167
#[inline]
168-
pub fn interact_on(&self, term: &Term) -> io::Result<Vec<usize>> {
169-
self._interact_on(term, false)?
170-
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Quit not allowed in this case"))
168+
pub fn interact_on(&self, term: &Term) -> Result<Vec<usize>> {
169+
Ok(self
170+
._interact_on(term, false)?
171+
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Quit not allowed in this case"))?)
171172
}
172173

173174
/// Like [`interact_opt`](Self::interact_opt) but allows a specific terminal to be set.
@@ -192,16 +193,16 @@ impl MultiSelect<'_> {
192193
/// }
193194
/// ```
194195
#[inline]
195-
pub fn interact_on_opt(&self, term: &Term) -> io::Result<Option<Vec<usize>>> {
196+
pub fn interact_on_opt(&self, term: &Term) -> Result<Option<Vec<usize>>> {
196197
self._interact_on(term, true)
197198
}
198199

199-
fn _interact_on(&self, term: &Term, allow_quit: bool) -> io::Result<Option<Vec<usize>>> {
200+
fn _interact_on(&self, term: &Term, allow_quit: bool) -> Result<Option<Vec<usize>>> {
200201
if self.items.is_empty() {
201202
return Err(io::Error::new(
202203
io::ErrorKind::Other,
203204
"Empty list of items given to `MultiSelect`",
204-
));
205+
))?;
205206
}
206207

207208
let mut paging = Paging::new(term, self.items.len(), self.max_length);

src/prompts/password.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
1-
use std::io;
1+
use console::Term;
2+
use zeroize::Zeroizing;
23

34
use crate::{
45
theme::{SimpleTheme, TermThemeRenderer, Theme},
56
validate::PasswordValidator,
7+
Result,
68
};
79

8-
use console::Term;
9-
use zeroize::Zeroizing;
10-
1110
type PasswordValidatorCallback<'a> = Box<dyn Fn(&String) -> Option<String> + 'a>;
1211

1312
/// Renders a password input prompt.
@@ -124,12 +123,12 @@ impl<'a> Password<'a> {
124123
///
125124
/// If the user confirms the result is `true`, `false` otherwise.
126125
/// The dialog is rendered on stderr.
127-
pub fn interact(&self) -> io::Result<String> {
126+
pub fn interact(&self) -> Result<String> {
128127
self.interact_on(&Term::stderr())
129128
}
130129

131130
/// Like `interact` but allows a specific terminal to be set.
132-
pub fn interact_on(&self, term: &Term) -> io::Result<String> {
131+
pub fn interact_on(&self, term: &Term) -> Result<String> {
133132
let mut render = TermThemeRenderer::new(term, self.theme);
134133
render.set_prompts_reset_height(false);
135134

@@ -163,7 +162,7 @@ impl<'a> Password<'a> {
163162
}
164163
}
165164

166-
fn prompt_password(&self, render: &mut TermThemeRenderer, prompt: &str) -> io::Result<String> {
165+
fn prompt_password(&self, render: &mut TermThemeRenderer, prompt: &str) -> Result<String> {
167166
loop {
168167
render.password_prompt(prompt)?;
169168
render.term().flush()?;

0 commit comments

Comments
 (0)