Merge cafbace836
into 366e52b76d
This commit is contained in:
commit
86018fdcf6
108
Cargo.lock
generated
108
Cargo.lock
generated
|
@ -56,6 +56,30 @@ dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "alacritty_terminal"
|
||||||
|
version = "0.24.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "db5ad9e2d4c1f7e17fccec9493eeb4e9c1f00e1167519d3940272b708ed8a069"
|
||||||
|
dependencies = [
|
||||||
|
"base64 0.22.1",
|
||||||
|
"bitflags 2.5.0",
|
||||||
|
"home",
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"miow",
|
||||||
|
"parking_lot",
|
||||||
|
"piper",
|
||||||
|
"polling",
|
||||||
|
"regex-automata",
|
||||||
|
"rustix-openpty",
|
||||||
|
"serde",
|
||||||
|
"signal-hook",
|
||||||
|
"unicode-width",
|
||||||
|
"vte 0.13.0",
|
||||||
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "alloc-no-stdlib"
|
name = "alloc-no-stdlib"
|
||||||
version = "2.0.4"
|
version = "2.0.4"
|
||||||
|
@ -297,6 +321,12 @@ version = "0.15.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9ae037714f313c1353189ead58ef9eec30a8e8dc101b2622d461418fd59e28a9"
|
checksum = "9ae037714f313c1353189ead58ef9eec30a8e8dc101b2622d461418fd59e28a9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "atomic-waker"
|
||||||
|
version = "1.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
|
@ -867,6 +897,15 @@ dependencies = [
|
||||||
"static_assertions",
|
"static_assertions",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "concurrent-queue"
|
||||||
|
version = "2.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "console"
|
name = "console"
|
||||||
version = "0.15.8"
|
version = "0.15.8"
|
||||||
|
@ -1147,6 +1186,12 @@ dependencies = [
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cursor-icon"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deranged"
|
name = "deranged"
|
||||||
version = "0.3.11"
|
version = "0.3.11"
|
||||||
|
@ -2730,6 +2775,15 @@ dependencies = [
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.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]]
|
[[package]]
|
||||||
name = "mockito"
|
name = "mockito"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
|
@ -2870,6 +2924,7 @@ dependencies = [
|
||||||
name = "nu"
|
name = "nu"
|
||||||
version = "0.95.1"
|
version = "0.95.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"alacritty_terminal",
|
||||||
"assert_cmd",
|
"assert_cmd",
|
||||||
"crossterm",
|
"crossterm",
|
||||||
"ctrlc",
|
"ctrlc",
|
||||||
|
@ -3427,6 +3482,7 @@ dependencies = [
|
||||||
name = "nu-test-support"
|
name = "nu-test-support"
|
||||||
version = "0.95.1"
|
version = "0.95.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"alacritty_terminal",
|
||||||
"nu-glob",
|
"nu-glob",
|
||||||
"nu-path",
|
"nu-path",
|
||||||
"nu-utils",
|
"nu-utils",
|
||||||
|
@ -4116,6 +4172,17 @@ version = "0.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "piper"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "464db0c665917b13ebb5d453ccdec4add5658ee1adc7affc7677615356a8afaf"
|
||||||
|
dependencies = [
|
||||||
|
"atomic-waker",
|
||||||
|
"fastrand",
|
||||||
|
"futures-io",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pkg-config"
|
name = "pkg-config"
|
||||||
version = "0.3.30"
|
version = "0.3.30"
|
||||||
|
@ -4602,6 +4669,21 @@ dependencies = [
|
||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "polling"
|
||||||
|
version = "3.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "645493cf344456ef24219d02a768cf1fb92ddf8c92161679ae3d91b91a637be3"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"concurrent-queue",
|
||||||
|
"hermit-abi",
|
||||||
|
"pin-project-lite",
|
||||||
|
"rustix",
|
||||||
|
"tracing",
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pori"
|
name = "pori"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
|
@ -5307,11 +5389,23 @@ checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.5.0",
|
"bitflags 2.5.0",
|
||||||
"errno",
|
"errno",
|
||||||
|
"itoa",
|
||||||
"libc",
|
"libc",
|
||||||
"linux-raw-sys",
|
"linux-raw-sys",
|
||||||
"windows-sys 0.52.0",
|
"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]]
|
[[package]]
|
||||||
name = "rustversion"
|
name = "rustversion"
|
||||||
version = "1.0.15"
|
version = "1.0.15"
|
||||||
|
@ -6700,6 +6794,20 @@ dependencies = [
|
||||||
"vte_generate_state_changes",
|
"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]]
|
[[package]]
|
||||||
name = "vte_generate_state_changes"
|
name = "vte_generate_state_changes"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
|
|
|
@ -62,6 +62,7 @@ members = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
|
alacritty_terminal = "0.24"
|
||||||
alphanumeric-sort = "1.5"
|
alphanumeric-sort = "1.5"
|
||||||
ansi-str = "0.8"
|
ansi-str = "0.8"
|
||||||
anyhow = "1.0.82"
|
anyhow = "1.0.82"
|
||||||
|
@ -230,6 +231,7 @@ nix = { workspace = true, default-features = false, features = [
|
||||||
nu-test-support = { path = "./crates/nu-test-support", version = "0.95.1" }
|
nu-test-support = { path = "./crates/nu-test-support", version = "0.95.1" }
|
||||||
nu-plugin-protocol = { path = "./crates/nu-plugin-protocol", version = "0.95.1" }
|
nu-plugin-protocol = { path = "./crates/nu-plugin-protocol", version = "0.95.1" }
|
||||||
nu-plugin-core = { path = "./crates/nu-plugin-core", version = "0.95.1" }
|
nu-plugin-core = { path = "./crates/nu-plugin-core", version = "0.95.1" }
|
||||||
|
alacritty_terminal = { workspace = true }
|
||||||
assert_cmd = "2.0"
|
assert_cmd = "2.0"
|
||||||
dirs = { workspace = true }
|
dirs = { workspace = true }
|
||||||
tango-bench = "0.5"
|
tango-bench = "0.5"
|
||||||
|
|
|
@ -18,4 +18,5 @@ nu-utils = { path = "../nu-utils", version = "0.95.1" }
|
||||||
|
|
||||||
num-format = { workspace = true }
|
num-format = { workspace = true }
|
||||||
which = { workspace = true }
|
which = { workspace = true }
|
||||||
tempfile = { workspace = true }
|
tempfile = { workspace = true }
|
||||||
|
alacritty_terminal = { workspace = true }
|
||||||
|
|
|
@ -4,6 +4,7 @@ pub mod fs;
|
||||||
pub mod locale_override;
|
pub mod locale_override;
|
||||||
pub mod macros;
|
pub mod macros;
|
||||||
pub mod playground;
|
pub mod playground;
|
||||||
|
pub mod terminal;
|
||||||
use std::process::ExitStatus;
|
use std::process::ExitStatus;
|
||||||
|
|
||||||
// Needs to be reexported for `nu!` macro
|
// Needs to be reexported for `nu!` macro
|
||||||
|
|
176
crates/nu-test-support/src/terminal.rs
Normal file
176
crates/nu-test-support/src/terminal.rs
Normal file
|
@ -0,0 +1,176 @@
|
||||||
|
//! Helper functions for tests that requires a terminal emulator. Terminal
|
||||||
|
//! emulation is supported by the `alacritty_terminal` crate.
|
||||||
|
//!
|
||||||
|
//! Here's the general process of writing a test with a terminal emulator. This
|
||||||
|
//! module provides helper functions for common cases, but you can always do it
|
||||||
|
//! on your own. Examples can be found in `tests/terminal`.
|
||||||
|
//!
|
||||||
|
//! Step 1: Create an `alacritty_terminal::Term` instance. Here you can
|
||||||
|
//! configure window size and scrollback buffer size, etc. `default_terminal()`
|
||||||
|
//! will create one for you with sensible defaults.
|
||||||
|
//!
|
||||||
|
//! Step 2: Create a PTY and spawn a Nushell process to the slave end.
|
||||||
|
//! `pty_with_nushell()` will do that for you. Here you can set PWD or pass
|
||||||
|
//! command line arguments to Nushell. It's always a good idea to pass
|
||||||
|
//! `--no-config-file`, otherwise Nushell will ask if you want to create one
|
||||||
|
//! with default, and that messes up the input.
|
||||||
|
//!
|
||||||
|
//! Step 3: Wait for Nushell to initialize (sleeping for 500ms should do).
|
||||||
|
//! `pty_with_nushell()` also does that for you. On Linux, trying to write to
|
||||||
|
//! the PTY before Nushell finishes initialization appears to succeed, but the
|
||||||
|
//! data will be lost. I'm not sure if this is a bug or just weird behavior of
|
||||||
|
//! Linux PTY. It's not necessary on Windows, but it won't hurt either.
|
||||||
|
//!
|
||||||
|
//! Step 4: Write data to the PTY. Any data you sent will appear to Nushell as
|
||||||
|
//! if they were typed in a terminal. ANSI escape codes are used for special
|
||||||
|
//! keystrokes. For example, if you want to press Enter, send "\r" (NOT "\n").
|
||||||
|
//! On Linux, use `showkey -a` to see the actual value of a keystroke. The
|
||||||
|
//! [Wikipedia page](https://en.wikipedia.org/wiki/ANSI_escape_code) also
|
||||||
|
//! contains a list of common ANSI escape codes.
|
||||||
|
//!
|
||||||
|
//! Step 5: Wait for Nushell to respond and update the terminal state. Sometimes
|
||||||
|
//! Nushell will emit terminal events (e.g. querying cursor position, modifying
|
||||||
|
//! system clipboard), and these events need to be handled. `read_to_end()` will
|
||||||
|
//! do that for you, and you can use `pty_write_handler()` for the event handler
|
||||||
|
//! if you don't care about any of the terminal events.
|
||||||
|
//!
|
||||||
|
//! Step 6: Examine the terminal state and make assertions. You can use
|
||||||
|
//! `extract_text()` and `extract_cursor()` if you only care about the text.
|
||||||
|
|
||||||
|
use alacritty_terminal::{
|
||||||
|
event::{Event, EventListener, WindowSize},
|
||||||
|
grid::Indexed,
|
||||||
|
term::{test::TermSize, Config},
|
||||||
|
tty::{self, EventedReadWrite, Options, Pty, Shell},
|
||||||
|
vte::ansi::{Processor, StdSyncHandler},
|
||||||
|
Term,
|
||||||
|
};
|
||||||
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
io::{ErrorKind, Read, Write},
|
||||||
|
path::PathBuf,
|
||||||
|
sync::mpsc,
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct EventProxy(mpsc::Sender<Event>);
|
||||||
|
|
||||||
|
impl EventListener for EventProxy {
|
||||||
|
fn send_event(&self, event: Event) {
|
||||||
|
let _ = self.0.send(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a 24x80 terminal with default configurations. Returns the terminal
|
||||||
|
/// and a `mpsc::Receiver` that receives terminal events.
|
||||||
|
pub fn default_terminal() -> (Term<EventProxy>, mpsc::Receiver<Event>) {
|
||||||
|
let config = Config::default();
|
||||||
|
let size = TermSize {
|
||||||
|
screen_lines: 24,
|
||||||
|
columns: 80,
|
||||||
|
};
|
||||||
|
let (tx, rx) = mpsc::channel();
|
||||||
|
(Term::new(config, &size, EventProxy(tx)), rx)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a PTY and connect the slave end to a Nushell process, then wait for
|
||||||
|
/// Nushell to initialize. If `pwd` is None, the Nushell process will inherit
|
||||||
|
/// PWD from the current process.
|
||||||
|
pub fn pty_with_nushell(args: Vec<&str>, pwd: Option<PathBuf>) -> Pty {
|
||||||
|
let executable = crate::fs::executable_path().to_string_lossy().to_string();
|
||||||
|
let options = Options {
|
||||||
|
shell: Some(Shell::new(
|
||||||
|
executable,
|
||||||
|
args.iter().map(|s| s.to_string()).collect(),
|
||||||
|
)),
|
||||||
|
working_directory: pwd,
|
||||||
|
hold: false,
|
||||||
|
env: HashMap::new(),
|
||||||
|
};
|
||||||
|
let window_size = WindowSize {
|
||||||
|
num_lines: 24,
|
||||||
|
num_cols: 80,
|
||||||
|
cell_width: 0,
|
||||||
|
cell_height: 0,
|
||||||
|
};
|
||||||
|
let pty = tty::new(&options, window_size, 0).expect("creating a PTY should succeed");
|
||||||
|
|
||||||
|
// Wait for Nushell to initialize.
|
||||||
|
std::thread::sleep(Duration::from_millis(500));
|
||||||
|
|
||||||
|
pty
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reads from `pty` until no more data is available. Will periodically call
|
||||||
|
/// `event_handler` to handle terminal events.
|
||||||
|
pub fn read_to_end<T: EventListener>(
|
||||||
|
terminal: &mut Term<T>,
|
||||||
|
pty: &mut Pty,
|
||||||
|
events: &mut mpsc::Receiver<Event>,
|
||||||
|
mut event_handler: impl FnMut(&mut Term<T>, &mut Pty, Event),
|
||||||
|
) {
|
||||||
|
let mut parser: Processor<StdSyncHandler> = Processor::new();
|
||||||
|
loop {
|
||||||
|
// Read from the PTY.
|
||||||
|
let mut buf = [0; 512];
|
||||||
|
match pty.reader().read(&mut buf) {
|
||||||
|
Ok(n) => {
|
||||||
|
if n == 0 {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
// Update the terminal state.
|
||||||
|
for byte in &buf[..n] {
|
||||||
|
parser.advance(terminal, *byte);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle terminal events.
|
||||||
|
while let Ok(event) = events.try_recv() {
|
||||||
|
event_handler(terminal, pty, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Poll again after 100ms. The delay is necessary so that
|
||||||
|
// the child process can respond to any new data we might
|
||||||
|
// have sent in the event handler.
|
||||||
|
std::thread::sleep(Duration::from_millis(100));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
if let ErrorKind::Interrupted = err.kind() {
|
||||||
|
// retry
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An event handler that only responds to `Event::PtyWrite`. This is the
|
||||||
|
/// minimum amount of event handling you need to get Nushell working.
|
||||||
|
pub fn pty_write_handler<T: EventListener>(_terminal: &mut Term<T>, pty: &mut Pty, event: Event) {
|
||||||
|
if let Event::PtyWrite(text) = event {
|
||||||
|
pty.writer()
|
||||||
|
.write_all(text.as_bytes())
|
||||||
|
.expect("writing to PTY succeeds");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extracts the current cursor position.
|
||||||
|
pub fn extract_cursor<T>(terminal: &Term<T>) -> (usize, usize) {
|
||||||
|
let cursor = terminal.grid().cursor.point;
|
||||||
|
(cursor.line.0 as usize, cursor.column.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extracts all visible text, ignoring text styles.
|
||||||
|
pub fn extract_text<T>(terminal: &Term<T>) -> Vec<String> {
|
||||||
|
let mut text: Vec<String> = vec![];
|
||||||
|
for Indexed { point, cell } in terminal.grid().display_iter() {
|
||||||
|
if point.column == 0 {
|
||||||
|
text.push(String::new());
|
||||||
|
}
|
||||||
|
text.last_mut()
|
||||||
|
.expect("terminal grid start at column 0")
|
||||||
|
.push(cell.c);
|
||||||
|
}
|
||||||
|
text
|
||||||
|
}
|
|
@ -14,3 +14,4 @@ mod plugins;
|
||||||
mod repl;
|
mod repl;
|
||||||
mod scope;
|
mod scope;
|
||||||
mod shell;
|
mod shell;
|
||||||
|
mod terminal;
|
||||||
|
|
77
tests/terminal/mod.rs
Normal file
77
tests/terminal/mod.rs
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
use alacritty_terminal::tty::EventedReadWrite;
|
||||||
|
use nu_test_support::terminal::{
|
||||||
|
default_terminal, extract_cursor, extract_text, pty_with_nushell, pty_write_handler,
|
||||||
|
read_to_end,
|
||||||
|
};
|
||||||
|
use std::io::Write;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn auto_cd_works() {
|
||||||
|
// Setup a directory with a sub-directory in it.
|
||||||
|
let cwd = tempfile::tempdir().unwrap();
|
||||||
|
std::fs::create_dir(cwd.path().join("foo")).unwrap();
|
||||||
|
|
||||||
|
// Create the PTY and the terminal.
|
||||||
|
let mut pty = pty_with_nushell(vec!["--no-config-file"], Some(cwd.path().to_path_buf()));
|
||||||
|
let (mut term, mut events) = default_terminal();
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
pty.writer().write_all(b".\\foo\r").unwrap();
|
||||||
|
#[cfg(unix)]
|
||||||
|
pty.writer().write_all(b"./foo\r").unwrap();
|
||||||
|
|
||||||
|
pty.writer().write_all(b"pwd\r").unwrap();
|
||||||
|
|
||||||
|
// Read the response from Nushell.
|
||||||
|
read_to_end(&mut term, &mut pty, &mut events, pty_write_handler);
|
||||||
|
|
||||||
|
// Examine the terminal state.
|
||||||
|
let (row, _col) = extract_cursor(&term);
|
||||||
|
let text = extract_text(&term);
|
||||||
|
assert!(text[row - 1].contains("foo"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn command_hints_are_pwd_aware() {
|
||||||
|
// PWD-aware command hints require setting history file format to "sqlite".
|
||||||
|
let nu_config = tempfile::NamedTempFile::new().unwrap();
|
||||||
|
let nu_config_string = nu_config.path().to_string_lossy().to_string();
|
||||||
|
std::fs::write(
|
||||||
|
&nu_config,
|
||||||
|
"$env.config = { history: { file_format: 'sqlite' } }",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Setup a directory with two sub-directories in it.
|
||||||
|
let cwd = tempfile::tempdir().unwrap();
|
||||||
|
std::fs::create_dir(cwd.path().join("foo")).unwrap();
|
||||||
|
std::fs::create_dir(cwd.path().join("bar")).unwrap();
|
||||||
|
|
||||||
|
// Create the PTY and the terminal.
|
||||||
|
let mut pty = pty_with_nushell(
|
||||||
|
vec![
|
||||||
|
"--config",
|
||||||
|
&nu_config_string,
|
||||||
|
"--env-config",
|
||||||
|
&nu_config_string,
|
||||||
|
],
|
||||||
|
Some(cwd.path().to_path_buf()),
|
||||||
|
);
|
||||||
|
let (mut term, mut events) = default_terminal();
|
||||||
|
|
||||||
|
pty.writer().write_all(b"cd foo\r").unwrap();
|
||||||
|
pty.writer().write_all(b"print 'FOO'\r").unwrap();
|
||||||
|
pty.writer().write_all(b"cd ../bar\r").unwrap();
|
||||||
|
pty.writer().write_all(b"print 'BAR'\r").unwrap();
|
||||||
|
pty.writer().write_all(b"cd ../foo\r").unwrap();
|
||||||
|
// Type "print", then press the right arrow, then press Enter.
|
||||||
|
pty.writer().write_all(b"print\x1b[C\r").unwrap();
|
||||||
|
|
||||||
|
// Read the response from Nushell.
|
||||||
|
read_to_end(&mut term, &mut pty, &mut events, pty_write_handler);
|
||||||
|
|
||||||
|
// Examine the terminal state.
|
||||||
|
let (row, _col) = extract_cursor(&term);
|
||||||
|
let text = extract_text(&term);
|
||||||
|
assert!(text[row - 2].contains("print 'FOO'"));
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user