#![allow(missing_docs)]
use super::error::{PromptError, Result};
pub fn is_interactive() -> bool {
use std::io::IsTerminal;
std::io::stderr().is_terminal() && std::io::stdin().is_terminal()
}
#[derive(Debug, Clone, PartialEq)]
pub enum Key {
Up,
Down,
Left,
Right,
Home,
End,
PageUp,
PageDown,
Enter,
Tab,
Char(char),
Backspace,
Delete,
Escape,
Interrupt,
DeleteWordBack,
}
pub mod interactive {
use super::{Key, PromptError, Result};
use crossterm::event::{self, Event, KeyCode, KeyModifiers};
pub fn read_key() -> Result<Key> {
loop {
match event::read().map_err(PromptError::Io)? {
Event::Key(ke) => {
if ke.modifiers.contains(KeyModifiers::CONTROL) {
match ke.code {
KeyCode::Char('c') | KeyCode::Char('d') => {
return Ok(Key::Interrupt);
}
KeyCode::Char('w') => return Ok(Key::DeleteWordBack),
KeyCode::Char('a') => return Ok(Key::Home),
KeyCode::Char('e') => return Ok(Key::End),
_ => continue,
}
}
return Ok(match ke.code {
KeyCode::Up => Key::Up,
KeyCode::Down => Key::Down,
KeyCode::Left => Key::Left,
KeyCode::Right => Key::Right,
KeyCode::Home => Key::Home,
KeyCode::End => Key::End,
KeyCode::PageUp => Key::PageUp,
KeyCode::PageDown => Key::PageDown,
KeyCode::Enter => Key::Enter,
KeyCode::Tab => Key::Tab,
KeyCode::Char(c) => Key::Char(c),
KeyCode::Backspace => Key::Backspace,
KeyCode::Delete => Key::Delete,
KeyCode::Esc => Key::Escape,
_ => continue,
});
}
_ => continue,
}
}
}
pub fn enter_raw() -> Result<()> {
crossterm::terminal::enable_raw_mode().map_err(PromptError::Io)
}
pub fn leave_raw() -> Result<()> {
crossterm::terminal::disable_raw_mode().map_err(PromptError::Io)
}
}
pub mod fallback {
use super::{PromptError, Result};
use std::io::BufRead;
pub fn read_line_raw() -> Result<String> {
let mut line = String::new();
std::io::stdin()
.lock()
.read_line(&mut line)
.map_err(PromptError::Io)?;
if line.is_empty() {
return Err(PromptError::Interrupted);
}
Ok(line.trim().to_string())
}
}