]> Repositorios git - scryer-prolog.git/commitdiff
Fixes issue 3264 by adding a fallback read mode when reading from non-tty stdin on...
authorAlexander McLin <[email protected]>
Mon, 30 Mar 2026 01:29:48 +0000 (21:29 -0400)
committerAlexander McLin <[email protected]>
Mon, 25 May 2026 22:13:01 +0000 (18:13 -0400)
src/machine/system_calls.rs
src/read.rs
src/read/fallback_mode.rs [new file with mode: 0644]
src/read/user_interaction.rs [new file with mode: 0644]

index 2ac93cb73c5baeea49faaac48124e132a14d6d91..df15aeb56742db5d3299f2d1f2190baf0b89016f 100644 (file)
@@ -68,9 +68,7 @@ use cpu_time::ProcessTime;
 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};
 
@@ -147,28 +145,6 @@ impl ModuleQuantification {
     }
 }
 
-#[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);
 
index a07f4d0990e53556b19dfb10ca039af91cbe8904..f0346ad219ad01f6a4d3000272c5adaaaef14fa8 100644 (file)
@@ -1,3 +1,8 @@
+#[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::*;
diff --git a/src/read/fallback_mode.rs b/src/read/fallback_mode.rs
new file mode 100644 (file)
index 0000000..b7a5ba9
--- /dev/null
@@ -0,0 +1,37 @@
+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
diff --git a/src/read/user_interaction.rs b/src/read/user_interaction.rs
new file mode 100644 (file)
index 0000000..fb82259
--- /dev/null
@@ -0,0 +1,49 @@
+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