use super::*;
pub(super) fn annotate_copy_byte_ranges(lines: &mut [TranscriptVisualLine]) {
let mut byte_base = 0;
let mut copy_line_seen = false;
for line in lines {
line.copy_byte_range = advance_copy_byte_range(line, &mut byte_base, &mut copy_line_seen);
}
}
pub(super) fn advance_copy_byte_range(
line: &TranscriptVisualLine,
byte_base: &mut usize,
copy_line_seen: &mut bool,
) -> Option<(usize, usize)> {
if !line.copyable {
return None;
}
if !line.copy_continuation && *copy_line_seen {
*byte_base = byte_base.saturating_add(1);
}
*copy_line_seen = true;
let start = *byte_base;
*byte_base = byte_base.saturating_add(line.copy_text.len());
Some((start, *byte_base))
}
pub(super) fn body_line_copy_offset(width: u16, extra: u16) -> u16 {
let (left, _) = horizontal_padding(width);
display_width_to_u16(left.saturating_add(usize::from(extra)))
}
pub(super) fn copy_byte_boundaries_for_span(display_text: &str, copy_text: &str) -> Vec<usize> {
if display_text != copy_text {
let display_width = UnicodeWidthStr::width(display_text);
let mut boundaries = vec![0; display_width.saturating_add(1)];
if let Some(end) = boundaries.last_mut() {
*end = copy_text.len();
}
return boundaries;
}
let mut boundaries = vec![0];
let mut copy_byte = 0usize;
let mut saw_positive_width = false;
for grapheme in display_text.graphemes(true) {
let width = UnicodeWidthStr::width(grapheme);
if width == 0 {
copy_byte = copy_byte.saturating_add(grapheme.len());
if saw_positive_width && let Some(end) = boundaries.last_mut() {
*end = copy_byte;
}
continue;
}
let grapheme_start = if saw_positive_width {
copy_byte
} else {
boundaries.last().copied().unwrap_or_default()
};
for _ in 1..width {
boundaries.push(grapheme_start);
}
copy_byte = copy_byte.saturating_add(grapheme.len());
boundaries.push(copy_byte);
saw_positive_width = true;
}
if !saw_positive_width && let Some(end) = boundaries.last_mut() {
*end = copy_byte;
}
boundaries
}
pub(super) fn append_copy_byte_boundaries(
boundaries: &mut Vec<usize>,
span_boundaries: &[usize],
copy_byte_base: usize,
) {
let Some((first, rest)) = span_boundaries.split_first() else {
return;
};
let first = copy_byte_base.saturating_add(*first);
if let Some(last) = boundaries.last_mut() {
*last = first;
} else {
boundaries.push(first);
}
boundaries.extend(
rest.iter()
.map(|boundary| copy_byte_base.saturating_add(*boundary)),
);
}