1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
use {
crate::*,
minimad::{
Composite,
Compound,
},
unicode_width::UnicodeWidthStr,
};
/// Wrap Minimad compounds with their style and
/// termimad specific information
#[derive(Debug, Clone)]
pub struct FmtComposite<'s> {
pub kind: CompositeKind,
pub compounds: Vec<Compound<'s>>,
// cached visible length in cells, not counting margins, bullets, etc.
pub visible_length: usize,
pub spacing: Option<Spacing>,
}
impl<'s> FmtComposite<'s> {
pub fn new() -> Self {
FmtComposite {
kind: CompositeKind::Paragraph,
compounds: Vec::new(),
visible_length: 0,
spacing: None,
}
}
pub fn from(composite: Composite<'s>, skin: &MadSkin) -> Self {
let kind: CompositeKind = composite.style.into();
FmtComposite {
visible_length: skin.visible_composite_length(kind, &composite.compounds),
kind,
compounds: composite.compounds,
spacing: None,
}
}
pub fn from_compound(compound: Compound<'s>) -> Self {
let mut fc = Self::new();
fc.add_compound(compound);
fc
}
/// Return the number of characters (usually spaces) to insert both
/// sides of the composite
pub const fn completions(&self) -> (usize, usize) {
match &self.spacing {
Some(spacing) => spacing.completions_for(self.visible_length),
None => (0, 0),
}
}
/// Add a compound and modifies `visible_length` accordingly
pub fn add_compound(&mut self, compound: Compound<'s>) {
self.visible_length += compound.src.width();
self.compounds.push(compound);
}
/// Ensure the cached `visible_length` is correct.
///
/// It's normally not necessary to call it, but
/// this must be called if compounds are added,
/// removed or modified without using the `FmtComposite` API
pub fn recompute_width(&mut self, skin: &MadSkin) {
self.visible_length = skin.visible_composite_length(self.kind, &self.compounds);
}
/// try to ensure the composite's width doesn't exceed the given
/// width.
///
/// The alignment can be used, if necessary, to know which side it's better
/// to remove content (for example if the alignment is left then we remove at
/// right).
/// The fitter may remove a part in the core of the composite if it looks
/// good enough. In this specific case an ellipsis will replace the removed part.
pub fn fit_width(&mut self, width: usize, align: Alignment, skin: &MadSkin) {
Fitter::for_align(align).fit(self, width, skin);
}
/// if the composite is smaller than the given width, pad it
/// according to the alignment.
pub fn extend_width(&mut self, width: usize, align: Alignment) {
if let Some(ref mut spacing) = self.spacing {
if spacing.width < width {
spacing.width = width;
}
spacing.align = align;
} else if self.visible_length < width {
self.spacing = Some(Spacing { width, align });
}
}
/// try to make it so that the composite has exactly the given width,
/// either by shortening it or by adding space.
///
/// This calls the `fit_width` and `extend_width` methods.
pub fn fill_width(&mut self, width: usize, align: Alignment, skin: &MadSkin) {
self.fit_width(width, align, skin);
self.extend_width(width, align);
}
}
impl Default for FmtComposite<'_> {
fn default() -> Self {
Self::new()
}
}