render_tree/stylesheet/
style.rs

1use crate::stylesheet::Color;
2use std;
3use std::fmt;
4use std::io;
5use termcolor::WriteColor;
6use termcolor::{self, ColorSpec};
7
8pub trait WriteStyle: WriteColor {
9    fn set_style<'a>(&mut self, style: impl Into<Style>) -> io::Result<()> {
10        self.set_color(&style.into().to_color_spec())
11    }
12}
13
14impl<T: WriteColor> WriteStyle for T {}
15
16#[derive(Debug, Copy, Clone, Eq, PartialEq)]
17pub enum ColorAttribute {
18    Reset,
19    Inherit,
20    Color(Color),
21}
22
23impl fmt::Display for ColorAttribute {
24    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
25        match self {
26            ColorAttribute::Reset => write!(f, "reset"),
27            ColorAttribute::Inherit => write!(f, "inherit"),
28            ColorAttribute::Color(color) => write!(f, "{}", color),
29        }
30    }
31}
32
33impl AttributeValue for ColorAttribute {
34    type ApplyValue = Option<Color>;
35    type SetValue = ColorAttribute;
36
37    fn parse(s: &str) -> ColorAttribute {
38        match s {
39            "reset" => ColorAttribute::Reset,
40            other => ColorAttribute::Color(other.into()),
41        }
42    }
43
44    fn update(self, attribute: ColorAttribute) -> ColorAttribute {
45        match attribute {
46            ColorAttribute::Inherit => self,
47            other => other,
48        }
49    }
50
51    fn apply(&self, f: impl FnOnce(Option<Color>)) {
52        match self {
53            ColorAttribute::Color(color) => f(Some(*color)),
54            ColorAttribute::Reset => f(None),
55            _ => {}
56        }
57    }
58
59    fn is_default(&self) -> bool {
60        match self {
61            ColorAttribute::Inherit => true,
62            _ => false,
63        }
64    }
65
66    fn set(self, color: ColorAttribute) -> ColorAttribute {
67        color
68    }
69
70    fn debug_value(&self) -> Option<String> {
71        Some(format!("{}", self))
72    }
73}
74
75impl<'a> From<&'a str> for ColorAttribute {
76    fn from(color: &'a str) -> ColorAttribute {
77        ColorAttribute::Color(color.into())
78    }
79}
80
81impl From<Color> for ColorAttribute {
82    fn from(color: Color) -> ColorAttribute {
83        ColorAttribute::Color(color)
84    }
85}
86
87impl<'a> From<Option<&'a termcolor::Color>> for ColorAttribute {
88    fn from(color: Option<&'a termcolor::Color>) -> ColorAttribute {
89        match color {
90            None => ColorAttribute::Inherit,
91            Some(color) => ColorAttribute::Color(color.into()),
92        }
93    }
94}
95
96impl std::default::Default for ColorAttribute {
97    fn default() -> ColorAttribute {
98        ColorAttribute::Inherit
99    }
100}
101
102#[derive(Debug, Clone, Eq, PartialEq)]
103pub enum WeightAttribute {
104    // bright
105    Normal,
106
107    // bright + bold
108    Bold,
109
110    // neither
111    Dim,
112
113    Inherit,
114}
115
116#[derive(Debug, Copy, Clone, Eq, PartialEq)]
117pub enum SetWeight {
118    Normal,
119    Bold,
120    Dim,
121}
122
123impl fmt::Display for WeightAttribute {
124    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
125        match self {
126            WeightAttribute::Normal => write!(f, "normal"),
127            WeightAttribute::Bold => write!(f, "bold"),
128            WeightAttribute::Dim => write!(f, "dim"),
129            WeightAttribute::Inherit => write!(f, "inherit"),
130        }
131    }
132}
133
134impl std::default::Default for WeightAttribute {
135    fn default() -> WeightAttribute {
136        WeightAttribute::Inherit
137    }
138}
139
140impl AttributeValue for WeightAttribute {
141    type ApplyValue = SetWeight;
142    type SetValue = WeightAttribute;
143
144    fn parse(s: &str) -> WeightAttribute {
145        match s {
146            "normal" => WeightAttribute::Normal,
147            "bold" => WeightAttribute::Bold,
148            "dim" => WeightAttribute::Dim,
149            other => panic!("Unexpected value for `weight`: {}", other),
150        }
151    }
152
153    fn update(self, attribute: WeightAttribute) -> WeightAttribute {
154        match attribute {
155            WeightAttribute::Normal => WeightAttribute::Normal,
156            WeightAttribute::Bold => WeightAttribute::Bold,
157            WeightAttribute::Dim => WeightAttribute::Dim,
158            WeightAttribute::Inherit => self,
159        }
160    }
161
162    fn apply(&self, f: impl FnOnce(SetWeight)) {
163        match self {
164            WeightAttribute::Normal => f(SetWeight::Normal),
165            WeightAttribute::Bold => f(SetWeight::Bold),
166            WeightAttribute::Dim => f(SetWeight::Dim),
167            _ => {}
168        }
169    }
170
171    fn is_default(&self) -> bool {
172        match self {
173            WeightAttribute::Inherit => true,
174            _ => false,
175        }
176    }
177
178    fn set(self, weight: Self) -> WeightAttribute {
179        weight
180    }
181
182    fn debug_value(&self) -> Option<String> {
183        match self {
184            WeightAttribute::Inherit => None,
185            other => Some(format!("{}", other)),
186        }
187    }
188}
189
190#[derive(Debug, Copy, Clone, PartialEq, Eq)]
191pub enum BooleanAttribute {
192    On,
193    Off,
194    Inherit,
195}
196
197impl fmt::Display for BooleanAttribute {
198    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
199        match self {
200            BooleanAttribute::On => write!(f, "true"),
201            BooleanAttribute::Off => write!(f, "false"),
202            BooleanAttribute::Inherit => write!(f, "inherit"),
203        }
204    }
205}
206
207impl std::default::Default for BooleanAttribute {
208    fn default() -> BooleanAttribute {
209        BooleanAttribute::Inherit
210    }
211}
212
213impl AttributeValue for BooleanAttribute {
214    type ApplyValue = bool;
215    type SetValue = BooleanAttribute;
216
217    fn parse(s: &str) -> BooleanAttribute {
218        match s {
219            "true" => BooleanAttribute::On,
220            "false" => BooleanAttribute::Off,
221            other => panic!("Unexpected boolean attribute {}", other),
222        }
223    }
224
225    fn update(self, attribute: BooleanAttribute) -> BooleanAttribute {
226        match attribute {
227            BooleanAttribute::On => BooleanAttribute::On,
228            BooleanAttribute::Off => BooleanAttribute::Off,
229            BooleanAttribute::Inherit => self,
230        }
231    }
232
233    fn apply(&self, f: impl FnOnce(bool)) {
234        match self {
235            BooleanAttribute::On => f(true),
236            BooleanAttribute::Off => f(false),
237            _ => {}
238        }
239    }
240
241    fn is_default(&self) -> bool {
242        match self {
243            BooleanAttribute::Inherit => true,
244            _ => false,
245        }
246    }
247
248    fn set(self, boolean: BooleanAttribute) -> BooleanAttribute {
249        boolean
250    }
251
252    fn debug_value(&self) -> Option<String> {
253        None
254    }
255}
256
257impl<'a> Into<Style> for &'a str {
258    fn into(self) -> Style {
259        Style::from_stylesheet(self)
260    }
261}
262
263impl<'a> Into<Style> for &'a Style {
264    fn into(self) -> Style {
265        self.clone()
266    }
267}
268
269pub trait AttributeValue: Default + fmt::Display {
270    type ApplyValue;
271    type SetValue;
272
273    fn parse(s: &str) -> Self;
274    fn update(self, other: Self) -> Self;
275    fn apply(&self, f: impl FnOnce(Self::ApplyValue));
276    fn is_default(&self) -> bool;
277    fn set(self, value: Self::SetValue) -> Self;
278    fn debug_value(&self) -> Option<String>;
279}
280
281#[derive(Debug, Clone, PartialEq, Eq)]
282pub struct Attribute<Value: AttributeValue> {
283    name: AttributeName,
284    value: Value,
285}
286
287impl<Value: AttributeValue> fmt::Display for Attribute<Value> {
288    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
289        write!(f, "{}={}", self.name, self.value)
290    }
291}
292
293impl<Value: AttributeValue> Attribute<Value> {
294    pub fn inherit(name: impl Into<AttributeName>) -> Attribute<Value> {
295        Attribute(name.into(), Value::default())
296    }
297
298    pub fn tuple(&self) -> (AttributeName, Option<String>) {
299        (self.name, self.value.debug_value())
300    }
301}
302
303impl<Value: AttributeValue> Attribute<Value> {
304    pub fn update(self, attribute: Attribute<Value>) -> Attribute<Value> {
305        Attribute(self.name.clone(), self.value.update(attribute.value))
306    }
307
308    pub fn apply(&self, f: impl FnOnce(Value::ApplyValue)) {
309        self.value.apply(f)
310    }
311
312    pub fn is_default(&self) -> bool {
313        self.value.is_default()
314    }
315
316    pub fn has_value(&self) -> bool {
317        !self.is_default()
318    }
319
320    pub fn mutate(&mut self, value: Value) {
321        self.value = value
322    }
323}
324
325#[derive(Debug, Clone, Copy, PartialEq, Eq)]
326pub enum AttributeName {
327    Fg,
328    Bg,
329    Weight,
330    Underline,
331}
332
333impl<'a> From<&'a str> for AttributeName {
334    fn from(from: &'a str) -> AttributeName {
335        match from {
336            "fg" => AttributeName::Fg,
337            "bg" => AttributeName::Bg,
338            "weight" => AttributeName::Weight,
339            "underline" => AttributeName::Underline,
340            other => panic!("Invalid style attribute name {}", other),
341        }
342    }
343}
344
345impl<'a> From<String> for AttributeName {
346    fn from(from: String) -> AttributeName {
347        AttributeName::from(&from[..])
348    }
349}
350
351impl fmt::Display for AttributeName {
352    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
353        let name = match self {
354            AttributeName::Fg => "fg",
355            AttributeName::Bg => "bg",
356            AttributeName::Weight => "weight",
357            AttributeName::Underline => "underline",
358        };
359
360        write!(f, "{}", name)
361    }
362}
363
364#[allow(non_snake_case)]
365fn Attribute<Value: AttributeValue>(name: AttributeName, value: Value) -> Attribute<Value> {
366    Attribute {
367        name: name.into(),
368        value,
369    }
370}
371
372#[derive(Debug, Clone, PartialEq)]
373pub struct Style {
374    weight: Attribute<WeightAttribute>,
375    underline: Attribute<BooleanAttribute>,
376    fg: Attribute<ColorAttribute>,
377    bg: Attribute<ColorAttribute>,
378}
379
380impl fmt::Display for Style {
381    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
382        let mut has_prev = false;
383
384        let mut space = |f: &mut fmt::Formatter| -> fmt::Result {
385            if has_prev {
386                write!(f, " ")?;
387            } else {
388                has_prev = true;
389            }
390
391            Ok(())
392        };
393
394        write!(f, "Style {{")?;
395
396        if self.fg.has_value() {
397            space(f)?;
398            write!(f, "{}", self.fg)?;
399        }
400
401        if self.bg.has_value() {
402            space(f)?;
403            write!(f, "{}", self.bg)?;
404        }
405
406        if self.weight.has_value() {
407            space(f)?;
408            write!(f, "{}", self.weight)?;
409        }
410
411        if self.underline.has_value() {
412            space(f)?;
413            write!(f, "{}", self.underline)?;
414        }
415
416        write!(f, "}}")?;
417
418        Ok(())
419    }
420}
421
422#[allow(non_snake_case)]
423pub fn Style(input: &str) -> Style {
424    Style::from_stylesheet(input)
425}
426
427impl Style {
428    pub fn empty() -> Style {
429        Style {
430            fg: Attribute(AttributeName::Fg, ColorAttribute::default()),
431            bg: Attribute(AttributeName::Bg, ColorAttribute::default()),
432            weight: Attribute(AttributeName::Weight, WeightAttribute::default()),
433            underline: Attribute(AttributeName::Underline, BooleanAttribute::default()),
434        }
435    }
436
437    pub fn new() -> Style {
438        Style::empty()
439    }
440
441    pub fn from_stylesheet(input: &str) -> Style {
442        let mut fg = Attribute::inherit(AttributeName::Fg);
443        let mut bg = Attribute::inherit(AttributeName::Bg);
444        let mut weight = Attribute::inherit(AttributeName::Weight);
445        let mut underline = Attribute::inherit(AttributeName::Underline);
446
447        for (key, value) in StyleString::new(input) {
448            match key {
449                AttributeName::Fg => fg = Attribute(key, ColorAttribute::parse(value)),
450                AttributeName::Bg => bg = Attribute(key, ColorAttribute::parse(value)),
451                AttributeName::Weight => weight = Attribute(key, WeightAttribute::parse(value)),
452                AttributeName::Underline => {
453                    underline = Attribute(key, BooleanAttribute::parse(value))
454                }
455            }
456        }
457
458        Style {
459            weight,
460            underline,
461            bg,
462            fg,
463        }
464    }
465
466    pub fn from_color_spec(spec: ColorSpec) -> Style {
467        let mut weight = WeightAttribute::Inherit;
468
469        if spec.bold() && spec.intense() {
470            weight = weight.update(WeightAttribute::Bold);
471        } else if spec.intense() {
472            weight = weight.update(WeightAttribute::Normal);
473        } else if spec.bold() {
474            panic!("ColorSpec bold + not intense is not supported as it is not portable");
475        } else {
476            weight = weight.update(WeightAttribute::Dim);
477        }
478
479        let mut underline = BooleanAttribute::Inherit;
480
481        if spec.underline() {
482            underline = underline.set(BooleanAttribute::On);
483        }
484
485        let foreground = spec.fg().into();
486        let background = spec.bg().into();
487
488        Style {
489            weight: Attribute(AttributeName::Weight, weight),
490            underline: Attribute(AttributeName::Underline, underline),
491            fg: Attribute(AttributeName::Fg, foreground),
492            bg: Attribute(AttributeName::Bg, background),
493        }
494    }
495
496    pub fn debug_attributes(&self) -> Vec<(AttributeName, Option<String>)> {
497        let mut attrs: Vec<(AttributeName, Option<String>)> = vec![];
498
499        if self.weight.has_value() {
500            attrs.push(self.weight.tuple());
501        }
502
503        if self.fg.has_value() {
504            attrs.push(self.fg.tuple());
505        }
506
507        if self.bg.has_value() {
508            attrs.push(self.bg.tuple());
509        }
510
511        attrs
512    }
513
514    pub fn union(self, other: Style) -> Style {
515        Style {
516            weight: self.weight.update(other.weight),
517            underline: self.underline.update(other.underline),
518            fg: self.fg.update(other.fg),
519            bg: self.bg.update(other.bg),
520        }
521    }
522
523    pub fn to_color_spec(&self) -> ColorSpec {
524        let mut spec = ColorSpec::new();
525
526        self.weight.apply(|w| match w {
527            SetWeight::Normal => {
528                spec.set_intense(true);
529            }
530            SetWeight::Bold => {
531                spec.set_bold(true).set_intense(true);
532            }
533            SetWeight::Dim => {
534                spec.set_bold(false).set_intense(false);
535            }
536        });
537
538        self.underline.apply(|b| {
539            spec.set_underline(b);
540        });
541
542        self.fg.apply(|fg| {
543            spec.set_fg(fg.map(|fg| fg.into()));
544        });
545
546        self.bg.apply(|bg| {
547            spec.set_bg(bg.map(|bg| bg.into()));
548        });
549
550        spec
551    }
552
553    pub fn has_value(&self) -> bool {
554        !self.is_default()
555    }
556
557    pub fn is_default(&self) -> bool {
558        self.weight.is_default()
559            && self.underline.is_default()
560            && self.fg.is_default()
561            && self.bg.is_default()
562    }
563
564    pub fn fg(&self, color: impl Into<Color>) -> Style {
565        let color_attribute = ColorAttribute::Color(color.into());
566        self.update(|style| style.fg.mutate(color_attribute))
567    }
568
569    pub fn bg(&self, color: impl Into<Color>) -> Style {
570        let color_attribute = ColorAttribute::Color(color.into());
571        self.update(|style| style.bg.mutate(color_attribute))
572    }
573
574    pub fn weight(&self, weight: WeightAttribute) -> Style {
575        self.update(|style| style.weight.mutate(weight))
576    }
577
578    pub fn bold(&self) -> Style {
579        self.update(|style| style.weight.mutate(WeightAttribute::Bold))
580    }
581
582    pub fn dim(&self) -> Style {
583        self.update(|style| style.weight.mutate(WeightAttribute::Dim))
584    }
585
586    pub fn normal(&self) -> Style {
587        self.update(|style| style.weight.mutate(WeightAttribute::Normal))
588    }
589
590    pub fn underline(&self) -> Style {
591        self.update(|style| style.underline.mutate(BooleanAttribute::On))
592    }
593
594    pub fn nounderline(&self) -> Style {
595        self.update(|style| style.underline.mutate(BooleanAttribute::Off))
596    }
597
598    fn update(&self, f: impl FnOnce(&mut Style)) -> Style {
599        let mut style = self.clone();
600        f(&mut style);
601        style
602    }
603}
604
605struct StyleString<'a> {
606    rest: &'a str,
607}
608
609impl<'a> StyleString<'a> {
610    fn new(input: &str) -> StyleString {
611        StyleString { rest: input }
612    }
613}
614
615impl<'a> Iterator for StyleString<'a> {
616    type Item = (AttributeName, &'a str);
617
618    fn next(&mut self) -> Option<(AttributeName, &'a str)> {
619        if self.rest.len() == 0 {
620            return None;
621        }
622
623        let name = if let Some(next) = self.rest.find(':') {
624            let next_part = &self.rest[..next];
625            self.rest = &self.rest[(next + 1)..];
626            next_part.trim()
627        } else {
628            panic!("Unexpected style string, missing `:`")
629        };
630
631        if let Some(next) = self.rest.find(';') {
632            let next_part = self.rest[..next].trim();
633            self.rest = &self.rest[(next + 1)..];
634            Some((AttributeName::from(name), next_part))
635        } else {
636            let next_part = self.rest.trim();
637            self.rest = "";
638            Some((AttributeName::from(name), next_part))
639        }
640    }
641}