1use crate::ui::document::{LineBlock, LinePart};
2use crate::ui::style::{StyleOverrides, StyleToken, apply_style_with_theme_overrides};
3use crate::ui::theme::ThemeDefinition;
4
5pub fn parts_from_inline(text: &str) -> Vec<LinePart> {
6 let mut parts: Vec<LinePart> = Vec::new();
7 let mut buf = String::new();
8 let chars: Vec<char> = text.chars().collect();
9 let mut i = 0usize;
10
11 let flush = |parts: &mut Vec<LinePart>, buf: &mut String| {
12 if !buf.is_empty() {
13 parts.push(LinePart {
14 text: buf.clone(),
15 token: None,
16 });
17 buf.clear();
18 }
19 };
20
21 while i < chars.len() {
22 let ch = chars[i];
23 if ch == '\\' && i + 1 < chars.len() {
24 buf.push(chars[i + 1]);
25 i += 2;
26 continue;
27 }
28
29 if ch == '`' {
30 let fence = if i + 1 < chars.len() && chars[i + 1] == '`' {
31 2
32 } else {
33 1
34 };
35 let mut end = i + fence;
36 while end + fence - 1 < chars.len() {
37 if chars[end..end + fence].iter().all(|c| *c == '`') {
38 flush(&mut parts, &mut buf);
39 let content: String = chars[i + fence..end].iter().collect();
40 parts.push(LinePart {
41 text: content,
42 token: Some(StyleToken::Key),
43 });
44 i = end + fence;
45 break;
46 }
47 end += 1;
48 }
49 if end + fence - 1 < chars.len() {
50 continue;
51 }
52 }
53
54 if ch == '*' && i + 1 < chars.len() && chars[i + 1] == '*' {
55 let mut end = i + 2;
56 while end + 1 < chars.len() {
57 if chars[end] == '*' && chars[end + 1] == '*' {
58 flush(&mut parts, &mut buf);
59 let content: String = chars[i + 2..end].iter().collect();
60 parts.push(LinePart {
61 text: content,
62 token: Some(StyleToken::PanelBorder),
63 });
64 i = end + 2;
65 break;
66 }
67 end += 1;
68 }
69 if end + 1 < chars.len() {
70 continue;
71 }
72 }
73
74 if ch == '*' {
75 let mut end = i + 1;
76 while end < chars.len() {
77 if chars[end] == '*' {
78 flush(&mut parts, &mut buf);
79 let content: String = chars[i + 1..end].iter().collect();
80 parts.push(LinePart {
81 text: content,
82 token: Some(StyleToken::Muted),
83 });
84 i = end + 1;
85 break;
86 }
87 end += 1;
88 }
89 if end < chars.len() {
90 continue;
91 }
92 }
93
94 buf.push(ch);
95 i += 1;
96 }
97
98 flush(&mut parts, &mut buf);
99 parts
100}
101
102pub fn line_from_inline(text: &str) -> LineBlock {
103 LineBlock {
104 parts: parts_from_inline(text),
105 }
106}
107
108pub fn render_inline(
109 text: &str,
110 color: bool,
111 theme: &ThemeDefinition,
112 overrides: &StyleOverrides,
113) -> String {
114 let mut out = String::new();
115 for part in parts_from_inline(text) {
116 if let Some(token) = part.token {
117 out.push_str(&apply_style_with_theme_overrides(
118 &part.text, token, color, theme, overrides,
119 ));
120 } else {
121 out.push_str(&part.text);
122 }
123 }
124 out
125}