1use crate::{
7 ansi::{Color, Ground, NamedColor},
8 lexer::{EmphasisType, ResetKind, TagType, Token},
9};
10
11#[must_use]
15pub fn tag_to_markup_part(tag: &TagType) -> String {
16 match tag {
17 TagType::Emphasis(e) => match e {
18 EmphasisType::Bold => "bold".to_string(),
19 EmphasisType::Blink => "blink".to_string(),
20 EmphasisType::Dim => "dim".to_string(),
21 EmphasisType::Italic => "italic".to_string(),
22 EmphasisType::Strikethrough => "strikethrough".to_string(),
23 EmphasisType::Underline => "underline".to_string(),
24 EmphasisType::DoubleUnderline => "double-underline".to_string(),
25 EmphasisType::Overline => "overline".to_string(),
26 EmphasisType::Invisible => "invisible".to_string(),
27 EmphasisType::Reverse => "reverse".to_string(),
28 EmphasisType::RapidBlink => "rapid-blink".to_string(),
29 },
30 TagType::Color { color, ground } => {
31 let prepend = match ground {
32 Ground::Background => "bg:",
33 Ground::Foreground => "",
34 };
35 match color {
36 Color::Ansi256(a) => format!("{prepend}ansi({a})"),
37 Color::Named(n) => {
38 let name = match n {
39 NamedColor::Black => "black",
40 NamedColor::Red => "red",
41 NamedColor::Green => "green",
42 NamedColor::Yellow => "yellow",
43 NamedColor::Blue => "blue",
44 NamedColor::Magenta => "magenta",
45 NamedColor::Cyan => "cyan",
46 NamedColor::White => "white",
47 NamedColor::BrightBlack => "bright-black",
48 NamedColor::BrightRed => "bright-red",
49 NamedColor::BrightGreen => "bright-green",
50 NamedColor::BrightYellow => "bright-yellow",
51 NamedColor::BrightBlue => "bright-blue",
52 NamedColor::BrightMagenta => "bright-magenta",
53 NamedColor::BrightCyan => "bright-cyan",
54 NamedColor::BrightWhite => "bright-white",
55 };
56 format!("{prepend}{name}")
57 }
58 Color::Rgb(r, g, b) => format!("{prepend}rgb({r},{g},{b})"),
59 }
60 }
61 TagType::ResetAll => "/".to_string(),
62 TagType::ResetOne(inner) => {
63 let part = match inner {
64 ResetKind::Emphasis(e) => tag_to_markup_part(&TagType::Emphasis(*e)),
65 ResetKind::Color { color, ground } => tag_to_markup_part(&TagType::Color {
66 color: color.clone(),
67 ground: *ground,
68 }),
69 };
70 format!("/{part}")
71 }
72 TagType::Prefix(_) => String::new(),
73 }
74}
75
76#[must_use]
80pub fn tokens_to_markup(tokens: &[Token]) -> String {
81 let mut result = String::new();
82 let mut i = 0;
83
84 while i < tokens.len() {
85 match &tokens[i] {
86 Token::Text(s) => {
87 result.push_str(s);
88 i += 1;
89 }
90 Token::Tag(_) => {
91 let mut parts = Vec::new();
92 while i < tokens.len() {
93 if let Token::Tag(tag) = &tokens[i] {
94 parts.push(tag_to_markup_part(tag));
95 i += 1;
96 } else {
97 break;
98 }
99 }
100 result.push('[');
101 result.push_str(&parts.join(" "));
102 result.push(']');
103 }
104 }
105 }
106
107 result
108}