use std::time::{Duration, SystemTime};
#[cfg(feature = "repl")]
-use crossterm::event::{read, Event, KeyCode, KeyEvent, KeyEventKind, KeyModifiers};
-#[cfg(feature = "repl")]
-use crossterm::terminal::{disable_raw_mode, enable_raw_mode};
+use crate::read::user_interaction::{get_key, KeyCode, KeyModifiers};
use blake2::{Blake2b512, Blake2s256};
}
}
-#[cfg(feature = "repl")]
-pub(crate) fn get_key() -> KeyEvent {
- let key;
- enable_raw_mode().expect("failed to enable raw mode");
- loop {
- let key_ = read();
- if let Ok(Event::Key(key_)) = key_ {
- if key_.kind != KeyEventKind::Release {
- match key_.code {
- KeyCode::Char(_) | KeyCode::Enter | KeyCode::Tab => {
- key = key_;
- break;
- }
- _ => (),
- }
- }
- }
- }
- disable_raw_mode().expect("failed to disable raw mode");
- key
-}
-
fn pstr_segment_char_count_and_tail(heap: &Heap, pstr_loc: usize) -> (usize, usize) {
let char_iter = heap.char_iter(pstr_loc);
+#[cfg(feature = "repl")]
+pub mod fallback_mode;
+#[cfg(feature = "repl")]
+pub mod user_interaction;
+
use crate::parser::ast::*;
use crate::parser::lexer::Lexer;
use crate::parser::parser::*;
--- /dev/null
+use crossterm::event::{KeyCode, KeyEvent, KeyEventKind, KeyEventState, KeyModifiers};
+use std::io::{Read, Error, ErrorKind};
+
+// Provide graceful degradation limited support mode if reading from stdin that does not
+// support terminal features.
+//
+// Retrieve a single byte from stdin, does not support full Unicode decoding; only convert
+// byte to KeyEvent char if it falls within the ASCII subset of UTF-8.
+//
+// Does not support passing through Ctrl-C as a KeyEvent.
+pub(crate) fn limited_support_read() -> std::io::Result<KeyEvent> {
+ let byte_or_none = std::io::stdin().bytes().next();
+
+ match byte_or_none {
+ Some(byte) => match byte {
+ Ok(b) => {
+ if b.is_ascii() {
+ Ok(map_ascii_to_keyevent(b as char))
+ }
+ else {
+ Err(Error::new(ErrorKind::Unsupported, "not supported input"))
+ }
+ }
+ Err(e) => Err(e),
+ },
+ None => Err(Error::new(ErrorKind::UnexpectedEof, "EOF")),
+ }
+}
+
+fn map_ascii_to_keyevent(c: char) -> KeyEvent {
+ KeyEvent {
+ code: KeyCode::Char(c),
+ modifiers: KeyModifiers::NONE,
+ kind: KeyEventKind::Press,
+ state: KeyEventState::empty(),
+ }
+}
\ No newline at end of file
--- /dev/null
+use crossterm::event::{read, Event, KeyEventKind};
+pub(crate) use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
+use crossterm::terminal::{disable_raw_mode, enable_raw_mode};
+use crossterm::tty::IsTty;
+
+use crate::read::fallback_mode;
+
+pub(crate) fn get_key() -> KeyEvent {
+ let key;
+ if supported_terminal() {
+ enable_raw_mode().expect("failed to enable raw mode");
+ loop {
+ let key_ = read();
+ if let Ok(Event::Key(key_)) = key_ {
+ if key_.kind != KeyEventKind::Release {
+ match key_.code {
+ KeyCode::Char(_) | KeyCode::Enter | KeyCode::Tab => {
+ key = key_;
+ break;
+ }
+ _ => (),
+ }
+ }
+ }
+ }
+ disable_raw_mode().expect("failed to disable raw mode");
+ } else {
+ // stdin is not supported terminal type, fallback to limited support mode.
+ loop {
+ let key_ = fallback_mode::limited_support_read();
+ if let Ok(key_) = key_ {
+ key = key_;
+ break;
+ }
+ }
+ }
+ key
+}
+
+fn supported_terminal() -> bool {
+ #[cfg(windows)]
+ let windows_os = true;
+
+ #[cfg(not(windows))]
+ let windows_os = false;
+
+ // If OS is Windows and stdin is not a tty, it's either a pipe or an unsupported terminal configuration.
+ !windows_os || std::io::stdin().is_tty()
+}
\ No newline at end of file