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,
|
cursor,
|
||||||
event::{read, DisableBracketedPaste, EnableBracketedPaste, Event, KeyCode, KeyModifiers},
|
event::{read, DisableBracketedPaste, EnableBracketedPaste, Event, KeyCode, KeyModifiers},
|
||||||
style::{Print, PrintStyledContent, Stylize},
|
style::{Print, PrintStyledContent, Stylize},
|
||||||
terminal::{self, TerminalIoctl, FdTerminal},
|
terminal::{self, TerminalIoctl, FdTerminal, EnterAlternateScreen, LeaveAlternateScreen},
|
||||||
tty::IsTty,
|
tty::IsTty,
|
||||||
QueueableCommand,
|
QueueableCommand, ExecutableCommand
|
||||||
};
|
};
|
||||||
|
|
||||||
mod alternate_screen;
|
|
||||||
mod raw_mode;
|
|
||||||
use alternate_screen::AlternateScreen;
|
|
||||||
use raw_mode::RawMode;
|
|
||||||
|
|
||||||
pub mod validators;
|
pub mod validators;
|
||||||
|
|
||||||
#[cfg(feature = "qrencode")]
|
#[cfg(feature = "qrencode")]
|
||||||
|
@ -44,6 +39,89 @@ pub enum Message {
|
||||||
Data(String),
|
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> {
|
pub struct Terminal<R, W> {
|
||||||
read: BufReader<R>,
|
read: BufReader<R>,
|
||||||
write: W,
|
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> {
|
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
|
terminal
|
||||||
.queue(terminal::Clear(terminal::ClearType::All))?
|
.queue(terminal::Clear(terminal::ClearType::All))?
|
||||||
.queue(cursor::MoveTo(0, 0))?;
|
.queue(cursor::MoveTo(0, 0))?;
|
||||||
|
@ -83,7 +165,7 @@ where
|
||||||
terminal.flush()?;
|
terminal.flush()?;
|
||||||
|
|
||||||
let mut line = String::new();
|
let mut line = String::new();
|
||||||
self.read.read_line(&mut line)?;
|
terminal.read.read_line(&mut line)?;
|
||||||
Ok(line)
|
Ok(line)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,17 +200,14 @@ where
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: create a wrapper for bracketed paste similar to RawMode
|
|
||||||
#[cfg(feature = "mnemonic")]
|
#[cfg(feature = "mnemonic")]
|
||||||
#[allow(clippy::too_many_lines)]
|
#[allow(clippy::too_many_lines)]
|
||||||
pub fn prompt_wordlist(&mut self, prompt: &str, wordlist: &Wordlist) -> Result<String> {
|
pub fn prompt_wordlist(&mut self, prompt: &str, wordlist: &Wordlist) -> Result<String> {
|
||||||
let mut terminal = AlternateScreen::new(&mut self.write)?;
|
let mut terminal = self.lock().alternate_screen()?.raw_mode()?.bracketed_paste()?;
|
||||||
let mut terminal = RawMode::new(&mut terminal)?;
|
|
||||||
|
|
||||||
terminal
|
terminal
|
||||||
.queue(terminal::Clear(terminal::ClearType::All))?
|
.queue(terminal::Clear(terminal::ClearType::All))?
|
||||||
.queue(cursor::MoveTo(0, 0))?
|
.queue(cursor::MoveTo(0, 0))?;
|
||||||
.queue(EnableBracketedPaste)?;
|
|
||||||
let mut lines = prompt.lines().peekable();
|
let mut lines = prompt.lines().peekable();
|
||||||
let mut prefix_length = 0;
|
let mut prefix_length = 0;
|
||||||
while let Some(line) = lines.next() {
|
while let Some(line) = lines.next() {
|
||||||
|
@ -142,7 +221,7 @@ where
|
||||||
}
|
}
|
||||||
terminal.flush()?;
|
terminal.flush()?;
|
||||||
|
|
||||||
let (mut cols, mut _rows) = self.terminal.size()?;
|
let (mut cols, mut _rows) = terminal.size()?;
|
||||||
let mut input = String::new();
|
let mut input = String::new();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
@ -236,8 +315,6 @@ where
|
||||||
terminal.flush()?;
|
terminal.flush()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
terminal.queue(DisableBracketedPaste)?.flush()?;
|
|
||||||
|
|
||||||
Ok(input)
|
Ok(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,8 +350,7 @@ where
|
||||||
|
|
||||||
// TODO: return secrecy::Secret<String>
|
// TODO: return secrecy::Secret<String>
|
||||||
pub fn prompt_passphrase(&mut self, prompt: &str) -> Result<String> {
|
pub fn prompt_passphrase(&mut self, prompt: &str) -> Result<String> {
|
||||||
let mut terminal = AlternateScreen::new(&mut self.write)?;
|
let mut terminal = self.lock().alternate_screen()?.raw_mode()?;
|
||||||
let mut terminal = RawMode::new(&mut terminal)?;
|
|
||||||
|
|
||||||
terminal
|
terminal
|
||||||
.queue(terminal::Clear(terminal::ClearType::All))?
|
.queue(terminal::Clear(terminal::ClearType::All))?
|
||||||
|
@ -292,7 +368,7 @@ where
|
||||||
}
|
}
|
||||||
terminal.flush()?;
|
terminal.flush()?;
|
||||||
|
|
||||||
let (mut cols, mut _rows) = self.terminal.size()?;
|
let (mut cols, mut _rows) = terminal.size()?;
|
||||||
|
|
||||||
let mut passphrase = String::new();
|
let mut passphrase = String::new();
|
||||||
loop {
|
loop {
|
||||||
|
@ -332,11 +408,10 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prompt_message(&mut self, prompt: &Message) -> Result<()> {
|
pub fn prompt_message(&mut self, prompt: &Message) -> Result<()> {
|
||||||
let mut terminal = AlternateScreen::new(&mut self.write)?;
|
let mut terminal = self.lock().alternate_screen()?.raw_mode()?;
|
||||||
let mut terminal = RawMode::new(&mut terminal)?;
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let (cols, rows) = self.terminal.size()?;
|
let (cols, rows) = terminal.size()?;
|
||||||
|
|
||||||
terminal
|
terminal
|
||||||
.queue(terminal::Clear(terminal::ClearType::All))?
|
.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