use std::io::Write;
use anyhow::Context;
use console::Term;
pub fn get_terminal_size() -> anyhow::Result<(u16, u16)> {
let term = Term::stdout();
term.size_checked().context("Failed to get terminal size")
}
pub fn set_scrolling_region(top: u16, bottom: u16) -> anyhow::Result<()> {
let mut stderr = std::io::stderr();
write!(stderr, "\x1b[{};{}r", top, bottom).context("Failed to set scrolling region")?;
stderr.flush().context("Failed to flush stdout")?;
Ok(())
}
pub fn reset_scrolling_region() -> anyhow::Result<()> {
let mut stderr = std::io::stderr();
write!(stderr, "\x1b[r").context("Failed to reset scrolling region")?;
stderr.flush().context("Failed to flush stdout")?;
Ok(())
}
pub fn clear_scrolling_region() -> anyhow::Result<()> {
let mut stderr = std::io::stderr();
write!(stderr, "\x1b[J").context("Failed to clear scrolling region")?;
stderr.flush().context("Failed to flush stdout")?;
Ok(())
}
pub fn move_cursor_to_line(line: u16) -> anyhow::Result<()> {
let mut stderr = std::io::stderr();
write!(stderr, "\x1b[{};1H", line).context("Failed to move cursor to line")?;
stderr.flush().context("Failed to flush stdout")?;
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_get_terminal_size() {
let _size = get_terminal_size();
}
#[test]
fn test_set_scrolling_region() {
let _ = set_scrolling_region(1u16, 10u16);
}
#[test]
fn test_set_scrolling_region_single_line() {
let _ = set_scrolling_region(5u16, 5u16);
}
#[test]
fn test_set_scrolling_region_large() {
let _ = set_scrolling_region(1u16, 1000u16);
}
#[test]
fn test_reset_scrolling_region() {
let _ = reset_scrolling_region();
}
#[test]
fn test_clear_scrolling_region() {
let _ = clear_scrolling_region();
}
#[test]
fn test_move_cursor_to_line() {
let _ = move_cursor_to_line(5u16);
}
#[test]
fn test_move_cursor_to_line_first() {
let _ = move_cursor_to_line(1u16);
}
#[test]
fn test_move_cursor_to_line_large() {
let _ = move_cursor_to_line(1000u16);
}
#[test]
fn test_scrolling_region_sequence() {
let _ = set_scrolling_region(1u16, 5u16);
let _ = move_cursor_to_line(1u16);
let _ = clear_scrolling_region();
let _ = reset_scrolling_region();
}
#[test]
fn test_scrolling_region_typical_usage() {
let term_rows = 24u16;
let scroll_lines = 5u16;
let region_top = term_rows - scroll_lines + 1;
let _ = set_scrolling_region(region_top, term_rows);
let _ = move_cursor_to_line(region_top);
let _ = clear_scrolling_region();
let _ = reset_scrolling_region();
}
#[test]
fn test_scrolling_region_full_terminal() {
let _ = set_scrolling_region(1u16, 24u16);
let _ = reset_scrolling_region();
}
#[test]
fn test_multiple_cursor_moves() {
for line in 1u16..=10 {
let _ = move_cursor_to_line(line);
}
}
#[test]
fn test_set_and_reset_multiple_times() {
for idx in 1u16..=5 {
let _ = set_scrolling_region(idx, idx + 10);
let _ = reset_scrolling_region();
}
}
}