magi-code 0.77.1

Repository-aware CLI coding agent for terminal work
Documentation
use super::*;

#[test]
fn transcript_timestamps_render_inline_and_stay_out_of_copy() {
    let local_timestamp =
        chrono::TimeZone::with_ymd_and_hms(&chrono::Local, 2024, 1, 2, 3, 4, 5).unwrap();
    let timestamp = local_timestamp.with_timezone(&chrono::Utc);
    let mut state = MissionControlState::default();
    state.apply_output_event(&OutputEvent::AssistantComplete {
        text: "answer".into(),
    });
    state.set_transcript_timestamp_for_test(0, local_timestamp);

    let lines = visual_lines(&state, 24);
    let header = line_text(&lines[1].line);
    assert_eq!(UnicodeWidthStr::width(header.as_str()), 24);
    assert!(header.ends_with(" 03:04:05"), "{header:?}");
    assert_eq!(lines[1].copy_text, "Agent");
    assert!(!state.transcript_visual_text().contains("03:04:05"));

    let mut user = MissionControlState::default();
    user.apply_output_event_at(
        &OutputEvent::UserPrompt {
            text: "hello".into(),
        },
        Some(timestamp),
    );
    let user_lines = visual_lines(&user, 26);
    assert_eq!(line_text(&user_lines[1].line), "  03:04:05 | User: hello  ");
    assert_eq!(user_lines[1].copy_text, "User: hello");
    assert!(user_lines[1].copyable);
    assert!(!user_lines[0].copyable);
    assert!(!user_lines[2].copyable);
    assert_eq!(user_lines[0].copy_text, "");
    assert_eq!(user_lines[2].copy_text, "");
    assert!(!user.transcript_visual_text().contains("03:04:05"));
    assert!(
        user_lines[1]
            .line
            .spans
            .iter()
            .all(|span| { span.style.bg == Some(MissionControlTheme::default().surface_panel()) })
    );

    let timestamp_span = user_lines[1]
        .line
        .spans
        .iter()
        .find(|span| span.content.as_ref() == "03:04:05")
        .expect("inline timestamp span");
    assert_eq!(
        timestamp_span.style.fg,
        Some(MissionControlTheme::default().text_muted())
    );
    assert!(timestamp_span.style.add_modifier.contains(Modifier::DIM));
    let user_start = line_text(&user_lines[1].line)
        .find("User: ")
        .expect("user label");
    let timestamp_start = line_text(&user_lines[1].line)
        .find("03:04:05")
        .expect("timestamp");
    for column in timestamp_start..user_start {
        let start = text_position_for_visual_cell(&user, 1, column, 26).expect("prefix start");
        let end = text_position_for_visual_cell(&user, 1, column + 1, 26).expect("prefix end");
        assert_eq!(start.byte, end.byte, "column={column}");
    }
    let start = text_position_for_visual_cell(&user, 1, user_start, 26).expect("user start");
    let end = text_position_for_visual_cell(&user, 1, 26, 26).expect("user end");
    user.start_selection(crate::tui::layout::TuiPane::Transcript, start);
    user.update_selection(crate::tui::layout::TuiPane::Transcript, end);
    assert_eq!(
        user.finish_selection(crate::tui::layout::TuiPane::Transcript, 26),
        Some("User: hello".to_string())
    );
}

#[test]
fn user_prompt_without_timestamp_has_no_dangling_separator() {
    let mut state = MissionControlState::default();
    state.transcript.push_back("you: hello".to_string());

    let lines = visual_lines(&state, 24);
    assert_eq!(lines[1].copy_text, "User: hello");
    assert_eq!(line_text(&lines[1].line), "  User: hello           ");
    assert!(!line_text(&lines[1].line).contains(" | "));
    assert_eq!(visual_text_for_width(&state, 24), "User: hello");
}

#[test]
fn user_prompt_multiline_and_empty_copy_keep_logical_newlines() {
    let mut state = MissionControlState::default();
    state
        .transcript
        .push_back("you: first\n\nthird".to_string());
    assert_eq!(visual_text_for_width(&state, 24), "User: first\n\nthird");

    let mut empty = MissionControlState::default();
    empty.transcript.push_back("you: ".to_string());
    let lines = visual_lines(&empty, 24);
    assert_eq!(lines[1].copy_text, "User: ");
    assert_eq!(visual_text_for_width(&empty, 24), "User: ");
}

#[test]
fn user_prompt_inline_prefix_wraps_and_keeps_tiny_rows_full_width() {
    let timestamp = chrono::TimeZone::with_ymd_and_hms(&chrono::Utc, 2024, 1, 2, 3, 4, 5).unwrap();
    let mut state = MissionControlState::default();
    state.apply_output_event_at(
        &OutputEvent::UserPrompt {
            text: "abc界".into(),
        },
        Some(timestamp),
    );

    for width in [1, 2, 3, 12, 24] {
        let lines = visual_lines(&state, width);
        assert!(
            lines.iter().all(|line| {
                UnicodeWidthStr::width(line_text(&line.line).as_str()) == usize::from(width)
            }),
            "width={width}: {lines:?}"
        );
        assert_eq!(
            visual_text_for_width(&state, width),
            "User: abc界",
            "width={width}"
        );
        assert!(lines.iter().all(|line| visual_line_rows(line, width) == 1));
    }
}

#[test]
fn transcript_timestamp_headers_fit_narrow_widths_without_wrapping() {
    let local_timestamp =
        chrono::TimeZone::with_ymd_and_hms(&chrono::Local, 2024, 1, 2, 3, 4, 5).unwrap();
    let timestamp = local_timestamp.with_timezone(&chrono::Utc);
    let mut state = MissionControlState::default();
    state.apply_output_event_at(
        &OutputEvent::AssistantComplete {
            text: "answer".into(),
        },
        Some(timestamp),
    );

    for width in 1..=12 {
        let lines = visual_lines(&state, width);
        assert!(
            lines[..3]
                .iter()
                .all(|line| visual_line_rows(line, width) == 1),
            "width={width}"
        );
        assert!(lines.iter().all(|line| {
            UnicodeWidthStr::width(line_text(&line.line).as_str()) == usize::from(width)
        }));
    }
}

#[test]
fn transcript_timestamp_copy_mapping_collapses_tiny_timestamp_headers() {
    let mut state = timestamped_long_header_state();
    for width in 1..=8 {
        let lines = visual_lines(&state, width);
        assert!(
            lines[1].copy_text.is_empty(),
            "width={width}: {:?}",
            lines[1]
        );
        for column in 0..usize::from(width) {
            let start = text_position_for_visual_cell(&state, 1, column, width)
                .expect("timestamp cell start");
            let end = text_position_for_visual_cell(&state, 1, column + 1, width)
                .expect("timestamp cell end");
            assert_eq!(start.byte, end.byte, "width={width} column={column}");
            state.start_selection(crate::tui::layout::TuiPane::Transcript, start);
            state.update_selection(crate::tui::layout::TuiPane::Transcript, end);
            assert_eq!(
                state.finish_selection(crate::tui::layout::TuiPane::Transcript, width),
                None,
                "width={width} column={column}"
            );
        }
    }
}

#[test]
fn transcript_timestamp_copy_mapping_collapses_trailing_region_and_hidden_title() {
    let mut state = timestamped_long_header_state();
    let width = 24;
    let lines = visual_lines(&state, width);
    let header_copy = lines[1].copy_text.clone();
    assert_eq!(header_copy, "✓ Tool • very-");
    assert!(!header_copy.contains("hidden-tail"));
    let rendered = line_text(&lines[1].line);
    assert!(rendered.ends_with(" 03:04:05"), "{rendered:?}");
    let timestamp_start = usize::from(width) - "03:04:05".len();

    for start_column in [timestamp_start - 1, timestamp_start] {
        let start = text_position_for_visual_cell(&state, 1, start_column, width)
            .expect("trailing-region start");
        let end = text_position_for_visual_cell(&state, 1, usize::from(width), width)
            .expect("timestamp end");
        assert_eq!(start.byte, end.byte, "start_column={start_column}");
        state.start_selection(crate::tui::layout::TuiPane::Transcript, start);
        state.update_selection(crate::tui::layout::TuiPane::Transcript, end);
        assert_eq!(
            state.finish_selection(crate::tui::layout::TuiPane::Transcript, width),
            None,
            "start_column={start_column}"
        );
    }

    let start = text_position_for_visual_cell(&state, 1, 1, width).expect("header start");
    let end =
        text_position_for_visual_cell(&state, 1, usize::from(width), width).expect("header end");
    state.start_selection(crate::tui::layout::TuiPane::Transcript, start);
    state.update_selection(crate::tui::layout::TuiPane::Transcript, end);
    let copied = state
        .finish_selection(crate::tui::layout::TuiPane::Transcript, width)
        .expect("visible header copy");
    assert_eq!(copied, header_copy);
    assert!(!copied.contains("hidden-tail"));
}