keyfork-prompt: incorporate AlternateScreen and RawMode into a generic guard type
This commit is contained in:
parent
f6b41fce5f
commit
aba62fc4bf
|
@ -1,80 +0,0 @@
|
|||
use std::{
|
||||
io::Write,
|
||||
os::fd::AsRawFd,
|
||||
};
|
||||
|
||||
use keyfork_crossterm::{
|
||||
cursor::MoveTo,
|
||||
terminal::{EnterAlternateScreen, LeaveAlternateScreen},
|
||||
ExecutableCommand,
|
||||
};
|
||||
|
||||
use crate::Result;
|
||||
|
||||
pub(crate) struct AlternateScreen<'a, W>
|
||||
where
|
||||
W: Write + AsRawFd + Sized,
|
||||
{
|
||||
write: &'a mut W,
|
||||
}
|
||||
|
||||
impl<'a, W> AlternateScreen<'a, W>
|
||||
where
|
||||
W: Write + AsRawFd + Sized,
|
||||
{
|
||||
pub(crate) fn new(write_handle: &'a mut W) -> Result<Self> {
|
||||
write_handle.execute(EnterAlternateScreen)?.execute(MoveTo(0, 0))?;
|
||||
Ok(Self {
|
||||
write: write_handle,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<W> Write for AlternateScreen<'_, W>
|
||||
where
|
||||
W: Write + AsRawFd + Sized,
|
||||
{
|
||||
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||
self.write.write(buf)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> std::io::Result<()> {
|
||||
self.write.flush()
|
||||
}
|
||||
}
|
||||
|
||||
impl<W> AsRawFd for AlternateScreen<'_, W>
|
||||
where
|
||||
W: Write + AsRawFd + Sized,
|
||||
{
|
||||
fn as_raw_fd(&self) -> std::os::fd::RawFd {
|
||||
self.write.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
impl<W> ExecutableCommand for AlternateScreen<W>
|
||||
where
|
||||
W: Write + AsRawFd + Sized,
|
||||
{
|
||||
fn execute(&mut self, command: impl crossterm::Command) -> std::io::Result<&mut Self> {
|
||||
let mut write = self.write.lock().unwrap();
|
||||
match write.execute(command) {
|
||||
Ok(_) => {
|
||||
drop(write);
|
||||
Ok(self)
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
impl<W> Drop for AlternateScreen<'_, W>
|
||||
where
|
||||
W: Write + AsRawFd + Sized,
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
self.write.execute(LeaveAlternateScreen).unwrap();
|
||||
}
|
||||
}
|
|
@ -10,16 +10,11 @@ use keyfork_crossterm::{
|
|||
cursor,
|
||||
event::{read, DisableBracketedPaste, EnableBracketedPaste, Event, KeyCode, KeyModifiers},
|
||||
style::{Print, PrintStyledContent, Stylize},
|
||||
terminal::{self, TerminalIoctl, FdTerminal},
|
||||
terminal::{self, TerminalIoctl, FdTerminal, EnterAlternateScreen, LeaveAlternateScreen},
|
||||
tty::IsTty,
|
||||
QueueableCommand,
|
||||
QueueableCommand, ExecutableCommand
|
||||
};
|
||||
|
||||
mod alternate_screen;
|
||||
mod raw_mode;
|
||||
use alternate_screen::AlternateScreen;
|
||||
use raw_mode::RawMode;
|
||||
|
||||
pub mod validators;
|
||||
|
||||
#[cfg(feature = "qrencode")]
|
||||
|
@ -44,6 +39,89 @@ pub enum Message {
|
|||
Data(String),
|
||||
}
|
||||
|
||||
struct TerminalGuard<'a, R, W> where W: Write + AsRawFd {
|
||||
read: &'a mut BufReader<R>,
|
||||
write: &'a mut W,
|
||||
terminal: &'a mut FdTerminal,
|
||||
}
|
||||
|
||||
impl<'a, R, W> TerminalGuard<'a, R, W> where W: Write + AsRawFd, R: Read {
|
||||
fn new(read: &'a mut BufReader<R>, write: &'a mut W, terminal: &'a mut FdTerminal) -> Self {
|
||||
Self {
|
||||
read,
|
||||
write,
|
||||
terminal
|
||||
}
|
||||
}
|
||||
|
||||
fn alternate_screen(mut self) -> std::io::Result<Self> {
|
||||
self.execute(EnterAlternateScreen)?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
fn raw_mode(self) -> std::io::Result<Self> {
|
||||
self.terminal.enable_raw_mode()?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
fn bracketed_paste(mut self) -> std::io::Result<Self> {
|
||||
self.execute(EnableBracketedPaste)?;
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<R, W> TerminalIoctl for TerminalGuard<'_, R, W> where R: Read, W: Write + AsRawFd {
|
||||
fn enable_raw_mode(&mut self) -> std::io::Result<()> {
|
||||
self.terminal.enable_raw_mode()
|
||||
}
|
||||
|
||||
fn disable_raw_mode(&mut self) -> std::io::Result<()> {
|
||||
self.terminal.disable_raw_mode()
|
||||
}
|
||||
|
||||
fn size(&self) -> std::io::Result<(u16, u16)> {
|
||||
self.terminal.size()
|
||||
}
|
||||
|
||||
fn window_size(&self) -> std::io::Result<terminal::WindowSize> {
|
||||
self.terminal.window_size()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R, W> Read for TerminalGuard<'_, R, W> where R: Read, W: Write + AsRawFd {
|
||||
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||
self.read.read(buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl<R, W> BufRead for TerminalGuard<'_, R, W> where R: Read, W: Write + AsRawFd {
|
||||
fn fill_buf(&mut self) -> std::io::Result<&[u8]> {
|
||||
self.read.fill_buf()
|
||||
}
|
||||
|
||||
fn consume(&mut self, amt: usize) {
|
||||
self.read.consume(amt)
|
||||
}
|
||||
}
|
||||
|
||||
impl<R, W> Write for TerminalGuard<'_, R, W> where W: Write + AsRawFd {
|
||||
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||
self.write.write(buf)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> std::io::Result<()> {
|
||||
self.write.flush()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R, W> Drop for TerminalGuard<'_, R, W> where W: Write + AsRawFd {
|
||||
fn drop(&mut self) {
|
||||
self.write.execute(DisableBracketedPaste).unwrap();
|
||||
self.write.execute(LeaveAlternateScreen).unwrap();
|
||||
self.terminal.disable_raw_mode().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Terminal<R, W> {
|
||||
read: BufReader<R>,
|
||||
write: W,
|
||||
|
@ -66,8 +144,12 @@ where
|
|||
})
|
||||
}
|
||||
|
||||
fn lock(&mut self) -> TerminalGuard<'_, R, W> {
|
||||
TerminalGuard::new(&mut self.read, &mut self.write, &mut self.terminal)
|
||||
}
|
||||
|
||||
pub fn prompt_input(&mut self, prompt: &str) -> Result<String> {
|
||||
let mut terminal = AlternateScreen::new(&mut self.write)?;
|
||||
let mut terminal = self.lock().alternate_screen()?;
|
||||
terminal
|
||||
.queue(terminal::Clear(terminal::ClearType::All))?
|
||||
.queue(cursor::MoveTo(0, 0))?;
|
||||
|
@ -83,7 +165,7 @@ where
|
|||
terminal.flush()?;
|
||||
|
||||
let mut line = String::new();
|
||||
self.read.read_line(&mut line)?;
|
||||
terminal.read.read_line(&mut line)?;
|
||||
Ok(line)
|
||||
}
|
||||
|
||||
|
@ -118,17 +200,14 @@ where
|
|||
))
|
||||
}
|
||||
|
||||
// TODO: create a wrapper for bracketed paste similar to RawMode
|
||||
#[cfg(feature = "mnemonic")]
|
||||
#[allow(clippy::too_many_lines)]
|
||||
pub fn prompt_wordlist(&mut self, prompt: &str, wordlist: &Wordlist) -> Result<String> {
|
||||
let mut terminal = AlternateScreen::new(&mut self.write)?;
|
||||
let mut terminal = RawMode::new(&mut terminal)?;
|
||||
let mut terminal = self.lock().alternate_screen()?.raw_mode()?.bracketed_paste()?;
|
||||
|
||||
terminal
|
||||
.queue(terminal::Clear(terminal::ClearType::All))?
|
||||
.queue(cursor::MoveTo(0, 0))?
|
||||
.queue(EnableBracketedPaste)?;
|
||||
.queue(cursor::MoveTo(0, 0))?;
|
||||
let mut lines = prompt.lines().peekable();
|
||||
let mut prefix_length = 0;
|
||||
while let Some(line) = lines.next() {
|
||||
|
@ -142,7 +221,7 @@ where
|
|||
}
|
||||
terminal.flush()?;
|
||||
|
||||
let (mut cols, mut _rows) = self.terminal.size()?;
|
||||
let (mut cols, mut _rows) = terminal.size()?;
|
||||
let mut input = String::new();
|
||||
|
||||
loop {
|
||||
|
@ -236,8 +315,6 @@ where
|
|||
terminal.flush()?;
|
||||
}
|
||||
|
||||
terminal.queue(DisableBracketedPaste)?.flush()?;
|
||||
|
||||
Ok(input)
|
||||
}
|
||||
|
||||
|
@ -273,8 +350,7 @@ where
|
|||
|
||||
// TODO: return secrecy::Secret<String>
|
||||
pub fn prompt_passphrase(&mut self, prompt: &str) -> Result<String> {
|
||||
let mut terminal = AlternateScreen::new(&mut self.write)?;
|
||||
let mut terminal = RawMode::new(&mut terminal)?;
|
||||
let mut terminal = self.lock().alternate_screen()?.raw_mode()?;
|
||||
|
||||
terminal
|
||||
.queue(terminal::Clear(terminal::ClearType::All))?
|
||||
|
@ -292,7 +368,7 @@ where
|
|||
}
|
||||
terminal.flush()?;
|
||||
|
||||
let (mut cols, mut _rows) = self.terminal.size()?;
|
||||
let (mut cols, mut _rows) = terminal.size()?;
|
||||
|
||||
let mut passphrase = String::new();
|
||||
loop {
|
||||
|
@ -332,11 +408,10 @@ where
|
|||
}
|
||||
|
||||
pub fn prompt_message(&mut self, prompt: &Message) -> Result<()> {
|
||||
let mut terminal = AlternateScreen::new(&mut self.write)?;
|
||||
let mut terminal = RawMode::new(&mut terminal)?;
|
||||
let mut terminal = self.lock().alternate_screen()?.raw_mode()?;
|
||||
|
||||
loop {
|
||||
let (cols, rows) = self.terminal.size()?;
|
||||
let (cols, rows) = terminal.size()?;
|
||||
|
||||
terminal
|
||||
.queue(terminal::Clear(terminal::ClearType::All))?
|
||||
|
|
|
@ -1,79 +0,0 @@
|
|||
use std::{
|
||||
io::Write,
|
||||
os::fd::AsRawFd,
|
||||
};
|
||||
|
||||
use keyfork_crossterm::terminal::{FdTerminal, TerminalIoctl};
|
||||
|
||||
use crate::Result;
|
||||
|
||||
pub(crate) struct RawMode<'a, W>
|
||||
where
|
||||
W: Write + AsRawFd + Sized,
|
||||
{
|
||||
write: &'a mut W,
|
||||
terminal: FdTerminal,
|
||||
}
|
||||
|
||||
impl<'a, W> RawMode<'a, W>
|
||||
where
|
||||
W: Write + AsRawFd + Sized,
|
||||
{
|
||||
pub(crate) fn new(write_handle: &'a mut W) -> Result<Self> {
|
||||
let mut terminal = FdTerminal::from(write_handle.as_raw_fd());
|
||||
terminal.enable_raw_mode()?;
|
||||
Ok(Self {
|
||||
terminal,
|
||||
write: write_handle,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<W> Write for RawMode<'_, W>
|
||||
where
|
||||
W: Write + AsRawFd + Sized,
|
||||
{
|
||||
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||
self.write.write(buf)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> std::io::Result<()> {
|
||||
self.write.flush()
|
||||
}
|
||||
}
|
||||
|
||||
impl<W> AsRawFd for RawMode<'_, W>
|
||||
where
|
||||
W: Write + AsRawFd + Sized,
|
||||
{
|
||||
fn as_raw_fd(&self) -> std::os::fd::RawFd {
|
||||
self.write.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
impl<W> ExecutableCommand for RawMode<W>
|
||||
where
|
||||
W: Write + AsRawFd + Sized,
|
||||
{
|
||||
fn execute(&mut self, command: impl crossterm::Command) -> std::io::Result<&mut Self> {
|
||||
let mut write = self.write.lock().unwrap();
|
||||
match write.execute(command) {
|
||||
Ok(_) => {
|
||||
drop(write);
|
||||
Ok(self)
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
impl<W> Drop for RawMode<'_, W>
|
||||
where
|
||||
W: Write + AsRawFd + Sized,
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
self.terminal.disable_raw_mode().unwrap();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue