magi-code 0.77.1

Repository-aware CLI coding agent for terminal work
Documentation
#[cfg(test)]
use super::CARD_LAYOUT_MIN_WIDTH;
use super::visual_lines::{TranscriptVisualLine, visit_visual_lines};
use crate::tui::{state::MissionControlState, transcript};

fn copy_position_for_visual_cell(
    line: &TranscriptVisualLine,
    row: usize,
    column: usize,
    wrap_width: u16,
) -> Option<crate::tui::selection::TextPosition> {
    let column_offset = usize::from(line.visual_copy_column_offset);
    if row == 0 && !line.visual_copy_byte_boundaries.is_empty() {
        let relative_column = column.saturating_sub(column_offset);
        let byte = line
            .visual_copy_byte_boundaries
            .get(relative_column)
            .copied()
            .or_else(|| line.visual_copy_byte_boundaries.last().copied())?
            .min(line.copy_text.len());
        return Some(crate::tui::selection::TextPosition::new(byte, row, column));
    }
    let position = transcript::text_position_for_visual_cell_with_leading_columns(
        &line.copy_text,
        column_offset,
        row,
        column,
        wrap_width,
    )?;
    Some(crate::tui::selection::TextPosition::new(
        position.byte.min(line.copy_text.len()),
        row,
        column,
    ))
}

pub(crate) fn text_position_for_visual_cell(
    state: &MissionControlState,
    visual_row: usize,
    column: usize,
    wrap_width: u16,
) -> Option<crate::tui::selection::TextPosition> {
    let mut current_row = 0usize;
    let mut byte_base = 0usize;
    let mut copy_line_seen = false;
    visit_visual_lines(state, wrap_width, |line, rows| {
        if line.copyable && !line.copy_continuation && copy_line_seen {
            byte_base = byte_base.saturating_add(1);
        }
        if line.copyable {
            copy_line_seen = true;
        }

        let next_row = current_row.saturating_add(rows);
        if visual_row < next_row {
            if !line.copyable {
                return Some(Some(crate::tui::selection::TextPosition::new(
                    byte_base, visual_row, column,
                )));
            }
            let row_in_line = visual_row.saturating_sub(current_row);
            return Some(
                copy_position_for_visual_cell(line, row_in_line, column, wrap_width).map(
                    |position| {
                        crate::tui::selection::TextPosition::new(
                            byte_base.saturating_add(position.byte),
                            visual_row,
                            column,
                        )
                    },
                ),
            );
        }
        current_row = next_row;
        if line.copyable {
            byte_base = byte_base.saturating_add(line.copy_text.len());
        }
        None
    })
    .flatten()
}

#[cfg(test)]
pub(crate) fn visual_text(state: &MissionControlState) -> String {
    visual_text_for_width(state, CARD_LAYOUT_MIN_WIDTH)
}

pub(crate) fn visual_text_for_width(state: &MissionControlState, wrap_width: u16) -> String {
    let mut text = String::new();
    let mut copy_line_seen = false;
    visit_visual_lines(state, wrap_width, |line, _| {
        if !line.copyable {
            return None::<()>;
        }
        if !line.copy_continuation {
            if copy_line_seen {
                text.push('\n');
            }
            copy_line_seen = true;
        }
        text.push_str(&line.copy_text);
        None
    });
    text
}