crossterm
crossterm copied to clipboard
cursor::SavePosition / cursor::RestorePosition break with newlines
Describe the bug cursor::SavePosition seems to only save the position on a line and doesnt work with newline.
To Reproduce Working Code to overwrite printed value:
use crossterm::{cursor, terminal, ExecutableCommand, QueueableCommand};
fn main() {
let mut stdout = stdout();
stdout.execute(cursor::Hide).unwrap();
for year in 1950..2030 {
stdout.queue(cursor::SavePosition).unwrap();
stdout
.write_all(format!("{year}").as_bytes()
)
.unwrap();
stdout.flush().unwrap();
thread::sleep(time::Duration::from_millis(200));
stdout.queue(cursor::RestorePosition).unwrap();
stdout
.queue(terminal::Clear(terminal::ClearType::FromCursorDown))
.unwrap();
}
stdout.execute(cursor::Show).unwrap();
println!("Done!");
}
Adding a single newline breaks the code:
use crossterm::{cursor, terminal, ExecutableCommand, QueueableCommand};
fn main() {
let mut stdout = stdout();
stdout.execute(cursor::Hide).unwrap();
for year in 1950..2030 {
stdout.queue(cursor::SavePosition).unwrap();
stdout
.write_all(format!("{year}\n").as_bytes()
)
.unwrap();
stdout.flush().unwrap();
thread::sleep(time::Duration::from_millis(200));
stdout.queue(cursor::RestorePosition).unwrap();
stdout
.queue(terminal::Clear(terminal::ClearType::FromCursorDown))
.unwrap();
}
stdout.execute(cursor::Show).unwrap();
println!("Done!");
}
Expected behavior Restore the position of the cursor.
OS Ubuntu 22.04
Terminal/Console gnome-terminal
I have a guess that save restore cursor position requires raw mode to be enabled to work 100% of the time. Otherwise sometimes they fail.
Tried out raw mode and it doesn't seem to fix my issue. Just seems like SavePosition and RestorePosition don't work when there are newlines. I've resorted to just counting the newlines and using MoveUp + ClearType::FromCursorDown(My intention is to print some lines, then overwrite them in a loop).
It might also be due to scrolling effect, if the terminal size is small it can mess the math see https://unix.stackexchange.com/questions/278884/save-cursor-position-and-restore-it-in-terminal/278888#278888 for why scrolling breaks this.
Either way crossterm just wraps the ansi sequences https://github.com/crossterm-rs/crossterm/blob/9a50fd2ce2701bb15f58722495024937143ad34d/src/cursor.rs#L272 so this is can't be considered a crossterm bug.
Possibly work around this issue by fetching the terminal position at the loop start, and doing a goto after the print. Like @sigmaSd says crossterm doesn't do much else than just writing an ANSI code.
I had the same bug, found out that my terminal emulator (st) did not implement all of the VT100 escape sequences, after testing. The code in other terminals (xterm) works just fine.
I've resorted to just counting the newlines and using MoveUp + ClearType::FromCursorDown(My intention is to print some lines, then overwrite them in a loop).
I've just encountered the same issue and used this workaround (as well as printing \r
to clear the first line) and it works well. :clap: thanks @wmmc88 !