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 osc_8_hyperlink() {
    let mut parser = crate::Parser::new(TerminalSize { rows: 24, cols: 80 }, 0);
    // Set hyperlink, write text, close hyperlink, write more text
    process(
        &mut parser,
        b"\x1b]8;;https://example.com\x07link\x1b]8;;\x07plain",
    );
    let screen = parser.screen();
    // "link" cells should have the hyperlink
    assert_eq!(
        screen
            .cell(0, 0)
            .unwrap()
            .hyperlink()
            .map(|h| h.uri.as_ref()),
        Some("https://example.com")
    );
    assert_eq!(
        screen
            .cell(0, 3)
            .unwrap()
            .hyperlink()
            .map(|h| h.uri.as_ref()),
        Some("https://example.com")
    );
    assert_eq!(
        screen
            .cell(0, 0)
            .unwrap()
            .hyperlink()
            .and_then(|h| h.id.as_deref()),
        None
    );
    // "plain" cells should not
    assert!(screen.cell(0, 4).unwrap().hyperlink().is_none());
}

#[test]
fn osc_8_hyperlink_with_params() {
    let mut parser = crate::Parser::new(TerminalSize { rows: 24, cols: 80 }, 0);
    // OSC 8 with id parameter
    process(
        &mut parser,
        b"\x1b]8;id=foo;https://example.com\x07X\x1b]8;;\x07",
    );
    let screen = parser.screen();
    assert_eq!(
        screen
            .cell(0, 0)
            .unwrap()
            .hyperlink()
            .map(|h| h.uri.as_ref()),
        Some("https://example.com")
    );
}

#[test]
fn osc_8_hyperlink_st_terminator() {
    let mut parser = crate::Parser::new(TerminalSize { rows: 24, cols: 80 }, 0);
    process(
        &mut parser,
        b"\x1b]8;;https://example.com\x1b\\X\x1b]8;;\x1b\\",
    );
    let screen = parser.screen();
    assert_eq!(
        screen
            .cell(0, 0)
            .unwrap()
            .hyperlink()
            .map(|h| h.uri.as_ref()),
        Some("https://example.com")
    );
}

#[test]
fn osc_8_reset_by_ris() {
    let mut parser = crate::Parser::new(TerminalSize { rows: 24, cols: 80 }, 0);
    process(&mut parser, b"\x1b]8;;https://example.com\x07\x1bcX");
    let screen = parser.screen();
    // After RIS, hyperlink should be cleared
    assert!(screen.cell(0, 0).unwrap().hyperlink().is_none());
}

#[test]
fn osc_8_hyperlink_preserves_id() {
    let mut parser = crate::Parser::new(TerminalSize { rows: 24, cols: 80 }, 0);
    process(&mut parser, b"\x1b]8;id=foo;https://x\x07A\x1b]8;;\x07");
    let screen = parser.screen();
    let link = screen
        .cell(0, 0)
        .unwrap()
        .hyperlink()
        .expect("link present");
    assert_eq!(link.id.as_deref(), Some("foo"));
    assert_eq!(link.uri.as_ref(), "https://x");
}

#[test]
fn osc_8_adjacent_spans_with_different_ids_do_not_merge() {
    let mut parser = crate::Parser::new(TerminalSize { rows: 24, cols: 80 }, 0);
    process(
        &mut parser,
        b"\x1b]8;id=A;https://x\x07A\x1b]8;id=B;https://x\x07B\x1b]8;;\x07",
    );
    let screen = parser.screen();
    let link_a = screen.cell(0, 0).unwrap().hyperlink().expect("A link");
    let link_b = screen.cell(0, 1).unwrap().hyperlink().expect("B link");
    assert_eq!(link_a.uri, link_b.uri);
    assert_ne!(
        link_a, link_b,
        "adjacent OSC 8 spans with different ids must remain distinct hyperlinks",
    );
    assert_eq!(link_a.id.as_deref(), Some("A"));
    assert_eq!(link_b.id.as_deref(), Some("B"));
}

#[test]
fn osc_8_unknown_key_is_ignored() {
    let mut parser = crate::Parser::new(TerminalSize { rows: 24, cols: 80 }, 0);
    process(&mut parser, b"\x1b]8;foo=bar;https://x\x07A\x1b]8;;\x07");
    let screen = parser.screen();
    let link = screen
        .cell(0, 0)
        .unwrap()
        .hyperlink()
        .expect("link present");
    assert_eq!(link.id, None);
    assert_eq!(link.uri.as_ref(), "https://x");
}

#[test]
fn osc_8_id_with_colon_separator() {
    let mut parser = crate::Parser::new(TerminalSize { rows: 24, cols: 80 }, 0);
    process(
        &mut parser,
        b"\x1b]8;id=foo:bar=baz;https://x\x07A\x1b]8;;\x07",
    );
    let screen = parser.screen();
    let link = screen
        .cell(0, 0)
        .unwrap()
        .hyperlink()
        .expect("link present");
    assert_eq!(link.id.as_deref(), Some("foo"));
    assert_eq!(link.uri.as_ref(), "https://x");
}