1use crate::{MathRenderer, RenderError};
4use ratatui::{
5 buffer::Buffer,
6 layout::Rect,
7 style::{Color, Style},
8 text::{Line, Span},
9 widgets::{Block, Paragraph, Widget, Wrap},
10};
11
12#[derive(Clone)]
14pub struct MathWidget<'a> {
15 latex: &'a str,
16 style: Style,
17 block: Option<Block<'a>>,
18 use_unicode_scripts: bool,
19 wrap: bool,
20}
21
22impl<'a> MathWidget<'a> {
23 pub fn new(latex: &'a str) -> Self {
25 Self {
26 latex,
27 style: Style::default(),
28 block: None,
29 use_unicode_scripts: true,
30 wrap: false,
31 }
32 }
33
34 pub fn style(mut self, style: Style) -> Self {
36 self.style = style;
37 self
38 }
39
40 pub fn fg(mut self, color: Color) -> Self {
42 self.style = self.style.fg(color);
43 self
44 }
45
46 pub fn bg(mut self, color: Color) -> Self {
48 self.style = self.style.bg(color);
49 self
50 }
51
52 pub fn block(mut self, block: Block<'a>) -> Self {
54 self.block = Some(block);
55 self
56 }
57
58 pub fn use_unicode_scripts(mut self, use_unicode: bool) -> Self {
60 self.use_unicode_scripts = use_unicode;
61 self
62 }
63
64 pub fn wrap(mut self, wrap: bool) -> Self {
66 self.wrap = wrap;
67 self
68 }
69
70 pub fn render_to_string(&self) -> Result<String, RenderError> {
72 let renderer = MathRenderer::new().use_unicode_scripts(self.use_unicode_scripts);
73 renderer.render_latex(self.latex)
74 }
75}
76
77impl Widget for MathWidget<'_> {
78 fn render(self, area: Rect, buf: &mut Buffer) {
79 let renderer = MathRenderer::new().use_unicode_scripts(self.use_unicode_scripts);
80
81 let rendered = match renderer.render_latex(self.latex) {
82 Ok(s) => s,
83 Err(e) => format!("Error: {}", e),
84 };
85
86 let lines: Vec<Line> = rendered
87 .lines()
88 .map(|line| Line::from(Span::styled(line.to_string(), self.style)))
89 .collect();
90
91 let mut paragraph = Paragraph::new(lines);
92
93 if let Some(block) = self.block {
94 paragraph = paragraph.block(block);
95 }
96
97 if self.wrap {
98 paragraph = paragraph.wrap(Wrap { trim: false });
99 }
100
101 paragraph.render(area, buf);
102 }
103}
104
105pub struct MathWidgetState {
107 rendered: Option<String>,
108 error: Option<String>,
109}
110
111impl MathWidgetState {
112 pub fn new() -> Self {
113 Self {
114 rendered: None,
115 error: None,
116 }
117 }
118
119 pub fn update(&mut self, latex: &str, use_unicode_scripts: bool) {
121 let renderer = MathRenderer::new().use_unicode_scripts(use_unicode_scripts);
122 match renderer.render_latex(latex) {
123 Ok(s) => {
124 self.rendered = Some(s);
125 self.error = None;
126 }
127 Err(e) => {
128 self.rendered = None;
129 self.error = Some(e.to_string());
130 }
131 }
132 }
133
134 pub fn rendered(&self) -> Option<&str> {
136 self.rendered.as_deref()
137 }
138
139 pub fn error(&self) -> Option<&str> {
141 self.error.as_deref()
142 }
143}
144
145impl Default for MathWidgetState {
146 fn default() -> Self {
147 Self::new()
148 }
149}
150
151pub struct StatefulMathWidget<'a> {
153 style: Style,
154 block: Option<Block<'a>>,
155 wrap: bool,
156}
157
158impl<'a> StatefulMathWidget<'a> {
159 pub fn new() -> Self {
160 Self {
161 style: Style::default(),
162 block: None,
163 wrap: false,
164 }
165 }
166
167 pub fn style(mut self, style: Style) -> Self {
168 self.style = style;
169 self
170 }
171
172 pub fn block(mut self, block: Block<'a>) -> Self {
173 self.block = Some(block);
174 self
175 }
176
177 pub fn wrap(mut self, wrap: bool) -> Self {
178 self.wrap = wrap;
179 self
180 }
181
182 pub fn render(self, area: Rect, buf: &mut Buffer, state: &MathWidgetState) {
183 let text = state
184 .rendered
185 .as_deref()
186 .or(state.error.as_deref())
187 .unwrap_or("");
188
189 let lines: Vec<Line> = text
190 .lines()
191 .map(|line| Line::from(Span::styled(line.to_string(), self.style)))
192 .collect();
193
194 let mut paragraph = Paragraph::new(lines);
195
196 if let Some(block) = self.block {
197 paragraph = paragraph.block(block);
198 }
199
200 if self.wrap {
201 paragraph = paragraph.wrap(Wrap { trim: false });
202 }
203
204 paragraph.render(area, buf);
205 }
206}
207
208impl Default for StatefulMathWidget<'_> {
209 fn default() -> Self {
210 Self::new()
211 }
212}