Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: move from console to crossterm #213

Closed
wants to merge 22 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
7004341
Replace console::Key by crossterm::KeyCode, part 1.
grunweg Jul 10, 2022
9bd2dd8
Replace console::Key by crossterm::KeyCode, part 2.
grunweg Jul 10, 2022
56a89c0
Replace console::Key by crossterm::KeyCode, part 3.
grunweg Jul 10, 2022
a857b75
cargo fmt
grunweg Jul 10, 2022
d295ca6
TEMP comment out most files with compile errors: all but theme and co…
grunweg Jul 10, 2022
ac4a99f
Remove uses of console::Term, part 1: mechanically remove all uses of…
grunweg Jul 10, 2022
400df55
Allow flushing the terminal via TermThemeRenderer.
grunweg Jul 10, 2022
528c0df
Remove clear_line() calls in input.rs.
grunweg Jul 10, 2022
8d19d22
Port input.rs to crossterm.
grunweg Jul 10, 2022
683a193
Mostly port select,multi_select,sort prompt to crossterm: just borrow…
grunweg Jul 10, 2022
6d41b18
Move TermThemeRenderer and the confirmation prompt to crossterm.
grunweg Aug 17, 2022
dd0d6f4
Make the paging module compile.
grunweg Aug 17, 2022
a7072aa
Port fuzzy-select prompt. And fix two clippy warnings along the way.
grunweg Jul 10, 2022
82ed7d4
cargo fmt
grunweg Aug 18, 2022
47d1cd1
Document clear_*() methods of TermThemeRenderer.
grunweg Aug 17, 2022
cda693a
Allow sharing a terminal between a TermThemeRenderer and a Paging ins…
grunweg Aug 28, 2022
a975463
theme.rs: remove some now-superfluous helper functions.
grunweg Aug 28, 2022
9582bc8
cargo fmt
grunweg Aug 28, 2022
271daf3
Take references to a Term; don't clone it.
grunweg Aug 28, 2022
0bcb0da
Add a new helper to construct a terminal from stderr.
grunweg Aug 28, 2022
a44708e
Fix doctests.
grunweg Aug 28, 2022
a53f478
Fix clippy warnings; format.
grunweg Aug 28, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Expand Up @@ -28,6 +28,7 @@ console = "0.15.0"
tempfile = { version = "3", optional = true }
zeroize = { version = "1.1.1", optional = true }
fuzzy-matcher = { version = "0.3.7", optional = true }
crossterm = "0.24.0"

[[example]]
name = "password"
Expand Down
4 changes: 3 additions & 1 deletion examples/buffered.rs
@@ -1,4 +1,5 @@
use console::Term;
fn main() {} // TODO fix this!
/*use console::Term;
use dialoguer::{theme::ColorfulTheme, Confirm, Input, MultiSelect, Select, Sort};

fn main() {
Expand Down Expand Up @@ -40,3 +41,4 @@ fn main() {
.interact_on(&term)
.unwrap();
}
*/
4 changes: 4 additions & 0 deletions src/lib.rs
Expand Up @@ -47,5 +47,9 @@ mod edit;
mod history;
mod paging;
mod prompts;
pub use term::Term;
mod term;
pub mod theme;
mod validate;

const DEFAULT_TERMINAL_SIZE: (u16, u16) = (80, 24);
14 changes: 8 additions & 6 deletions src/paging.rs
@@ -1,6 +1,8 @@
use std::io;

use console::Term;
use crossterm::terminal;

use crate::{term::Term, theme, DEFAULT_TERMINAL_SIZE};

/// Creates a paging module
///
Expand All @@ -19,8 +21,8 @@ pub struct Paging<'a> {
}

impl<'a> Paging<'a> {
pub fn new(term: &'a Term, items_len: usize, max_capacity: Option<usize>) -> Paging<'a> {
let term_size = term.size();
pub fn new(term: &Term, items_len: usize, max_capacity: Option<usize>) -> Paging {
let term_size = terminal::size().unwrap_or(DEFAULT_TERMINAL_SIZE);
// Subtract -2 because we need space to render the prompt, if paging is active
let capacity = max_capacity
.unwrap_or(std::usize::MAX)
Expand All @@ -46,7 +48,7 @@ impl<'a> Paging<'a> {

/// Updates all internal based on the current terminal size and cursor position
pub fn update(&mut self, cursor_pos: usize) -> io::Result<()> {
let new_term_size = self.term.size();
let new_term_size = terminal::size().unwrap_or(DEFAULT_TERMINAL_SIZE);

if self.current_term_size != new_term_size {
self.current_term_size = new_term_size;
Expand All @@ -64,8 +66,8 @@ impl<'a> Paging<'a> {
} else {
self.active = self.pages > 1;
self.activity_transition = true;
// Clear everything to prevent "ghost" lines in terminal when a resize happened
self.term.clear_last_lines(self.capacity)?;
// Clear everything to prevent "ghost" lines in terminal when a resize happened.
theme::clear_last_lines(self.term, self.capacity as u16)?;
}

if cursor_pos != !0
Expand Down
100 changes: 53 additions & 47 deletions src/prompts/confirm.rs
@@ -1,8 +1,14 @@
use std::io;

use crate::theme::{SimpleTheme, TermThemeRenderer, Theme};
use crate::{
term::Term,
theme::{SimpleTheme, TermThemeRenderer, Theme},
};

use console::{Key, Term};
use crossterm::{
event::{read, Event, KeyCode, KeyEvent},
terminal,
};

/// Renders a confirm prompt.
///
Expand Down Expand Up @@ -102,7 +108,7 @@ impl Confirm<'_> {
/// This unlike [`interact_opt`](Self::interact_opt) does not allow to quit with 'Esc' or 'q'.
#[inline]
pub fn interact(&self) -> io::Result<bool> {
self.interact_on(&Term::stderr())
self.interact_on(&Term::from_stderr())
}

/// Enables user interaction and returns the result.
Expand All @@ -113,21 +119,20 @@ impl Confirm<'_> {
/// or `None` if user cancelled with 'Esc' or 'q'.
#[inline]
pub fn interact_opt(&self) -> io::Result<Option<bool>> {
self.interact_on_opt(&Term::stderr())
self.interact_on_opt(&Term::from_stderr())
}

/// Like [interact](#method.interact) but allows a specific terminal to be set.
///
/// ## Examples
///
/// ```rust,no_run
/// use dialoguer::Confirm;
/// use console::Term;
/// use dialoguer::{Confirm, Term};
///
/// # fn main() -> std::io::Result<()> {
/// let proceed = Confirm::new()
/// .with_prompt("Do you wish to continue?")
/// .interact_on(&Term::stderr())?;
/// .interact_on(&Term::from_stderr())?;
/// # Ok(())
/// # }
/// ```
Expand All @@ -141,12 +146,11 @@ impl Confirm<'_> {
///
/// ## Examples
/// ```rust,no_run
/// use dialoguer::Confirm;
/// use console::Term;
/// use dialoguer::{Confirm, Term};
///
/// fn main() -> std::io::Result<()> {
/// let confirmation = Confirm::new()
/// .interact_on_opt(&Term::stdout())?;
/// .interact_on_opt(&Term::from_stdout())?;
///
/// match confirmation {
/// Some(answer) => println!("User answered {}", if answer { "yes" } else { "no " }),
Expand Down Expand Up @@ -176,65 +180,67 @@ impl Confirm<'_> {
term.flush()?;

let rv;

terminal::enable_raw_mode()?;
if self.wait_for_newline {
// Waits for user input and for the user to hit the Enter key
// before validation.
let mut value = default_if_show;

loop {
let input = term.read_key()?;

match input {
Key::Char('y') | Key::Char('Y') => {
value = Some(true);
}
Key::Char('n') | Key::Char('N') => {
value = Some(false);
}
Key::Enter => {
if !allow_quit {
value = value.or(self.default);
if let Event::Key(KeyEvent { code, modifiers: _ }) = read().unwrap() {
terminal::disable_raw_mode()?;
match code {
KeyCode::Char('y') | KeyCode::Char('Y') => {
value = Some(true);
}
KeyCode::Char('n') | KeyCode::Char('N') => {
value = Some(false);
}
KeyCode::Enter => {
if !allow_quit {
value = value.or(self.default);
}

if value.is_some() || allow_quit {
rv = value;
break;
if value.is_some() || allow_quit {
rv = value;
break;
}
continue;
}
KeyCode::Esc | KeyCode::Char('q') if allow_quit => {
value = None;
}
_ => {
continue;
}
continue;
}
Key::Escape | Key::Char('q') if allow_quit => {
value = None;
}
_ => {
continue;
}
};

term.clear_line()?;
render.clear_current_line()?;
render.confirm_prompt(&self.prompt, value)?;
}
} else {
// Default behavior: matches continuously on every keystroke,
// and does not wait for user to hit the Enter key.
loop {
let input = term.read_key()?;
let value = match input {
Key::Char('y') | Key::Char('Y') => Some(true),
Key::Char('n') | Key::Char('N') => Some(false),
Key::Enter if self.default.is_some() => Some(self.default.unwrap()),
Key::Escape | Key::Char('q') if allow_quit => None,
_ => {
continue;
}
if let Event::Key(KeyEvent { code, modifiers: _ }) = read().unwrap() {
let value = match code {
KeyCode::Char('y') | KeyCode::Char('Y') => Some(true),
KeyCode::Char('n') | KeyCode::Char('N') => Some(false),
KeyCode::Enter if self.default.is_some() => Some(self.default.unwrap()),
KeyCode::Esc | KeyCode::Char('q') if allow_quit => None,
_ => {
continue;
}
};
terminal::disable_raw_mode()?;
rv = value;
break;
};

rv = value;
break;
}
}

term.clear_line()?;
render.clear_current_line()?;
if self.report {
render.confirm_prompt_selection(&self.prompt, rv)?;
}
Expand Down
13 changes: 13 additions & 0 deletions src/prompts/dummy.rs
@@ -0,0 +1,13 @@
use std::io;
use crate::{paging::Paging, term::Term, theme::{SimpleTheme, TermThemeRenderer}};

fn test(term: Term) -> io::Result<()> {
let mut paging = Paging::new(Term::clone(&term), 0, Some(42));
let mut render = TermThemeRenderer::new(Term::clone(&term), &SimpleTheme);

term.hide_cursor()?;

paging.render_prompt(|paging_info| render.select_prompt("My prompt string", paging_info))?;

Ok(())
}