Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cursor::position() fails when piping stdout #919

Open
jonathanharg opened this issue Aug 24, 2024 · 0 comments · May be fixed by #957
Open

cursor::position() fails when piping stdout #919

jonathanharg opened this issue Aug 24, 2024 · 0 comments · May be fixed by #957

Comments

@jonathanharg
Copy link

Describe the bug
A The cursor position could not be read within a normal duration error occurs when trying to call cursor::position() when stdout is being piped (to a file for example).

Likely related to #828.

To Reproduce

fn main() {
    let (x, y) = crossterm::cursor::position().unwrap();
    println!("Cursor position is ({x}, {y})");
}
 ❱ cargo run > output
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.01s
     Running `target/debug/repro`
thread 'main' panicked at src/main.rs:2:48:
called `Result::unwrap()` on an `Err` value: Custom { kind: Other, error: "The cursor position could not be read within a normal duration" }
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 ❱ cat output
 ❱ [8;1R

Expected behavior

 ❱ cargo run > output
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.01s
     Running `target/debug/repro`
 ❱ cat output
Cursor position is (0, 3)

Other functions such as terminal::size() work when piping stdout.

A simple change to use /dev/tty instead of stdout doesn't seem to fix the problem.

diff --git a/src/cursor/sys/unix.rs b/src/cursor/sys/unix.rs
index 4734212..92e10e6 100644
--- a/src/cursor/sys/unix.rs
+++ b/src/cursor/sys/unix.rs
@@ -31,9 +31,17 @@ fn read_position() -> io::Result<(u16, u16)> {

 fn read_position_raw() -> io::Result<(u16, u16)> {
     // Use `ESC [ 6 n` to and retrieve the cursor position.
-    let mut stdout = io::stdout();
-    stdout.write_all(b"\x1B[6n")?;
-    stdout.flush()?;
+    const QUERY: &[u8] = b"\x1B[6n";
+
+    let result = std::fs::File::open("/dev/tty").and_then(|mut file| {
+        file.write_all(QUERY)?;
+        file.flush()
+    });
+    if result.is_err() {
+        let mut stdout = io::stdout();
+        stdout.write_all(QUERY)?;
+        stdout.flush()?;
+    }

     loop {
         match poll_internal(Some(Duration::from_millis(2000)), &CursorPositionFilter) {

OS

  • macOS Sonoma 14.5

Terminal/Console

  • WezTerm
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant