1use icons::Icon;
4
5use super::*;
6
7#[derive(Clone, Debug, PartialEq, Eq)]
10pub struct Chip {
11 pub range: Range<usize>,
12 pub glyph: Icon,
13 pub title: SharedString,
14}
15
16const SLOT: &str = "\u{2003}";
19
20pub(super) struct Chipped {
23 pub text: SharedString,
24 pub shown: Shown,
25 pub slots: Vec<(Range<usize>, Icon)>,
27 pub titles: Vec<Range<usize>>,
29}
30
31impl Chipped {
32 pub fn plain(text: SharedString) -> Self {
34 Self {
35 text,
36 shown: Shown::default(),
37 slots: Vec::new(),
38 titles: Vec::new(),
39 }
40 }
41}
42
43pub(super) fn chipped(content: &SharedString, chips: &[Chip]) -> Chipped {
47 if chips.is_empty() {
48 return Chipped::plain(content.clone());
49 }
50 let mut text = String::with_capacity(content.len());
51 let (mut slots, mut titles, mut pairs) = (Vec::new(), Vec::new(), Vec::new());
52 let mut at = 0;
53 for chip in chips {
54 let range = &chip.range;
55 if range.start < at
56 || range.is_empty()
57 || range.end > content.len()
58 || !content.is_char_boundary(range.start)
59 || !content.is_char_boundary(range.end)
60 {
61 continue;
62 }
63 text.push_str(&content[at..range.start]);
64 let from = text.len();
65 text.push_str(SLOT);
66 slots.push((from..text.len(), chip.glyph.clone()));
67 text.push(' ');
68 let title = text.len();
69 text.push_str(&chip.title.replace('\n', " "));
71 titles.push(title..text.len());
72 pairs.push((range.clone(), from..text.len()));
73 at = range.end;
74 }
75 text.push_str(&content[at..]);
76 Chipped {
77 text: text.into(),
78 shown: Shown::new(pairs),
79 slots,
80 titles,
81 }
82}
83
84pub(super) fn follow(edit: Edit, range: &Range<usize>) -> Option<Range<usize>> {
87 if edit.start < range.end && range.start < edit.old_end {
88 return None;
89 }
90 edit.map(range.clone())
91}
92
93pub(super) fn outside(chips: &[Chip], offset: usize, back: bool) -> usize {
96 match chips
97 .iter()
98 .find(|chip| chip.range.start < offset && offset < chip.range.end)
99 {
100 Some(chip) if back => chip.range.start,
101 Some(chip) => chip.range.end,
102 None => offset,
103 }
104}
105
106pub(super) fn widen(chips: &[Chip], range: Range<usize>) -> Range<usize> {
108 outside(chips, range.start, true)..outside(chips, range.end, false)
109}