use std::borrow::Cow;
use ratatui::text::Line;
use unicode_segmentation::UnicodeSegmentation;
use unicode_width::UnicodeWidthStr;
pub trait PartialLine<'a> {
fn substring(self, start: usize, len: u16) -> Line<'a>;
}
impl<'a> PartialLine<'a> for Line<'a> {
fn substring(mut self, start: usize, len: u16) -> Self {
let len = len as usize;
let end = start + len;
let end = if end > self.width() {
self.width()
} else {
end
};
let mut cur = 0;
let mut discard_until = 0;
let mut discard_after = self.spans.len();
for (i, span) in self.spans.iter_mut().enumerate() {
let span_width = span.width();
if cur + span_width < start {
cur += span_width;
discard_until = i + 1;
continue;
}
if cur >= end {
discard_after = i;
break;
}
let start = start.saturating_sub(cur);
let end = if cur + span_width > end {
end - cur
} else {
span_width
};
let mut start_index = 0;
let mut end_index = span.content.len(); let mut cum = 0; for (idx, grapheme) in span.content.grapheme_indices(true) {
let grapheme_width = grapheme.width();
if cum + grapheme_width < start {
start_index = idx + grapheme.len();
cum += grapheme_width;
} else if start != 0 {
start_index = idx + grapheme.len();
break;
}
}
cum = span_width;
for (idx, grapheme) in span.content.grapheme_indices(true).rev() {
let grapheme_width = grapheme.width();
if cum - grapheme_width >= end {
end_index = idx;
cum -= grapheme_width;
} else {
break;
}
}
match span.content {
Cow::Borrowed(s) => {
span.content = Cow::Borrowed(&s[start_index..end_index]);
}
Cow::Owned(ref mut s) => {
s.drain(end_index..);
s.drain(..start_index);
}
}
cur += span_width;
}
self.spans.drain(discard_after..);
self.spans.drain(..discard_until);
self
}
}