tastty-core 0.1.0

Sans-IO core of the tastty terminal session library: VT parser, screen buffer, and byte encoders.
use super::*;

#[test]
fn visible_to_absolute_initial() {
    let screen = Screen::new(crate::grid::Size { rows: 5, cols: 10 }, 100);
    let abs = screen.visible_to_absolute(Position { row: 0, col: 0 });
    assert_eq!(
        abs,
        Some(AbsolutePosition { row: 0, col: 0 }),
        "with no scrollback consumed, visible (0,0) must map to absolute (0,0)",
    );
    let abs = screen.visible_to_absolute(Position { row: 4, col: 9 });
    assert_eq!(
        abs,
        Some(AbsolutePosition { row: 4, col: 9 }),
        "bottom-right visible cell must map to the matching absolute position",
    );
    assert_eq!(
        screen.visible_to_absolute(Position { row: 5, col: 0 }),
        None,
        "row past the visible region must yield None, not clamp",
    );
    assert_eq!(
        screen.visible_to_absolute(Position { row: 0, col: 10 }),
        None,
        "col past the visible region must yield None, not clamp",
    );
}

#[test]
fn absolute_to_visible_initial() {
    let screen = Screen::new(crate::grid::Size { rows: 5, cols: 10 }, 100);
    let pos = screen.absolute_to_visible(AbsolutePosition { row: 0, col: 0 });
    assert_eq!(pos, Some(Position { row: 0, col: 0 }));
    let pos = screen.absolute_to_visible(AbsolutePosition { row: 4, col: 9 });
    assert_eq!(pos, Some(Position { row: 4, col: 9 }));
    // out of visible range
    assert_eq!(
        screen.absolute_to_visible(AbsolutePosition { row: 5, col: 0 }),
        None,
    );
}

#[test]
fn absolute_position_stable_across_scrollback_push() {
    // Write enough rows to push some into scrollback. The abs row
    // captured before the scroll must still resolve to the same
    // content after the scroll.
    let mut parser = crate::Parser::new(TerminalSize { rows: 3, cols: 10 }, 100);
    parser.process(b"line0\r\n");
    // Capture abs position of "line0" while it is still on row 0.
    let abs = parser
        .screen()
        .visible_to_absolute(Position { row: 0, col: 0 })
        .expect("row 0 visible");
    assert_eq!(abs.row, 0);
    // Push enough lines to scroll "line0" into scrollback.
    for i in 1..6 {
        parser.process(format!("line{i}\r\n").as_bytes());
    }
    // "line0" is no longer visible in the live region, but it is in
    // scrollback. Its abs position is unchanged.
    let still_abs = parser
        .screen()
        .visible_to_absolute(Position { row: 0, col: 0 })
        .expect("row 0 still has content");
    assert_ne!(still_abs.row, abs.row, "viewport top has advanced");
    // The original abs position no longer maps to a visible row.
    assert_eq!(
        parser.screen().absolute_to_visible(abs),
        None,
        "an abs row that has scrolled into history must no longer resolve to a visible row",
    );
}