From 23b1a5bdb01edee63bda843492e9065b16a6ef18 Mon Sep 17 00:00:00 2001 From: Leni Aniva Date: Wed, 16 Aug 2023 22:54:22 -0700 Subject: [PATCH 1/5] Add unicode capability (demonstration) Signed-off-by: Leni Aniva --- src/reader.rs | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/reader.rs b/src/reader.rs index e6a8a103..7a492535 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -162,9 +162,23 @@ impl NBReader { if self.eof { return Ok(()); } + // FIXME: Temporary flag to demonstrate utf-8 capabilities + let unicode = true; + let mut char_buf: Vec = Vec::new(); + while let Ok(from_channel) = self.reader.try_recv() { match from_channel { - Ok(PipedChar::Char(c)) => self.buffer.push(c as char), + Ok(PipedChar::Char(c)) => { + if unicode { + char_buf.push(c); + if let Ok(s) = std::str::from_utf8(&char_buf) { + self.buffer.push(s.chars().next().unwrap()); + char_buf.clear(); + } + } else { + self.buffer.push(c as char) + } + }, Ok(PipedChar::EOF) => self.eof = true, // this is just from experience, e.g. "sleep 5" returns the other error which // most probably means that there is no stdout stream at all -> send EOF @@ -300,6 +314,22 @@ mod tests { Err(_) => panic!(), } } + #[test] + fn test_expect_unicode() { + let f = io::Cursor::new("∀ melon\r\n"); + let mut r = NBReader::new(f, None); + assert_eq!( + ("∀ melon".to_string(), "\r\n".to_string()), + r.read_until(&ReadUntil::String("\r\n".to_string())) + .expect("cannot read line") + ); + // check for EOF + match r.read_until(&ReadUntil::NBytes(10)) { + Ok(_) => panic!(), + Err(Error::EOF { .. }) => {} + Err(_) => panic!(), + } + } #[test] fn test_regex() { From 34bbaeb2e47233c29930db4a91b69e23954d59a7 Mon Sep 17 00:00:00 2001 From: Leni Aniva Date: Wed, 16 Aug 2023 22:58:04 -0700 Subject: [PATCH 2/5] Add cat demonstration program Signed-off-by: Leni Aniva --- examples/cat.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 examples/cat.rs diff --git a/examples/cat.rs b/examples/cat.rs new file mode 100644 index 00000000..0accb03e --- /dev/null +++ b/examples/cat.rs @@ -0,0 +1,14 @@ +use rexpect::error::Error; +use rexpect::spawn; + +fn main() -> Result<(), Error> { + let mut p = spawn("cat", Some(1000))?; + + let ex: String = "∀".to_string(); + p.send_line(&ex)?; + let line = p.read_line()?; + + println!("In: {}", &ex); + println!("Out: {}", &line); + Ok(()) +} From 4293d9bd6d07a3bd91162c169c7f0623fe5853e4 Mon Sep 17 00:00:00 2001 From: Leni Aniva Date: Thu, 17 Aug 2023 07:40:31 -0700 Subject: [PATCH 3/5] Add encoding field and enum Signed-off-by: Leni Aniva --- src/encoding.rs | 6 ++++++ src/lib.rs | 2 ++ src/reader.rs | 22 +++++++++++++--------- 3 files changed, 21 insertions(+), 9 deletions(-) create mode 100644 src/encoding.rs diff --git a/src/encoding.rs b/src/encoding.rs new file mode 100644 index 00000000..d35bb951 --- /dev/null +++ b/src/encoding.rs @@ -0,0 +1,6 @@ +#[derive(Debug)] +#[allow(non_snake_case)] +pub enum Encoding { + ASCII, + UTF8, +} diff --git a/src/lib.rs b/src/lib.rs index 4b58e14f..faac06cc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -64,11 +64,13 @@ //! } //! ``` +pub mod encoding; pub mod error; pub mod process; pub mod reader; pub mod session; +pub use encoding::Encoding; pub use reader::ReadUntil; pub use session::{spawn, spawn_bash, spawn_python, spawn_stream}; diff --git a/src/reader.rs b/src/reader.rs index 7a492535..5770481d 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -1,6 +1,7 @@ //! Unblocking reader which supports waiting for strings/regexes and EOF to be present use crate::error::Error; +use crate::encoding::Encoding; pub use regex::Regex; use std::io::prelude::*; use std::io::{self, BufReader}; @@ -108,6 +109,7 @@ pub struct NBReader { buffer: String, eof: bool, timeout: Option, + encoding: Encoding, } impl NBReader { @@ -154,6 +156,7 @@ impl NBReader { buffer: String::with_capacity(1024), eof: false, timeout: timeout.map(time::Duration::from_millis), + encoding: Encoding::UTF8, } } @@ -162,21 +165,22 @@ impl NBReader { if self.eof { return Ok(()); } - // FIXME: Temporary flag to demonstrate utf-8 capabilities - let unicode = true; + // NOTE: When UTF-8 mode is on, there is no handling to salvage a + // stream of chars if a broken unicode char is not completed. let mut char_buf: Vec = Vec::new(); while let Ok(from_channel) = self.reader.try_recv() { match from_channel { Ok(PipedChar::Char(c)) => { - if unicode { - char_buf.push(c); - if let Ok(s) = std::str::from_utf8(&char_buf) { - self.buffer.push(s.chars().next().unwrap()); - char_buf.clear(); + match &self.encoding { + Encoding::ASCII => self.buffer.push(c as char), + Encoding::UTF8 => { + char_buf.push(c); + if let Ok(s) = std::str::from_utf8(&char_buf) { + self.buffer.push(s.chars().next().unwrap()); + char_buf.clear(); + } } - } else { - self.buffer.push(c as char) } }, Ok(PipedChar::EOF) => self.eof = true, From 36f07d466b24a20df45e6042a7cd857d20648739 Mon Sep 17 00:00:00 2001 From: Leni Aniva Date: Fri, 18 Aug 2023 21:00:57 -0700 Subject: [PATCH 4/5] derive Eq for Encoding Signed-off-by: Leni Aniva --- src/encoding.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/encoding.rs b/src/encoding.rs index d35bb951..d74c417b 100644 --- a/src/encoding.rs +++ b/src/encoding.rs @@ -1,4 +1,4 @@ -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq)] #[allow(non_snake_case)] pub enum Encoding { ASCII, From efb3ba68017de0df531712dad699f9d02cfe0954 Mon Sep 17 00:00:00 2001 From: Leni Aniva Date: Sun, 3 Mar 2024 10:41:22 -0800 Subject: [PATCH 5/5] Make UTF8 the default encoding --- src/encoding.rs | 2 +- src/session.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/encoding.rs b/src/encoding.rs index 8ffdd119..a7e04b33 100644 --- a/src/encoding.rs +++ b/src/encoding.rs @@ -1,7 +1,7 @@ #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)] #[allow(non_snake_case)] pub enum Encoding { - #[default] ASCII, + #[default] UTF8, } diff --git a/src/session.rs b/src/session.rs index ae76583a..09eadca5 100644 --- a/src/session.rs +++ b/src/session.rs @@ -232,7 +232,7 @@ pub fn spawn(program: &str, timeout_ms: Option) -> Result, encoding: Encoding) -> Result { +pub fn spawn_command(command: Command, timeout_ms: Option) -> Result { spawn_with_options( command, Options {