keyfork-prompt: use raw mode for input
This commit is contained in:
parent
c232828290
commit
35e0eb57a0
|
@ -1,26 +1,15 @@
|
||||||
#![allow(missing_docs)]
|
#![allow(missing_docs)]
|
||||||
|
|
||||||
use keyfork_prompt::{
|
use keyfork_prompt::{
|
||||||
prompt_validated_wordlist,
|
Message,
|
||||||
validators::{mnemonic, Validator},
|
|
||||||
default_handler,
|
default_handler,
|
||||||
};
|
};
|
||||||
|
|
||||||
use keyfork_mnemonic::English;
|
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut handler = default_handler().unwrap();
|
let mut handler = default_handler()?;
|
||||||
let transport_validator = mnemonic::MnemonicSetValidator {
|
|
||||||
word_lengths: [24],
|
|
||||||
};
|
|
||||||
|
|
||||||
let mnemonics = prompt_validated_wordlist::<English, _>(
|
let output = handler.prompt_input("Test message: ")?;
|
||||||
&mut *handler,
|
handler.prompt_message(Message::Text(format!("Result: {output}")))?;
|
||||||
"Enter a 24-word mnemonic: ",
|
|
||||||
3,
|
|
||||||
&*transport_validator.to_fn(),
|
|
||||||
)?;
|
|
||||||
assert_eq!(mnemonics[0].as_bytes().len(), 32);
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -217,9 +217,9 @@ pub fn default_handler() -> Result<Box<dyn PromptHandler>, DefaultHandlerError>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// stdout can be not-a-terminal and we'll just override it anyways, stdin is the
|
// we can revert stdin to a readable input by using raw mode, but we can't do the more
|
||||||
// important one.
|
// significant operations if we don't have access to a terminal stderr
|
||||||
if std::io::stdin().is_terminal() {
|
if std::io::stderr().is_terminal() {
|
||||||
// because this is a "guessed" handler, let's take the nice route and not error, just skip.
|
// because this is a "guessed" handler, let's take the nice route and not error, just skip.
|
||||||
if let Ok(terminal) = default_terminal() {
|
if let Ok(terminal) = default_terminal() {
|
||||||
return Ok(Box::new(terminal));
|
return Ok(Box::new(terminal));
|
||||||
|
|
|
@ -178,12 +178,14 @@ where
|
||||||
W: Write + AsRawFd + Sized,
|
W: Write + AsRawFd + Sized,
|
||||||
{
|
{
|
||||||
fn prompt_input(&mut self, prompt: &str) -> Result<String> {
|
fn prompt_input(&mut self, prompt: &str) -> Result<String> {
|
||||||
let mut terminal = self.lock().alternate_screen()?;
|
let mut terminal = self.lock().alternate_screen()?.raw_mode()?;
|
||||||
terminal
|
terminal
|
||||||
.queue(terminal::Clear(terminal::ClearType::All))?
|
.queue(terminal::Clear(terminal::ClearType::All))?
|
||||||
.queue(cursor::MoveTo(0, 0))?;
|
.queue(cursor::MoveTo(0, 0))?;
|
||||||
let mut lines = prompt.lines().peekable();
|
let mut lines = prompt.lines().peekable();
|
||||||
|
let mut prefix_length = 0;
|
||||||
while let Some(line) = lines.next() {
|
while let Some(line) = lines.next() {
|
||||||
|
prefix_length = line.len();
|
||||||
terminal.queue(Print(line))?;
|
terminal.queue(Print(line))?;
|
||||||
if lines.peek().is_some() {
|
if lines.peek().is_some() {
|
||||||
terminal
|
terminal
|
||||||
|
@ -193,9 +195,66 @@ where
|
||||||
}
|
}
|
||||||
terminal.flush()?;
|
terminal.flush()?;
|
||||||
|
|
||||||
let mut line = String::new();
|
let (mut cols, mut _rows) = terminal.size()?;
|
||||||
terminal.read.read_line(&mut line)?;
|
|
||||||
Ok(line)
|
let mut input = String::new();
|
||||||
|
loop {
|
||||||
|
let input_len = input.len();
|
||||||
|
match read()? {
|
||||||
|
Event::Resize(new_cols, new_rows) => {
|
||||||
|
cols = new_cols;
|
||||||
|
_rows = new_rows;
|
||||||
|
}
|
||||||
|
Event::Key(k) => match k.code {
|
||||||
|
KeyCode::Enter => {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
KeyCode::Backspace => {
|
||||||
|
if input.pop().is_some() && prefix_length + input_len < cols as usize {
|
||||||
|
terminal
|
||||||
|
.queue(cursor::MoveLeft(1))?
|
||||||
|
.queue(Print(" "))?
|
||||||
|
.queue(cursor::MoveLeft(1))?
|
||||||
|
.flush()?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
KeyCode::Char('w') if k.modifiers.contains(KeyModifiers::CONTROL) => {
|
||||||
|
let mut has_deleted_text = true;
|
||||||
|
while input.pop().is_some_and(char::is_whitespace) {
|
||||||
|
has_deleted_text = false;
|
||||||
|
}
|
||||||
|
while input.pop().is_some_and(|c| !c.is_whitespace()) {
|
||||||
|
has_deleted_text = true;
|
||||||
|
}
|
||||||
|
if !input.is_empty() && has_deleted_text {
|
||||||
|
input.push(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
KeyCode::Char('c') if k.modifiers.contains(KeyModifiers::CONTROL) => {
|
||||||
|
return Err(Error::CtrlC);
|
||||||
|
}
|
||||||
|
KeyCode::Char(c) => {
|
||||||
|
input.push(c);
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
},
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
let printable_start = if prefix_length + input.len() < cols as usize {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
let printable_space = (cols as usize) - prefix_length;
|
||||||
|
input.len() - (printable_space - 1)
|
||||||
|
};
|
||||||
|
terminal
|
||||||
|
.queue(cursor::MoveToColumn(prefix_length as u16))?
|
||||||
|
.queue(terminal::Clear(terminal::ClearType::UntilNewLine))?
|
||||||
|
.queue(Print(&input[printable_start..]))?
|
||||||
|
.flush()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prompt_validated_wordlist(
|
fn prompt_validated_wordlist(
|
||||||
|
|
Loading…
Reference in New Issue