#[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
}