use icons::Icon;
use super::*;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Chip {
pub range: Range<usize>,
pub glyph: Icon,
pub title: SharedString,
}
const SLOT: &str = "\u{2003}";
pub(super) struct Chipped {
pub text: SharedString,
pub shown: Shown,
pub slots: Vec<(Range<usize>, Icon)>,
pub titles: Vec<Range<usize>>,
}
impl Chipped {
pub fn plain(text: SharedString) -> Self {
Self {
text,
shown: Shown::default(),
slots: Vec::new(),
titles: Vec::new(),
}
}
}
pub(super) fn chipped(content: &SharedString, chips: &[Chip]) -> Chipped {
if chips.is_empty() {
return Chipped::plain(content.clone());
}
let mut text = String::with_capacity(content.len());
let (mut slots, mut titles, mut pairs) = (Vec::new(), Vec::new(), Vec::new());
let mut at = 0;
for chip in chips {
let range = &chip.range;
if range.start < at
|| range.is_empty()
|| range.end > content.len()
|| !content.is_char_boundary(range.start)
|| !content.is_char_boundary(range.end)
{
continue;
}
text.push_str(&content[at..range.start]);
let from = text.len();
text.push_str(SLOT);
slots.push((from..text.len(), chip.glyph.clone()));
text.push(' ');
let title = text.len();
text.push_str(&chip.title.replace('\n', " "));
titles.push(title..text.len());
pairs.push((range.clone(), from..text.len()));
at = range.end;
}
text.push_str(&content[at..]);
Chipped {
text: text.into(),
shown: Shown::new(pairs),
slots,
titles,
}
}
pub(super) fn follow(edit: Edit, range: &Range<usize>) -> Option<Range<usize>> {
if edit.start < range.end && range.start < edit.old_end {
return None;
}
edit.map(range.clone())
}
pub(super) fn outside(chips: &[Chip], offset: usize, back: bool) -> usize {
match chips
.iter()
.find(|chip| chip.range.start < offset && offset < chip.range.end)
{
Some(chip) if back => chip.range.start,
Some(chip) => chip.range.end,
None => offset,
}
}
pub(super) fn widen(chips: &[Chip], range: Range<usize>) -> Range<usize> {
outside(chips, range.start, true)..outside(chips, range.end, false)
}