use unicode_segmentation::UnicodeSegmentation;
use unicode_width::UnicodeWidthStr;
use crate::input::{codepoint_to_byte, widths};
#[cfg(test)]
mod tests;
pub(crate) struct Line<'a> {
pub before: &'a str,
pub cursor: &'a str,
pub after: &'a str,
pad: usize,
}
impl Line<'_> {
pub fn padding(&self) -> String {
" ".repeat(self.pad)
}
}
pub(crate) fn layout(value: &str, cursor: usize, width: u16) -> Line<'_> {
let width = width.max(1) as usize;
let (head, tail) = value.split_at(codepoint_to_byte(value, cursor));
let room = (width - 1).saturating_sub(widths(tail).sum());
let (cursor, tail) = match tail.graphemes(true).next() {
Some(g) => (g, &tail[g.len()..]),
None => (" ", ""),
};
let (len, used) = fit(head.graphemes(true).rev(), room);
let before = &head[head.len() - len..];
let room = width.saturating_sub(used + cursor.width());
let (len, used) = fit(tail.graphemes(true), room);
Line {
before,
cursor,
after: &tail[..len],
pad: room - used,
}
}
fn fit<'a>(graphemes: impl Iterator<Item = &'a str>, room: usize) -> (usize, usize) {
let (mut len, mut used) = (0, 0);
for g in graphemes {
let w = g.width();
if used + w > room {
break;
}
len += g.len();
used += w;
}
(len, used)
}