From af0d4e6f52beb0699e9d428bb19fc3d13bcdbbd2 Mon Sep 17 00:00:00 2001 From: YizhePKU Date: Sun, 20 Oct 2024 11:22:29 +0000 Subject: [PATCH 1/9] Support automated UX testing --- Cargo.lock | 169 +++++++++++++++++++++++++++++++++- Cargo.toml | 1 + examples/typing_latency.rs | 71 +++++++++++++++ tests/basic.rs | 181 +++++++++++++++++++++++++++++++++++++ 4 files changed, 419 insertions(+), 3 deletions(-) create mode 100644 examples/typing_latency.rs create mode 100644 tests/basic.rs diff --git a/Cargo.lock b/Cargo.lock index a35b5db5..53d0a832 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,6 +23,40 @@ dependencies = [ "memchr", ] +[[package]] +name = "alacritty-test" +version = "0.1.0" +source = "git+https://github.com/YizhePKU/alacritty-test.git?rev=2f63ebe#2f63ebe293c7026e24342a3b934bc747065c5240" +dependencies = [ + "alacritty_terminal", + "polling", + "unicode-width-16", +] + +[[package]] +name = "alacritty_terminal" +version = "0.24.1-rc2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef001fb819ec89184604b7f073e1cb5e5df57666e7fcfc7f8e229116f866a89e" +dependencies = [ + "base64", + "bitflags 2.5.0", + "home", + "libc", + "log", + "miow", + "parking_lot", + "piper", + "polling", + "regex-automata", + "rustix-openpty", + "serde", + "signal-hook", + "unicode-width-16", + "vte 0.13.0", + "windows-sys 0.52.0", +] + [[package]] name = "allocator-api2" version = "0.2.16" @@ -61,12 +95,24 @@ dependencies = [ "x11rb", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "bitflags" version = "1.3.2" @@ -134,6 +180,15 @@ dependencies = [ "error-code", ] +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "core-foundation-sys" version = "0.8.6" @@ -222,6 +277,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "cursor-icon" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991" + [[package]] name = "derive-new" version = "0.6.0" @@ -323,6 +384,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + [[package]] name = "gethostname" version = "0.4.3" @@ -370,6 +437,12 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + [[package]] name = "home" version = "0.5.9" @@ -512,13 +585,22 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.9", "libc", "log", "wasi", "windows-sys 0.52.0", ] +[[package]] +name = "miow" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "359f76430b20a79f9e20e115b3428614e654f04fab314482fc0fda0ebd3c6044" +dependencies = [ + "windows-sys 0.48.0", +] + [[package]] name = "nix" version = "0.28.0" @@ -637,12 +719,44 @@ dependencies = [ "indexmap", ] +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "piper" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" +dependencies = [ + "atomic-waker", + "fastrand", + "futures-io", +] + [[package]] name = "pkg-config" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +[[package]] +name = "polling" +version = "3.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3ed00ed3fbf728b5816498ecd316d1716eecaced9c0c8d2c5a6740ca214985b" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi 0.4.0", + "pin-project-lite", + "rustix", + "tracing", + "windows-sys 0.52.0", +] + [[package]] name = "pretty_assertions" version = "1.4.0" @@ -691,8 +805,9 @@ dependencies = [ [[package]] name = "reedline" -version = "0.35.0" +version = "0.36.0" dependencies = [ + "alacritty-test", "arboard", "chrono", "crossbeam", @@ -808,11 +923,23 @@ checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ "bitflags 2.5.0", "errno", + "itoa", "libc", "linux-raw-sys", "windows-sys 0.52.0", ] +[[package]] +name = "rustix-openpty" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a25c3aad9fc1424eb82c88087789a7d938e1829724f3e4043163baf0d13cfc12" +dependencies = [ + "errno", + "libc", + "rustix", +] + [[package]] name = "rustversion" version = "1.0.14" @@ -916,7 +1043,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55ff8ef943b384c414f54aefa961dd2bd853add74ec75e7ac74cf91dba62bcfa" dependencies = [ - "vte", + "vte 0.11.1", ] [[package]] @@ -981,6 +1108,22 @@ dependencies = [ "syn", ] +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" + [[package]] name = "tree_magic_mini" version = "3.1.4" @@ -1013,6 +1156,12 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +[[package]] +name = "unicode-width-16" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eba15036aa0f5bf8ed6cd12a624ddb61fd50b0779b1c05d89b663bcaed7b5c2" + [[package]] name = "utf8parse" version = "0.2.1" @@ -1041,6 +1190,20 @@ dependencies = [ "vte_generate_state_changes", ] +[[package]] +name = "vte" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40eb22ae96f050e0c0d6f7ce43feeae26c348fc4dea56928ca81537cfaa6188b" +dependencies = [ + "bitflags 2.5.0", + "cursor-icon", + "log", + "serde", + "utf8parse", + "vte_generate_state_changes", +] + [[package]] name = "vte_generate_state_changes" version = "0.1.1" diff --git a/Cargo.toml b/Cargo.toml index 12544dcf..a2a2f126 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,6 +36,7 @@ unicode-segmentation = "1.9.0" unicode-width = "0.1.9" [dev-dependencies] +alacritty-test = { git = "https://github.com/YizhePKU/alacritty-test.git", rev = "2f63ebe" } gethostname = "0.4.0" pretty_assertions = "1.4.0" rstest = { version = "0.18.0", default-features = false } diff --git a/examples/typing_latency.rs b/examples/typing_latency.rs new file mode 100644 index 00000000..b27e7cbf --- /dev/null +++ b/examples/typing_latency.rs @@ -0,0 +1,71 @@ +//! Measure the typing latency of Reedline with default configurations. + +use alacritty_test::{pty_spawn, EventedReadWrite, Terminal}; +use reedline::{DefaultPrompt, Reedline, Signal}; +use std::{ + io::Write, + time::{Duration, Instant}, +}; + +fn child() -> ! { + let mut line_editor = Reedline::create(); + let prompt = DefaultPrompt::default(); + + loop { + let sig = line_editor.read_line(&prompt).unwrap(); + match sig { + Signal::Success(buffer) => { + println!("We processed: {buffer}"); + } + _ => std::process::exit(-1), + } + } +} + +fn main() -> std::io::Result<()> { + if let Some(arg) = std::env::args().nth(1) { + if arg == "--child" { + child(); + } + } + + let mut pty = pty_spawn( + "target/debug/examples/typing_latency", + vec!["--child"], + None, + )?; + let mut terminal = Terminal::new(); + terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; + + // Test latency of a single keystroke. + let mut total_latency = Duration::from_millis(0); + for loop_cnt in 1.. { + let old_cursor = terminal.inner().grid().cursor.point; + + // input a single keystroke + pty.writer().write_all(b"A").unwrap(); + + let start_time = Instant::now(); + loop { + // measure with 10us accuracy + terminal.read_from_pty(&mut pty, Some(Duration::from_micros(10)))?; + + let new_cursor = terminal.inner().grid().cursor.point; + if new_cursor.column > old_cursor.column { + break; + } + } + total_latency += start_time.elapsed(); + + println!( + "single keystroke latency = {:.2}ms, averaging over {loop_cnt} iterations", + (total_latency.as_millis() as f64) / (loop_cnt as f64), + ); + + // delete the keystroke + pty.writer().write_all(b"\x7f\x7f\x7f\x7f").unwrap(); + terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; + } + + Ok(()) +} diff --git a/tests/basic.rs b/tests/basic.rs new file mode 100644 index 00000000..f46b43f7 --- /dev/null +++ b/tests/basic.rs @@ -0,0 +1,181 @@ +use alacritty_test::{extract_text, pty_spawn, EventedReadWrite, Terminal}; +use std::{io::Write, time::Duration}; + +/// Test if Reedline prints the prompt at startup. +#[test] +fn prints_prompt() -> std::io::Result<()> { + let mut pty = pty_spawn("target/debug/examples/basic", vec![], None)?; + let mut terminal = Terminal::new(); + terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; + + let text = extract_text(terminal.inner()); + assert_eq!(&text[0][..13], "~/reedline〉"); + + Ok(()) +} + +/// Test if Reedline echos back input when the user presses Enter. +#[test] +fn echos_input() -> std::io::Result<()> { + let mut pty = pty_spawn("target/debug/examples/basic", vec![], None)?; + let mut terminal = Terminal::new(); + terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; + + pty.writer().write_all(b"Hello World!\r")?; + terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; + let text = extract_text(terminal.inner()); + + assert_eq!(&text[0][13..25], "Hello World!"); + assert_eq!(&text[1][0..26], "We processed: Hello World!"); + assert_eq!(&text[2][0..13], "~/reedline〉"); + + Ok(()) +} + +/// Test if Reedline handles backspace correctly. +#[test] +fn backspace() -> std::io::Result<()> { + let mut pty = pty_spawn("target/debug/examples/basic", vec![], None)?; + let mut terminal = Terminal::new(); + terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; + + pty.writer().write_all(b"Hello World")?; + pty.writer().write_all(b"\x7f\x7f\x7f\x7f\x7f")?; + pty.writer().write_all(b"Bread!\r")?; + terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; + + let text = extract_text(terminal.inner()); + assert_eq!(&text[0][13..25], "Hello Bread!"); + assert_eq!(&text[1][0..26], "We processed: Hello Bread!"); + assert_eq!(&text[2][0..13], "~/reedline〉"); + + Ok(()) +} + +/// Test if Reedline supports history via up/down arrow. +#[test] +fn history() -> std::io::Result<()> { + let mut pty = pty_spawn("target/debug/examples/basic", vec![], None)?; + let mut terminal = Terminal::new(); + terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; + + pty.writer().write_all(b"Hello World!\r")?; + terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; + pty.writer().write_all(b"Goodbye!\r")?; + terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; + + // arrow up + pty.writer().write_all(b"\x1b[A")?; + terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; + let text = extract_text(terminal.inner()); + assert_eq!(&text[4][..21], "~/reedline〉Goodbye!"); + + // press Enter to execute it + pty.writer().write_all(b"\r")?; + terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; + let text = extract_text(terminal.inner()); + assert_eq!(&text[5][..22], "We processed: Goodbye!"); + + // arrow up twice + pty.writer().write_all(b"\x1b[A\x1b[A")?; + terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; + let text = extract_text(terminal.inner()); + assert_eq!(&text[6][..25], "~/reedline〉Hello World!"); + + // arrow down twice + pty.writer().write_all(b"\x1b[B\x1b[B")?; + terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; + let text = extract_text(terminal.inner()); + assert_eq!(&text[6][..25], "~/reedline〉 "); + + // type "Hel" then arrow up + pty.writer().write_all(b"Hel\x1b[A")?; + terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; + let text = extract_text(terminal.inner()); + assert_eq!(&text[6][..25], "~/reedline〉Hello World!"); + + // TODO: not sure how reverse search works in Reedline + + Ok(()) +} + +/// Test if Reedline supports ctrl-b/ctrl-f/ctrl-left/ctrl-right style movement. +#[test] +fn word_movement() -> std::io::Result<()> { + let mut pty = pty_spawn("target/debug/examples/basic", vec![], None)?; + let mut terminal = Terminal::new(); + terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; + + pty.writer().write_all(b"foo bar baz")?; + + // Ctrl-left twice, Ctrl-right once, Ctrl-b twice, Ctrl-f once. + pty.writer().write_all(b"\x1b[1;5D\x1b[1;5D")?; + pty.writer().write_all(b"\x1b[1;5C")?; + pty.writer().write_all(b"\x02\x02")?; + pty.writer().write_all(b"\x06")?; + + // Insert some more text, then press enter. + pty.writer().write_all(b"za\r")?; + terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; + + let text = extract_text(terminal.inner()); + assert_eq!(&text[0][..26], "~/reedline〉foo bazar baz"); + assert_eq!(&text[1][..27], "We processed: foo bazar baz"); + + Ok(()) +} + +/// Test if Ctrl-l clears the screen while keeping current entry. +#[test] +fn clear_screen() -> std::io::Result<()> { + let mut pty = pty_spawn("target/debug/examples/basic", vec![], None)?; + let mut terminal = Terminal::new(); + terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; + + pty.writer().write_all(b"Hello World!\r")?; + terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; + + pty.writer().write_all(b"Hello again!\x0c\r")?; + terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; + + let text = extract_text(terminal.inner()); + assert_eq!(&text[0][..25], "~/reedline〉Hello again!"); + + Ok(()) +} + +/// Test if Reedline supports common Emacs keybindings. +#[test] +fn emacs_keybinds() -> std::io::Result<()> { + let mut pty = pty_spawn("target/debug/examples/basic", vec![], None)?; + let mut terminal = Terminal::new(); + terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; + + pty.writer().write_all(b"Hello World!")?; + + // undo with Ctrl-z + pty.writer().write_all(b"\x1a")?; + terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; + let text = extract_text(terminal.inner()); + assert_eq!(&text[0][..25], "~/reedline〉Hello "); + + // redo with Ctrl-g + pty.writer().write_all(b"\x07")?; + terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; + let text = extract_text(terminal.inner()); + assert_eq!(&text[0][..25], "~/reedline〉Hello World!"); + + // delete "World" with alt+left, alt+backspace + pty.writer().write_all(b"\x1b[1;3D\x1b\x7f")?; + terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; + let text = extract_text(terminal.inner()); + assert_eq!(&text[0][..25], "~/reedline〉Hello ! "); + + // make "Hello" ALL CAPS with alt+b, alt+u + pty.writer().write_all(b"\x1bb\x1bu")?; + terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; + let text = extract_text(terminal.inner()); + assert_eq!(&text[0][..25], "~/reedline〉HELLO ! "); + + Ok(()) +} From c9ff13a01fc9638ccabdd3cb0dd270aa716d0e0b Mon Sep 17 00:00:00 2001 From: YizhePKU Date: Mon, 21 Oct 2024 15:13:00 +0800 Subject: [PATCH 2/9] Fix broken tests caused by path seperator differences --- tests/basic.rs | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/tests/basic.rs b/tests/basic.rs index f46b43f7..94302662 100644 --- a/tests/basic.rs +++ b/tests/basic.rs @@ -9,7 +9,10 @@ fn prints_prompt() -> std::io::Result<()> { terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; let text = extract_text(terminal.inner()); + #[cfg(not(windows))] assert_eq!(&text[0][..13], "~/reedline〉"); + #[cfg(windows)] + assert_eq!(&text[0][..13], "~\\reedline〉"); Ok(()) } @@ -27,7 +30,6 @@ fn echos_input() -> std::io::Result<()> { assert_eq!(&text[0][13..25], "Hello World!"); assert_eq!(&text[1][0..26], "We processed: Hello World!"); - assert_eq!(&text[2][0..13], "~/reedline〉"); Ok(()) } @@ -47,7 +49,6 @@ fn backspace() -> std::io::Result<()> { let text = extract_text(terminal.inner()); assert_eq!(&text[0][13..25], "Hello Bread!"); assert_eq!(&text[1][0..26], "We processed: Hello Bread!"); - assert_eq!(&text[2][0..13], "~/reedline〉"); Ok(()) } @@ -68,7 +69,7 @@ fn history() -> std::io::Result<()> { pty.writer().write_all(b"\x1b[A")?; terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; let text = extract_text(terminal.inner()); - assert_eq!(&text[4][..21], "~/reedline〉Goodbye!"); + assert_eq!(&text[4][13..21], "Goodbye!"); // press Enter to execute it pty.writer().write_all(b"\r")?; @@ -80,19 +81,19 @@ fn history() -> std::io::Result<()> { pty.writer().write_all(b"\x1b[A\x1b[A")?; terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; let text = extract_text(terminal.inner()); - assert_eq!(&text[6][..25], "~/reedline〉Hello World!"); + assert_eq!(&text[6][13..25], "Hello World!"); // arrow down twice pty.writer().write_all(b"\x1b[B\x1b[B")?; terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; let text = extract_text(terminal.inner()); - assert_eq!(&text[6][..25], "~/reedline〉 "); + assert_eq!(&text[6][13..25], " "); // type "Hel" then arrow up pty.writer().write_all(b"Hel\x1b[A")?; terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; let text = extract_text(terminal.inner()); - assert_eq!(&text[6][..25], "~/reedline〉Hello World!"); + assert_eq!(&text[6][13..25], "Hello World!"); // TODO: not sure how reverse search works in Reedline @@ -119,7 +120,7 @@ fn word_movement() -> std::io::Result<()> { terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; let text = extract_text(terminal.inner()); - assert_eq!(&text[0][..26], "~/reedline〉foo bazar baz"); + assert_eq!(&text[0][13..26], "foo bazar baz"); assert_eq!(&text[1][..27], "We processed: foo bazar baz"); Ok(()) @@ -139,7 +140,7 @@ fn clear_screen() -> std::io::Result<()> { terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; let text = extract_text(terminal.inner()); - assert_eq!(&text[0][..25], "~/reedline〉Hello again!"); + assert_eq!(&text[0][13..25], "Hello again!"); Ok(()) } @@ -157,25 +158,25 @@ fn emacs_keybinds() -> std::io::Result<()> { pty.writer().write_all(b"\x1a")?; terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; let text = extract_text(terminal.inner()); - assert_eq!(&text[0][..25], "~/reedline〉Hello "); + assert_eq!(&text[0][13..25], "Hello "); // redo with Ctrl-g pty.writer().write_all(b"\x07")?; terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; let text = extract_text(terminal.inner()); - assert_eq!(&text[0][..25], "~/reedline〉Hello World!"); + assert_eq!(&text[0][13..25], "Hello World!"); // delete "World" with alt+left, alt+backspace pty.writer().write_all(b"\x1b[1;3D\x1b\x7f")?; terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; let text = extract_text(terminal.inner()); - assert_eq!(&text[0][..25], "~/reedline〉Hello ! "); + assert_eq!(&text[0][13..25], "Hello ! "); // make "Hello" ALL CAPS with alt+b, alt+u pty.writer().write_all(b"\x1bb\x1bu")?; terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; let text = extract_text(terminal.inner()); - assert_eq!(&text[0][..25], "~/reedline〉HELLO ! "); + assert_eq!(&text[0][13..25], "HELLO ! "); Ok(()) } From 21e11dfb1393611bee42fb841fae720b7baee47c Mon Sep 17 00:00:00 2001 From: YizhePKU Date: Mon, 21 Oct 2024 15:15:04 +0800 Subject: [PATCH 3/9] Bump `alacritty-test` to fix Windows issues --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 53d0a832..2e798cd6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,7 +26,7 @@ dependencies = [ [[package]] name = "alacritty-test" version = "0.1.0" -source = "git+https://github.com/YizhePKU/alacritty-test.git?rev=2f63ebe#2f63ebe293c7026e24342a3b934bc747065c5240" +source = "git+https://github.com/YizhePKU/alacritty-test.git?rev=1c6dabc#1c6dabc3feaa8421cc5f557c9dae94382861e5da" dependencies = [ "alacritty_terminal", "polling", diff --git a/Cargo.toml b/Cargo.toml index a2a2f126..fd390c5e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,7 @@ unicode-segmentation = "1.9.0" unicode-width = "0.1.9" [dev-dependencies] -alacritty-test = { git = "https://github.com/YizhePKU/alacritty-test.git", rev = "2f63ebe" } +alacritty-test = { git = "https://github.com/YizhePKU/alacritty-test.git", rev = "1c6dabc" } gethostname = "0.4.0" pretty_assertions = "1.4.0" rstest = { version = "0.18.0", default-features = false } From c47fb1f0e921b4cd5e8dc18186dfa45056b8adc8 Mon Sep 17 00:00:00 2001 From: YizhePKU Date: Mon, 21 Oct 2024 15:40:17 +0800 Subject: [PATCH 4/9] Bump `alacritty-test` to fix Unix issues --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2e798cd6..afbea332 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,7 +26,7 @@ dependencies = [ [[package]] name = "alacritty-test" version = "0.1.0" -source = "git+https://github.com/YizhePKU/alacritty-test.git?rev=1c6dabc#1c6dabc3feaa8421cc5f557c9dae94382861e5da" +source = "git+https://github.com/YizhePKU/alacritty-test.git?rev=d8d0196#d8d01966df742269586380ccaff8af9184bc5320" dependencies = [ "alacritty_terminal", "polling", diff --git a/Cargo.toml b/Cargo.toml index fd390c5e..854839dd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,7 @@ unicode-segmentation = "1.9.0" unicode-width = "0.1.9" [dev-dependencies] -alacritty-test = { git = "https://github.com/YizhePKU/alacritty-test.git", rev = "1c6dabc" } +alacritty-test = { git = "https://github.com/YizhePKU/alacritty-test.git", rev = "d8d0196" } gethostname = "0.4.0" pretty_assertions = "1.4.0" rstest = { version = "0.18.0", default-features = false } From d32c3b5053bbefe87244870bddb337222656de4b Mon Sep 17 00:00:00 2001 From: YizhePKU Date: Mon, 21 Oct 2024 16:17:52 +0800 Subject: [PATCH 5/9] Improve the reliability of `write_all()` --- Cargo.lock | 2 +- Cargo.toml | 2 +- examples/typing_latency.rs | 11 +++----- tests/basic.rs | 52 +++++++++++++++++++------------------- 4 files changed, 32 insertions(+), 35 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index afbea332..c25013bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,7 +26,7 @@ dependencies = [ [[package]] name = "alacritty-test" version = "0.1.0" -source = "git+https://github.com/YizhePKU/alacritty-test.git?rev=d8d0196#d8d01966df742269586380ccaff8af9184bc5320" +source = "git+https://github.com/YizhePKU/alacritty-test.git?rev=6c4df50#6c4df50be8b94182928895df2b6fb73ca0d6cf73" dependencies = [ "alacritty_terminal", "polling", diff --git a/Cargo.toml b/Cargo.toml index 854839dd..b747c837 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,7 @@ unicode-segmentation = "1.9.0" unicode-width = "0.1.9" [dev-dependencies] -alacritty-test = { git = "https://github.com/YizhePKU/alacritty-test.git", rev = "d8d0196" } +alacritty-test = { git = "https://github.com/YizhePKU/alacritty-test.git", rev = "6c4df50" } gethostname = "0.4.0" pretty_assertions = "1.4.0" rstest = { version = "0.18.0", default-features = false } diff --git a/examples/typing_latency.rs b/examples/typing_latency.rs index b27e7cbf..350bcb69 100644 --- a/examples/typing_latency.rs +++ b/examples/typing_latency.rs @@ -1,11 +1,8 @@ //! Measure the typing latency of Reedline with default configurations. -use alacritty_test::{pty_spawn, EventedReadWrite, Terminal}; +use alacritty_test::{pty_spawn, PtyExt, Terminal}; use reedline::{DefaultPrompt, Reedline, Signal}; -use std::{ - io::Write, - time::{Duration, Instant}, -}; +use std::time::{Duration, Instant}; fn child() -> ! { let mut line_editor = Reedline::create(); @@ -43,7 +40,7 @@ fn main() -> std::io::Result<()> { let old_cursor = terminal.inner().grid().cursor.point; // input a single keystroke - pty.writer().write_all(b"A").unwrap(); + pty.write_all(b"A").unwrap(); let start_time = Instant::now(); loop { @@ -63,7 +60,7 @@ fn main() -> std::io::Result<()> { ); // delete the keystroke - pty.writer().write_all(b"\x7f\x7f\x7f\x7f").unwrap(); + pty.write_all(b"\x7f\x7f\x7f\x7f").unwrap(); terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; } diff --git a/tests/basic.rs b/tests/basic.rs index 94302662..8f92b7d0 100644 --- a/tests/basic.rs +++ b/tests/basic.rs @@ -1,5 +1,5 @@ -use alacritty_test::{extract_text, pty_spawn, EventedReadWrite, Terminal}; -use std::{io::Write, time::Duration}; +use alacritty_test::{extract_text, pty_spawn, PtyExt, Terminal}; +use std::time::Duration; /// Test if Reedline prints the prompt at startup. #[test] @@ -24,7 +24,7 @@ fn echos_input() -> std::io::Result<()> { let mut terminal = Terminal::new(); terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; - pty.writer().write_all(b"Hello World!\r")?; + pty.write_all(b"Hello World!\r")?; terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; let text = extract_text(terminal.inner()); @@ -41,9 +41,9 @@ fn backspace() -> std::io::Result<()> { let mut terminal = Terminal::new(); terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; - pty.writer().write_all(b"Hello World")?; - pty.writer().write_all(b"\x7f\x7f\x7f\x7f\x7f")?; - pty.writer().write_all(b"Bread!\r")?; + pty.write_all(b"Hello World")?; + pty.write_all(b"\x7f\x7f\x7f\x7f\x7f")?; + pty.write_all(b"Bread!\r")?; terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; let text = extract_text(terminal.inner()); @@ -60,37 +60,37 @@ fn history() -> std::io::Result<()> { let mut terminal = Terminal::new(); terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; - pty.writer().write_all(b"Hello World!\r")?; + pty.write_all(b"Hello World!\r")?; terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; - pty.writer().write_all(b"Goodbye!\r")?; + pty.write_all(b"Goodbye!\r")?; terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; // arrow up - pty.writer().write_all(b"\x1b[A")?; + pty.write_all(b"\x1b[A")?; terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; let text = extract_text(terminal.inner()); assert_eq!(&text[4][13..21], "Goodbye!"); // press Enter to execute it - pty.writer().write_all(b"\r")?; + pty.write_all(b"\r")?; terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; let text = extract_text(terminal.inner()); assert_eq!(&text[5][..22], "We processed: Goodbye!"); // arrow up twice - pty.writer().write_all(b"\x1b[A\x1b[A")?; + pty.write_all(b"\x1b[A\x1b[A")?; terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; let text = extract_text(terminal.inner()); assert_eq!(&text[6][13..25], "Hello World!"); // arrow down twice - pty.writer().write_all(b"\x1b[B\x1b[B")?; + pty.write_all(b"\x1b[B\x1b[B")?; terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; let text = extract_text(terminal.inner()); assert_eq!(&text[6][13..25], " "); // type "Hel" then arrow up - pty.writer().write_all(b"Hel\x1b[A")?; + pty.write_all(b"Hel\x1b[A")?; terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; let text = extract_text(terminal.inner()); assert_eq!(&text[6][13..25], "Hello World!"); @@ -107,16 +107,16 @@ fn word_movement() -> std::io::Result<()> { let mut terminal = Terminal::new(); terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; - pty.writer().write_all(b"foo bar baz")?; + pty.write_all(b"foo bar baz")?; // Ctrl-left twice, Ctrl-right once, Ctrl-b twice, Ctrl-f once. - pty.writer().write_all(b"\x1b[1;5D\x1b[1;5D")?; - pty.writer().write_all(b"\x1b[1;5C")?; - pty.writer().write_all(b"\x02\x02")?; - pty.writer().write_all(b"\x06")?; + pty.write_all(b"\x1b[1;5D\x1b[1;5D")?; + pty.write_all(b"\x1b[1;5C")?; + pty.write_all(b"\x02\x02")?; + pty.write_all(b"\x06")?; // Insert some more text, then press enter. - pty.writer().write_all(b"za\r")?; + pty.write_all(b"za\r")?; terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; let text = extract_text(terminal.inner()); @@ -133,10 +133,10 @@ fn clear_screen() -> std::io::Result<()> { let mut terminal = Terminal::new(); terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; - pty.writer().write_all(b"Hello World!\r")?; + pty.write_all(b"Hello World!\r")?; terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; - pty.writer().write_all(b"Hello again!\x0c\r")?; + pty.write_all(b"Hello again!\x0c\r")?; terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; let text = extract_text(terminal.inner()); @@ -152,28 +152,28 @@ fn emacs_keybinds() -> std::io::Result<()> { let mut terminal = Terminal::new(); terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; - pty.writer().write_all(b"Hello World!")?; + pty.write_all(b"Hello World!")?; // undo with Ctrl-z - pty.writer().write_all(b"\x1a")?; + pty.write_all(b"\x1a")?; terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; let text = extract_text(terminal.inner()); assert_eq!(&text[0][13..25], "Hello "); // redo with Ctrl-g - pty.writer().write_all(b"\x07")?; + pty.write_all(b"\x07")?; terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; let text = extract_text(terminal.inner()); assert_eq!(&text[0][13..25], "Hello World!"); // delete "World" with alt+left, alt+backspace - pty.writer().write_all(b"\x1b[1;3D\x1b\x7f")?; + pty.write_all(b"\x1b[1;3D\x1b\x7f")?; terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; let text = extract_text(terminal.inner()); assert_eq!(&text[0][13..25], "Hello ! "); // make "Hello" ALL CAPS with alt+b, alt+u - pty.writer().write_all(b"\x1bb\x1bu")?; + pty.write_all(b"\x1bb\x1bu")?; terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; let text = extract_text(terminal.inner()); assert_eq!(&text[0][13..25], "HELLO ! "); From 07f11a5c819532bbee0272883d49b07bdef9ace3 Mon Sep 17 00:00:00 2001 From: YizhePKU Date: Mon, 21 Oct 2024 16:41:51 +0800 Subject: [PATCH 6/9] Update display format for `typing_latency.rs` --- examples/typing_latency.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/examples/typing_latency.rs b/examples/typing_latency.rs index 350bcb69..4ebc21dc 100644 --- a/examples/typing_latency.rs +++ b/examples/typing_latency.rs @@ -1,4 +1,7 @@ //! Measure the typing latency of Reedline with default configurations. +//! +//! The result is not accurate on Windows, since alacritty has very bad latency +//! response on Windows due to the way it implemented async-IO without IOCP. use alacritty_test::{pty_spawn, PtyExt, Terminal}; use reedline::{DefaultPrompt, Reedline, Signal}; @@ -52,11 +55,13 @@ fn main() -> std::io::Result<()> { break; } } - total_latency += start_time.elapsed(); + let latency = start_time.elapsed(); + total_latency += latency; println!( - "single keystroke latency = {:.2}ms, averaging over {loop_cnt} iterations", - (total_latency.as_millis() as f64) / (loop_cnt as f64), + "single keystroke latency = {:.2}ms, average latency = {:.2}ms over {loop_cnt} iterations", + (latency.as_millis() as f64), + (total_latency.as_millis() as f64) / (loop_cnt as f64) ); // delete the keystroke From 1115b0df250c97a77b7e01d517e98a2367efce0d Mon Sep 17 00:00:00 2001 From: YizhePKU Date: Mon, 21 Oct 2024 17:01:40 +0800 Subject: [PATCH 7/9] Support nextest --- src/bin/testbin.rs | 22 ++++++++++++++++++++++ tests/basic.rs | 37 ++++++++++++++++++++++++++++--------- 2 files changed, 50 insertions(+), 9 deletions(-) create mode 100644 src/bin/testbin.rs diff --git a/src/bin/testbin.rs b/src/bin/testbin.rs new file mode 100644 index 00000000..b83a5b3e --- /dev/null +++ b/src/bin/testbin.rs @@ -0,0 +1,22 @@ +//! Test binary for UX testing. + +use reedline::{DefaultPrompt, Reedline, Signal}; +use std::io; + +fn main() -> io::Result<()> { + let mut line_editor = Reedline::create(); + let prompt = DefaultPrompt::default(); + + loop { + let sig = line_editor.read_line(&prompt)?; + match sig { + Signal::Success(buffer) => { + println!("We processed: {buffer}"); + } + Signal::CtrlD | Signal::CtrlC => { + println!("\nAborted!"); + break Ok(()); + } + } + } +} diff --git a/tests/basic.rs b/tests/basic.rs index 8f92b7d0..6ce249f5 100644 --- a/tests/basic.rs +++ b/tests/basic.rs @@ -1,10 +1,29 @@ use alacritty_test::{extract_text, pty_spawn, PtyExt, Terminal}; use std::time::Duration; +/// Return the absolute path to the test binary. +fn testbin() -> String { + if let Ok(nextest) = std::env::var("NEXTEST") { + if nextest == "1" { + return std::env::var("NEXTEST_BIN_EXE_testbin").unwrap(); + } + } + + #[cfg(not(windows))] + let path = "target/debug/testbin"; + #[cfg(windows)] + let path = "target/debug/testbin.exe"; + + std::fs::canonicalize(path) + .unwrap() + .to_string_lossy() + .to_string() +} + /// Test if Reedline prints the prompt at startup. #[test] fn prints_prompt() -> std::io::Result<()> { - let mut pty = pty_spawn("target/debug/examples/basic", vec![], None)?; + let mut pty = pty_spawn(&testbin(), vec![], None)?; let mut terminal = Terminal::new(); terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; @@ -20,7 +39,7 @@ fn prints_prompt() -> std::io::Result<()> { /// Test if Reedline echos back input when the user presses Enter. #[test] fn echos_input() -> std::io::Result<()> { - let mut pty = pty_spawn("target/debug/examples/basic", vec![], None)?; + let mut pty = pty_spawn(&testbin(), vec![], None)?; let mut terminal = Terminal::new(); terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; @@ -37,7 +56,7 @@ fn echos_input() -> std::io::Result<()> { /// Test if Reedline handles backspace correctly. #[test] fn backspace() -> std::io::Result<()> { - let mut pty = pty_spawn("target/debug/examples/basic", vec![], None)?; + let mut pty = pty_spawn(&testbin(), vec![], None)?; let mut terminal = Terminal::new(); terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; @@ -56,7 +75,7 @@ fn backspace() -> std::io::Result<()> { /// Test if Reedline supports history via up/down arrow. #[test] fn history() -> std::io::Result<()> { - let mut pty = pty_spawn("target/debug/examples/basic", vec![], None)?; + let mut pty = pty_spawn(&testbin(), vec![], None)?; let mut terminal = Terminal::new(); terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; @@ -89,8 +108,8 @@ fn history() -> std::io::Result<()> { let text = extract_text(terminal.inner()); assert_eq!(&text[6][13..25], " "); - // type "Hel" then arrow up - pty.write_all(b"Hel\x1b[A")?; + // type "Hell" then arrow up + pty.write_all(b"Hell\x1b[A")?; terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; let text = extract_text(terminal.inner()); assert_eq!(&text[6][13..25], "Hello World!"); @@ -103,7 +122,7 @@ fn history() -> std::io::Result<()> { /// Test if Reedline supports ctrl-b/ctrl-f/ctrl-left/ctrl-right style movement. #[test] fn word_movement() -> std::io::Result<()> { - let mut pty = pty_spawn("target/debug/examples/basic", vec![], None)?; + let mut pty = pty_spawn(&testbin(), vec![], None)?; let mut terminal = Terminal::new(); terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; @@ -129,7 +148,7 @@ fn word_movement() -> std::io::Result<()> { /// Test if Ctrl-l clears the screen while keeping current entry. #[test] fn clear_screen() -> std::io::Result<()> { - let mut pty = pty_spawn("target/debug/examples/basic", vec![], None)?; + let mut pty = pty_spawn(&testbin(), vec![], None)?; let mut terminal = Terminal::new(); terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; @@ -148,7 +167,7 @@ fn clear_screen() -> std::io::Result<()> { /// Test if Reedline supports common Emacs keybindings. #[test] fn emacs_keybinds() -> std::io::Result<()> { - let mut pty = pty_spawn("target/debug/examples/basic", vec![], None)?; + let mut pty = pty_spawn(&testbin(), vec![], None)?; let mut terminal = Terminal::new(); terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; From 50974785187bae630674361d52c51325408bad22 Mon Sep 17 00:00:00 2001 From: YizhePKU Date: Mon, 21 Oct 2024 09:17:58 +0000 Subject: [PATCH 8/9] Avoid PWD in prompt CI tends to run tests in unpredictable PWD. --- src/bin/testbin.rs | 7 +++++-- tests/basic.rs | 29 +++++++++++++---------------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/bin/testbin.rs b/src/bin/testbin.rs index b83a5b3e..49374f44 100644 --- a/src/bin/testbin.rs +++ b/src/bin/testbin.rs @@ -1,11 +1,14 @@ //! Test binary for UX testing. -use reedline::{DefaultPrompt, Reedline, Signal}; +use reedline::{DefaultPrompt, DefaultPromptSegment, Reedline, Signal}; use std::io; fn main() -> io::Result<()> { let mut line_editor = Reedline::create(); - let prompt = DefaultPrompt::default(); + let prompt = DefaultPrompt::new( + DefaultPromptSegment::Basic("Reedline".to_string()), + DefaultPromptSegment::Empty, + ); loop { let sig = line_editor.read_line(&prompt)?; diff --git a/tests/basic.rs b/tests/basic.rs index 6ce249f5..0cb682cd 100644 --- a/tests/basic.rs +++ b/tests/basic.rs @@ -28,10 +28,7 @@ fn prints_prompt() -> std::io::Result<()> { terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; let text = extract_text(terminal.inner()); - #[cfg(not(windows))] - assert_eq!(&text[0][..13], "~/reedline〉"); - #[cfg(windows)] - assert_eq!(&text[0][..13], "~\\reedline〉"); + assert_eq!(&text[0][..11], "Reedline〉"); Ok(()) } @@ -47,7 +44,7 @@ fn echos_input() -> std::io::Result<()> { terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; let text = extract_text(terminal.inner()); - assert_eq!(&text[0][13..25], "Hello World!"); + assert_eq!(&text[0][..23], "Reedline〉Hello World!"); assert_eq!(&text[1][0..26], "We processed: Hello World!"); Ok(()) @@ -66,7 +63,7 @@ fn backspace() -> std::io::Result<()> { terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; let text = extract_text(terminal.inner()); - assert_eq!(&text[0][13..25], "Hello Bread!"); + assert_eq!(&text[0][..23], "Reedline〉Hello Bread!"); assert_eq!(&text[1][0..26], "We processed: Hello Bread!"); Ok(()) @@ -88,7 +85,7 @@ fn history() -> std::io::Result<()> { pty.write_all(b"\x1b[A")?; terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; let text = extract_text(terminal.inner()); - assert_eq!(&text[4][13..21], "Goodbye!"); + assert_eq!(&text[4][..19], "Reedline〉Goodbye!"); // press Enter to execute it pty.write_all(b"\r")?; @@ -100,19 +97,19 @@ fn history() -> std::io::Result<()> { pty.write_all(b"\x1b[A\x1b[A")?; terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; let text = extract_text(terminal.inner()); - assert_eq!(&text[6][13..25], "Hello World!"); + assert_eq!(&text[6][..23], "Reedline〉Hello World!"); // arrow down twice pty.write_all(b"\x1b[B\x1b[B")?; terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; let text = extract_text(terminal.inner()); - assert_eq!(&text[6][13..25], " "); + assert_eq!(&text[6][..23], "Reedline〉 "); // type "Hell" then arrow up pty.write_all(b"Hell\x1b[A")?; terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; let text = extract_text(terminal.inner()); - assert_eq!(&text[6][13..25], "Hello World!"); + assert_eq!(&text[6][..23], "Reedline〉Hello World!"); // TODO: not sure how reverse search works in Reedline @@ -139,7 +136,7 @@ fn word_movement() -> std::io::Result<()> { terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; let text = extract_text(terminal.inner()); - assert_eq!(&text[0][13..26], "foo bazar baz"); + assert_eq!(&text[0][..24], "Reedline〉foo bazar baz"); assert_eq!(&text[1][..27], "We processed: foo bazar baz"); Ok(()) @@ -159,7 +156,7 @@ fn clear_screen() -> std::io::Result<()> { terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; let text = extract_text(terminal.inner()); - assert_eq!(&text[0][13..25], "Hello again!"); + assert_eq!(&text[0][..23], "Reedline〉Hello again!"); Ok(()) } @@ -177,25 +174,25 @@ fn emacs_keybinds() -> std::io::Result<()> { pty.write_all(b"\x1a")?; terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; let text = extract_text(terminal.inner()); - assert_eq!(&text[0][13..25], "Hello "); + assert_eq!(&text[0][..23], "Reedline〉Hello "); // redo with Ctrl-g pty.write_all(b"\x07")?; terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; let text = extract_text(terminal.inner()); - assert_eq!(&text[0][13..25], "Hello World!"); + assert_eq!(&text[0][..23], "Reedline〉Hello World!"); // delete "World" with alt+left, alt+backspace pty.write_all(b"\x1b[1;3D\x1b\x7f")?; terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; let text = extract_text(terminal.inner()); - assert_eq!(&text[0][13..25], "Hello ! "); + assert_eq!(&text[0][..23], "Reedline〉Hello ! "); // make "Hello" ALL CAPS with alt+b, alt+u pty.write_all(b"\x1bb\x1bu")?; terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; let text = extract_text(terminal.inner()); - assert_eq!(&text[0][13..25], "HELLO ! "); + assert_eq!(&text[0][..23], "Reedline〉HELLO ! "); Ok(()) } From 206ec13a107021d824a757b35a552fdcfa65b27f Mon Sep 17 00:00:00 2001 From: YizhePKU Date: Tue, 22 Oct 2024 01:57:01 +0800 Subject: [PATCH 9/9] Remove `examples/typing_latency.rs` It's useful, but probably doesn't belong to this PR. --- examples/typing_latency.rs | 73 -------------------------------------- 1 file changed, 73 deletions(-) delete mode 100644 examples/typing_latency.rs diff --git a/examples/typing_latency.rs b/examples/typing_latency.rs deleted file mode 100644 index 4ebc21dc..00000000 --- a/examples/typing_latency.rs +++ /dev/null @@ -1,73 +0,0 @@ -//! Measure the typing latency of Reedline with default configurations. -//! -//! The result is not accurate on Windows, since alacritty has very bad latency -//! response on Windows due to the way it implemented async-IO without IOCP. - -use alacritty_test::{pty_spawn, PtyExt, Terminal}; -use reedline::{DefaultPrompt, Reedline, Signal}; -use std::time::{Duration, Instant}; - -fn child() -> ! { - let mut line_editor = Reedline::create(); - let prompt = DefaultPrompt::default(); - - loop { - let sig = line_editor.read_line(&prompt).unwrap(); - match sig { - Signal::Success(buffer) => { - println!("We processed: {buffer}"); - } - _ => std::process::exit(-1), - } - } -} - -fn main() -> std::io::Result<()> { - if let Some(arg) = std::env::args().nth(1) { - if arg == "--child" { - child(); - } - } - - let mut pty = pty_spawn( - "target/debug/examples/typing_latency", - vec!["--child"], - None, - )?; - let mut terminal = Terminal::new(); - terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; - - // Test latency of a single keystroke. - let mut total_latency = Duration::from_millis(0); - for loop_cnt in 1.. { - let old_cursor = terminal.inner().grid().cursor.point; - - // input a single keystroke - pty.write_all(b"A").unwrap(); - - let start_time = Instant::now(); - loop { - // measure with 10us accuracy - terminal.read_from_pty(&mut pty, Some(Duration::from_micros(10)))?; - - let new_cursor = terminal.inner().grid().cursor.point; - if new_cursor.column > old_cursor.column { - break; - } - } - let latency = start_time.elapsed(); - total_latency += latency; - - println!( - "single keystroke latency = {:.2}ms, average latency = {:.2}ms over {loop_cnt} iterations", - (latency.as_millis() as f64), - (total_latency.as_millis() as f64) / (loop_cnt as f64) - ); - - // delete the keystroke - pty.write_all(b"\x7f\x7f\x7f\x7f").unwrap(); - terminal.read_from_pty(&mut pty, Some(Duration::from_millis(50)))?; - } - - Ok(()) -}