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 Normal,
106
107 Bold,
109
110 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}