From 79f02db04ae4f7e4e5068b149a0aa55c7a13334d Mon Sep 17 00:00:00 2001 From: Mikael Mello Date: Tue, 26 Dec 2023 17:31:06 -0800 Subject: [PATCH] Use tty instead of stdin on termion (#199) * Use tty instead of stdin on termion * Rename Tty enum variant to TTY * Update CHANGELOG * Allow upper-case acronym --- CHANGELOG.md | 11 ++++++----- inquire/src/error.rs | 5 ++++- inquire/src/terminal/crossterm.rs | 9 +++------ inquire/src/terminal/termion.rs | 32 +++++++++++++------------------ 4 files changed, 26 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f860f3d..0a1a7144 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,19 +14,20 @@ - Expand workflow clippy task to lint all-features in workspace. - Add docs badge to readme. - **Breaking** The Select and Multiselect Filter now scores input and is now expected to return an `Option`, making it possible to order/rank the list of options. [#176](https://github.com/mikaelmello/inquire/pull/176) - `None`: Will not be displayed in the list of options. - `Some(score)`: score determines the order of options, higher score, higher on the list of options. + `None`: Will not be displayed in the list of options. + `Some(score)`: score determines the order of options, higher score, higher on the list of options. - Implement fuzzy search as default on Select and MultiSelect prompts. [#176](https://github.com/mikaelmello/inquire/pull/176) - Add new option on Select/MultiSelect prompts allowing to reset selection to the first item on filter-input changes. [#176](https://github.com/mikaelmello/inquire/pull/176) - Emacs-like keybindings added where applicable: - - Ctrl-p/Ctrl-n for up/down - - Ctrl-b/Ctrl-f for left/right - - Ctrl-j/Ctrl-g for enter/cancel +- Ctrl-p/Ctrl-n for up/down +- Ctrl-b/Ctrl-f for left/right +- Ctrl-j/Ctrl-g for enter/cancel - Added 'with_starting_filter_input' to both Select and MultiSelect, which allows for setting an initial value to the filter section of the prompt. ### Fixes - Fixed typos in the code's comments. +- Fixed issue where inquire, using termion, would crash when receiving piped inputs. ### Dependency changes (some breaking) diff --git a/inquire/src/error.rs b/inquire/src/error.rs index 2da9b0a9..62206d99 100644 --- a/inquire/src/error.rs +++ b/inquire/src/error.rs @@ -65,7 +65,10 @@ impl From for InquireError { impl From for InquireError { fn from(err: io::Error) -> Self { - InquireError::IO(err) + match err.raw_os_error() { + Some(25 | 6) => InquireError::NotTTY, + _ => InquireError::IO(err), + } } } diff --git a/inquire/src/terminal/crossterm.rs b/inquire/src/terminal/crossterm.rs index d7676ac2..d0adcdf9 100644 --- a/inquire/src/terminal/crossterm.rs +++ b/inquire/src/terminal/crossterm.rs @@ -5,12 +5,12 @@ use crossterm::{ event::{self, KeyCode, KeyEvent, KeyModifiers}, queue, style::{Attribute, Color, Print, SetAttribute, SetBackgroundColor, SetForegroundColor}, - terminal::{self, enable_raw_mode, ClearType}, + terminal::{self, ClearType}, Command, }; use crate::{ - error::{InquireError, InquireResult}, + error::InquireResult, ui::{Attributes, Key, Styled}, }; @@ -34,10 +34,7 @@ pub struct CrosstermTerminal<'a> { impl<'a> CrosstermTerminal<'a> { pub fn new() -> InquireResult { - enable_raw_mode().map_err(|e| match e.raw_os_error() { - Some(25 | 6) => InquireError::NotTTY, - _ => InquireError::from(e), - })?; + crossterm::terminal::enable_raw_mode()?; Ok(Self { io: IO::Std { w: stderr() }, diff --git a/inquire/src/terminal/termion.rs b/inquire/src/terminal/termion.rs index f6a59564..b8434501 100644 --- a/inquire/src/terminal/termion.rs +++ b/inquire/src/terminal/termion.rs @@ -1,5 +1,8 @@ use core::fmt; -use std::io::{stderr, stdin, Result, Stderr, Stdin, Write}; +use std::{ + fs::File, + io::{Result, Write}, +}; use termion::{ color::{self, Color}, @@ -11,18 +14,15 @@ use termion::{ }; use crate::{ - error::{InquireError, InquireResult}, + error::InquireResult, ui::{Attributes, Styled}, }; use super::{Terminal, INITIAL_IN_MEMORY_CAPACITY}; +#[allow(clippy::upper_case_acronyms)] enum IO<'a> { - #[allow(unused)] - Std { - r: Keys, - w: RawTerminal, - }, + TTY(RawTerminal, Keys), #[allow(unused)] Custom { r: &'a mut dyn Iterator, @@ -38,18 +38,12 @@ pub struct TermionTerminal<'a> { impl<'a> TermionTerminal<'a> { #[allow(unused)] pub fn new() -> InquireResult { - let raw_mode = stderr() - .into_raw_mode() - .map_err(|e| match e.raw_os_error() { - Some(25 | 6) => InquireError::NotTTY, - _ => e.into(), - }); + let tty = termion::get_tty()?; + let raw_terminal = tty.into_raw_mode()?; + let keys = raw_terminal.try_clone()?.keys(); Ok(Self { - io: IO::Std { - r: stdin().keys(), - w: raw_mode?, - }, + io: IO::TTY(raw_terminal, keys), in_memory_content: String::with_capacity(INITIAL_IN_MEMORY_CAPACITY), }) } @@ -73,7 +67,7 @@ impl<'a> TermionTerminal<'a> { fn get_writer(&mut self) -> &mut dyn Write { match &mut self.io { - IO::Std { r: _, w } => w, + IO::TTY(w, _) => w, IO::Custom { r: _, w } => w, } } @@ -126,7 +120,7 @@ impl<'a> Terminal for TermionTerminal<'a> { fn read_key(&mut self) -> Result { loop { match &mut self.io { - IO::Std { r, w: _ } => { + IO::TTY(_, r) => { if let Some(key) = r.next() { return key.map(|k| k.into()); }