1#![forbid(unsafe_code)]
42#![warn(clippy::pedantic, missing_docs)]
43
44mod iter;
45mod render_chars;
46mod tokens;
47
48use asciimath_parser::tree::{
49 Expression, Frac, Func, Group, Intermediate, Matrix, Script, ScriptFunc, Simple, SimpleBinary,
50 SimpleFunc, SimpleScript, SimpleUnary,
51};
52use asciimath_parser::Tokenizer;
53pub use emojis::SkinTone;
54use iter::{Interleave, Modified};
55use render_chars::{enum_iter, struct_iter, RenderChars};
56use std::array;
57use std::fmt;
58use std::io;
59use std::io::Write;
60use std::iter::{Chain, Flatten, FusedIterator, Map};
61use std::str::Chars;
62use std::vec;
63use tokens::{
64 bold_map, cal_map, double_map, frak_map, italic_map, left_bracket_str, mono_map,
65 right_bracket_str, sans_map, subscript_char, superscript_char, symbol_str, TOKEN_MAP,
66};
67
68type CharIter = array::IntoIter<char, 1>;
69
70type GenericBinaryIter<'a> = Chain<
71 Chain<Chain<Chain<Chars<'a>, CharIter>, Box<SimpleIter<'a>>>, CharIter>,
72 Box<SimpleIter<'a>>,
73>;
74
75type CharMap<I> = Map<I, fn(char) -> char>;
76
77type Delim<'a, I> = Chain<Chain<Chars<'a>, I>, Chars<'a>>;
78
79type SimpleFuncIter<'a> = Chain<Chain<Chars<'a>, CharIter>, Box<SimpleIter<'a>>>;
80
81type GroupIter<'a> = Delim<'a, Box<ExpressionIter<'a>>>;
82
83type SimpleScriptIter<'a> = Chain<SimpleIter<'a>, ScriptIter<'a>>;
84
85type FuncIter<'a> =
86 Chain<Chain<Chain<Chars<'a>, ScriptIter<'a>>, CharIter>, Box<ScriptFuncIter<'a>>>;
87
88type ExpressionIter<'a> = Flatten<vec::IntoIter<IntermediateIter<'a>>>;
89
90type MatIter<'a> = Delim<'a, Box<Interleave<Delim<'a, Interleave<ExpressionIter<'a>>>>>>;
91
92struct_iter! { SimpMappedIter : CharMap<SimpleIter<'a>> }
93
94struct_iter! { FuncMappedIter : CharMap<ScriptFuncIter<'a>> }
95
96struct_iter! { ExprMappedIter : CharMap<ExpressionIter<'a>> }
97
98enum_iter! { SimpleUnaryIter :
99 Simple => Chain<CharIter, Box<SimpleIter<'a>>>,
100 Font => Box<CharMap<SimpleIter<'a>>>,
101 StrippedFont => Box<CharMap<ExpressionIter<'a>>>,
102 Wrapped => Delim<'a, Box<SimpleIter<'a>>>,
103 StrippedWrapped => Delim<'a, Box<ExpressionIter<'a>>>,
104 Single => Chain<Box<SimpleIter<'a>>, CharIter>,
105 StrippedSingle => Chain<Box<ExpressionIter<'a>>, CharIter>,
106 Moded => Box<Modified<SimpleIter<'a>>>,
107 StrippedModed => Box<Modified<ExpressionIter<'a>>>,
108 Generic => Chain<Chain<Chars<'a>, CharIter>, Box<SimpleIter<'a>>>,
109}
110
111enum_iter! { SimpleFracIter :
112 Vulgar => CharIter,
113 VulgOne => Chain<CharIter, SimpMappedIter<'a>>,
114 StrippedVulgOne => Chain<CharIter, Box<ExprMappedIter<'a>>>,
115 StrippedScript => Box<Chain<Chain<ExprMappedIter<'a>, CharIter>, ExprMappedIter<'a>>>,
116 DenomStrippedScript => Chain<Chain<SimpMappedIter<'a>, CharIter>, Box<ExprMappedIter<'a>>>,
117 NumerStrippedScript => Chain<Chain<Box<ExprMappedIter<'a>>, CharIter>, SimpMappedIter<'a>>,
118 Script => Chain<Chain<SimpMappedIter<'a>, CharIter>, SimpMappedIter<'a>>,
119 Simple => Chain<Chain<SimpleIter<'a>, CharIter>, SimpleIter<'a>>,
120}
121
122enum_iter! { SimpleBinaryIter :
123 Simple => Chain<CharIter, Box<SimpleIter<'a>>>,
124 ExprComb => Chain<Box<ExpressionIter<'a>>, CharIter>,
125 Comb => Chain<Box<SimpleIter<'a>>, CharIter>,
126 Char => CharIter,
127 Frac => Box<SimpleFracIter<'a>>,
128 Generic => GenericBinaryIter<'a>,
129}
130
131enum_iter! { SimpleIter :
132 Chars => Chars<'a>,
133 Func => SimpleFuncIter<'a>,
134 Unary => SimpleUnaryIter<'a>,
135 Binary => SimpleBinaryIter<'a>,
136 Group => GroupIter<'a>,
137 Matrix => MatIter<'a>,
138}
139
140enum_iter! { ScriptIter :
141 Empty => Chars<'static>,
142 Untouched => Chain<CharIter, SimpleIter<'a>>,
143 Mapped => CharMap<SimpleIter<'a>>,
144 SubsupUntouched => Chain<Chain<Chain<CharIter, SimpleIter<'a>>, CharIter>, SimpleIter<'a>>,
145 SubsupMapped => Chain<SimpMappedIter<'a>, SimpMappedIter<'a>>,
146}
147
148enum_iter! { ScriptFuncIter :
149 Simple => SimpleScriptIter<'a>,
150 Func => FuncIter<'a>,
151}
152
153enum_iter! { FracIter :
154 Simple => SimpleFracIter<'a>,
155 NumerStrippedScript => Chain<Chain<Box<ExprMappedIter<'a>>, CharIter>, FuncMappedIter<'a>>,
156 DenomStrippedScript => Chain<Chain<FuncMappedIter<'a>, CharIter>, Box<ExprMappedIter<'a>>>,
157 Script => Chain<Chain<FuncMappedIter<'a>, CharIter>, FuncMappedIter<'a>>,
158 VulgOne => Chain<CharIter, FuncMappedIter<'a>>,
159 One => Chain<Chars<'static>, ScriptFuncIter<'a>>,
160 Func => Chain<Chain<ScriptFuncIter<'a>, CharIter>, ScriptFuncIter<'a>>,
161}
162
163enum_iter! { IntermediateIter :
164 ScriptFunc => ScriptFuncIter<'a>,
165 Frac => FracIter<'a>,
166}
167
168macro_rules! num {
169 ($num:pat) => {
170 Simple::Number($num)
171 };
172}
173
174macro_rules! iden {
175 ($idn:pat) => {
176 Simple::Ident($idn)
177 };
178}
179
180macro_rules! symb {
181 ($sym:pat) => {
182 Simple::Symbol($sym)
183 };
184}
185
186macro_rules! script_func {
187 ($simp:pat) => {
188 ScriptFunc::Simple(SimpleScript {
189 simple: $simp,
190 script: Script::None,
191 })
192 };
193}
194
195macro_rules! sgroup {
196 ($expr:pat) => {
197 Simple::Group(Group { expr: $expr, .. })
198 };
199}
200
201macro_rules! xnum {
202 ($expr:expr, $num:pat) => {
203 matches!(
204 **$expr,
205 [Intermediate::ScriptFunc(script_func!(num!($num)))]
206 )
207 };
208}
209
210macro_rules! xiden {
211 ($expr:expr, $num:pat) => {
212 matches!(
213 **$expr,
214 [Intermediate::ScriptFunc(script_func!(iden!($num)))]
215 )
216 };
217}
218
219#[inline]
220fn vulg<'a>(vulgar: char) -> RenderChars<SimpleFracIter<'a>> {
221 RenderChars::from(vulgar).map(SimpleFracIter::Vulgar)
222}
223
224#[inline]
225fn gsfrac<'a>(
226 num: RenderChars<SimpleIter<'a>>,
227 den: RenderChars<SimpleIter<'a>>,
228) -> RenderChars<SimpleFracIter<'a>> {
229 num.chain(RenderChars::from('/'))
230 .chain(den)
231 .map(SimpleFracIter::Simple)
232}
233
234#[inline]
235fn gfrac<'a>(
236 num: RenderChars<ScriptFuncIter<'a>>,
237 den: RenderChars<ScriptFuncIter<'a>>,
238) -> RenderChars<FracIter<'a>> {
239 num.chain(RenderChars::from('/'))
240 .chain(den)
241 .map(FracIter::Func)
242}
243
244#[derive(Debug, Clone, PartialEq, Eq)]
246pub struct InlineRenderer {
247 pub strip_brackets: bool,
249 pub vulgar_fracs: bool,
251 pub script_fracs: bool,
253 pub skin_tone: SkinTone,
255}
256
257impl Default for InlineRenderer {
258 fn default() -> Self {
259 InlineRenderer {
260 strip_brackets: true,
261 vulgar_fracs: true,
262 script_fracs: true,
263 skin_tone: SkinTone::Default,
264 }
265 }
266}
267
268impl InlineRenderer {
269 fn render_simplefunc<'a>(&self, simple: &SimpleFunc<'a>) -> RenderChars<SimpleFuncIter<'a>> {
270 RenderChars::from(simple.func)
271 .chain(RenderChars::from(' '))
272 .chain(self.render_simple(simple.arg()).map(Box::new))
273 }
274
275 #[inline]
276 fn render_root<'a>(
277 &self,
278 root_char: char,
279 arg: &Simple<'a>,
280 ) -> RenderChars<SimpleBinaryIter<'a>> {
281 RenderChars::from(root_char)
282 .chain(self.render_simple(arg).map(Box::new))
283 .map(SimpleBinaryIter::Simple)
284 }
285
286 #[inline]
287 fn cover<'a>(
288 &self,
289 op: &'a str,
290 first: &Simple<'a>,
291 arg: &Simple<'a>,
292 chr: char,
293 ) -> RenderChars<SimpleBinaryIter<'a>> {
294 match arg {
295 sgroup!(expr) if self.strip_brackets => {
296 let rendered = self.render_expression(expr);
297 if rendered.len == 1 {
298 rendered
299 .map(Box::new)
300 .chain(RenderChars::from(chr))
301 .map(SimpleBinaryIter::ExprComb)
302 } else {
303 self.render_bgeneric(op, first, arg)
304 }
305 }
306 arg => {
307 let rendered = self.render_simple(arg);
308 if rendered.len == 1 {
309 rendered
310 .map(Box::new)
311 .chain(RenderChars::from(chr))
312 .map(SimpleBinaryIter::Comb)
313 } else {
314 self.render_bgeneric(op, first, arg)
315 }
316 }
317 }
318 }
319
320 #[inline]
321 fn render_equals<'a>(
322 &self,
323 iter: impl Iterator<Item = char> + Clone,
324 op: &'a str,
325 first: &Simple<'a>,
326 second: &Simple<'a>,
327 ) -> RenderChars<SimpleBinaryIter<'a>> {
328 if iter.clone().eq("∘".chars()) {
329 RenderChars::from('\u{2257}').map(SimpleBinaryIter::Char)
330 } else if iter.clone().eq("⋆".chars()) {
331 RenderChars::from('\u{225b}').map(SimpleBinaryIter::Char)
332 } else if iter.clone().eq("△".chars()) {
333 RenderChars::from('\u{225c}').map(SimpleBinaryIter::Char)
334 } else if iter.clone().eq("def".chars()) {
335 RenderChars::from('\u{225d}').map(SimpleBinaryIter::Char)
336 } else if iter.clone().eq("m".chars()) {
337 RenderChars::from('\u{225e}').map(SimpleBinaryIter::Char)
338 } else if iter.eq("?".chars()) {
339 RenderChars::from('\u{225f}').map(SimpleBinaryIter::Char)
340 } else {
341 self.render_bgeneric(op, first, second)
342 }
343 }
344
345 #[inline]
346 fn render_bgeneric<'a>(
347 &self,
348 op: &'a str,
349 first: &Simple<'a>,
350 second: &Simple<'a>,
351 ) -> RenderChars<SimpleBinaryIter<'a>> {
352 RenderChars::from(op)
353 .chain(RenderChars::from(' '))
354 .chain(self.render_simple(first).map(Box::new))
355 .chain(RenderChars::from(' '))
356 .chain(self.render_simple(second).map(Box::new))
357 .map(SimpleBinaryIter::Generic)
358 }
359
360 fn render_simplebinary<'a>(
361 &self,
362 simple: &SimpleBinary<'a>,
363 ) -> RenderChars<SimpleBinaryIter<'a>> {
364 let sb = self.strip_brackets;
365 match (simple.op, simple.first(), simple.second()) {
366 ("root", num!("2"), arg) => self.render_root('√', arg),
368 ("root", num!("3"), arg) => self.render_root('∛', arg),
369 ("root", num!("4"), arg) => self.render_root('∜', arg),
370 ("root", sgroup!(expr), arg) if xnum!(expr, "2") => self.render_root('√', arg),
371 ("root", sgroup!(expr), arg) if xnum!(expr, "3") => self.render_root('∛', arg),
372 ("root", sgroup!(expr), arg) if xnum!(expr, "4") => self.render_root('∜', arg),
373 ("frac", numer, denom) => self
375 .render_simplefrac(numer, denom)
376 .map(|iter| SimpleBinaryIter::Frac(Box::new(iter))),
377 (o @ ("stackrel" | "overset"), f @ iden!("a"), a) => self.cover(o, f, a, '\u{0363}'),
379 (o @ ("stackrel" | "overset"), f @ iden!("e"), a) => self.cover(o, f, a, '\u{0364}'),
380 (o @ ("stackrel" | "overset"), f @ iden!("i"), a) => self.cover(o, f, a, '\u{0365}'),
381 (o @ ("stackrel" | "overset"), f @ iden!("o"), a) => self.cover(o, f, a, '\u{0366}'),
382 (o @ ("stackrel" | "overset"), f @ iden!("u"), a) => self.cover(o, f, a, '\u{0367}'),
383 (o @ ("stackrel" | "overset"), f @ iden!("c"), a) => self.cover(o, f, a, '\u{0368}'),
384 (o @ ("stackrel" | "overset"), f @ iden!("d"), a) => self.cover(o, f, a, '\u{0369}'),
385 (o @ ("stackrel" | "overset"), f @ iden!("h"), a) => self.cover(o, f, a, '\u{036a}'),
386 (o @ ("stackrel" | "overset"), f @ iden!("m"), a) => self.cover(o, f, a, '\u{036b}'),
387 (o @ ("stackrel" | "overset"), f @ iden!("r"), a) => self.cover(o, f, a, '\u{036c}'),
388 (o @ ("stackrel" | "overset"), f @ iden!("t"), a) => self.cover(o, f, a, '\u{036d}'),
389 (o @ ("stackrel" | "overset"), f @ iden!("v"), a) => self.cover(o, f, a, '\u{036e}'),
390 (o @ ("stackrel" | "overset"), f @ iden!("x"), a) => self.cover(o, f, a, '\u{036f}'),
391 ("stackrel" | "overset", sgroup!(exp), arg) if sb && xiden!(exp, "a") => {
392 self.cover(simple.op, simple.first(), arg, '\u{0363}')
393 }
394 ("stackrel" | "overset", sgroup!(exp), arg) if sb && xiden!(exp, "e") => {
395 self.cover(simple.op, simple.first(), arg, '\u{0364}')
396 }
397 ("stackrel" | "overset", sgroup!(exp), arg) if sb && xiden!(exp, "i") => {
398 self.cover(simple.op, simple.first(), arg, '\u{0365}')
399 }
400 ("stackrel" | "overset", sgroup!(exp), arg) if sb && xiden!(exp, "o") => {
401 self.cover(simple.op, simple.first(), arg, '\u{0366}')
402 }
403 ("stackrel" | "overset", sgroup!(exp), arg) if sb && xiden!(exp, "u") => {
404 self.cover(simple.op, simple.first(), arg, '\u{0367}')
405 }
406 ("stackrel" | "overset", sgroup!(exp), arg) if sb && xiden!(exp, "c") => {
407 self.cover(simple.op, simple.first(), arg, '\u{0368}')
408 }
409 ("stackrel" | "overset", sgroup!(exp), arg) if sb && xiden!(exp, "d") => {
410 self.cover(simple.op, simple.first(), arg, '\u{0369}')
411 }
412 ("stackrel" | "overset", sgroup!(exp), arg) if sb && xiden!(exp, "h") => {
413 self.cover(simple.op, simple.first(), arg, '\u{036a}')
414 }
415 ("stackrel" | "overset", sgroup!(exp), arg) if sb && xiden!(exp, "m") => {
416 self.cover(simple.op, simple.first(), arg, '\u{036b}')
417 }
418 ("stackrel" | "overset", sgroup!(exp), arg) if sb && xiden!(exp, "r") => {
419 self.cover(simple.op, simple.first(), arg, '\u{036c}')
420 }
421 ("stackrel" | "overset", sgroup!(exp), arg) if sb && xiden!(exp, "t") => {
422 self.cover(simple.op, simple.first(), arg, '\u{036d}')
423 }
424 ("stackrel" | "overset", sgroup!(exp), arg) if sb && xiden!(exp, "v") => {
425 self.cover(simple.op, simple.first(), arg, '\u{036e}')
426 }
427 ("stackrel" | "overset", sgroup!(exp), arg) if sb && xiden!(exp, "x") => {
428 self.cover(simple.op, simple.first(), arg, '\u{036f}')
429 }
430 ("stackrel" | "overset", arg, symb!("=")) => match arg {
432 sgroup!(expr) if self.strip_brackets => {
433 let rendered = self.render_expression(expr);
434 self.render_equals(rendered.iter, simple.op, arg, simple.second())
435 }
436 arg => {
437 let rendered = self.render_simple(arg);
438 self.render_equals(rendered.iter, simple.op, arg, simple.second())
439 }
440 },
441 (op, first, second) => self.render_bgeneric(op, first, second),
443 }
444 }
445
446 #[inline]
447 fn render_font<'a>(
448 &self,
449 font: fn(char) -> char,
450 arg: &Simple<'a>,
451 ) -> RenderChars<SimpleUnaryIter<'a>> {
452 match arg {
453 sgroup!(expr) if self.strip_brackets => self
454 .render_expression(expr)
455 .map(|iter| SimpleUnaryIter::StrippedFont(Box::new(iter.map(font)))),
456 arg => self
457 .render_simple(arg)
458 .map(|iter| SimpleUnaryIter::Font(Box::new(iter.map(font)))),
459 }
460 }
461
462 #[inline]
463 fn render_sfunc<'a>(
464 &self,
465 open: &'a str,
466 arg: &Simple<'a>,
467 close: &'a str,
468 ) -> RenderChars<SimpleUnaryIter<'a>> {
469 match arg {
470 sgroup!(expr) if self.strip_brackets => RenderChars::from(open)
471 .chain(self.render_expression(expr).map(Box::new))
472 .chain(RenderChars::from(close))
473 .map(SimpleUnaryIter::StrippedWrapped),
474 arg => RenderChars::from(open)
475 .chain(self.render_simple(arg).map(Box::new))
476 .chain(RenderChars::from(close))
477 .map(SimpleUnaryIter::Wrapped),
478 }
479 }
480
481 #[inline]
482 fn render_mod<'a>(&self, chr: char, arg: &Simple<'a>) -> RenderChars<SimpleUnaryIter<'a>> {
483 match arg {
484 sgroup!(expr) if self.strip_brackets => self
485 .render_expression(expr)
486 .map(|iter| SimpleUnaryIter::StrippedModed(Box::new(Modified::new(iter, chr)))),
487 arg => self
488 .render_simple(arg)
489 .map(|iter| SimpleUnaryIter::Moded(Box::new(Modified::new(iter, chr)))),
490 }
491 }
492
493 #[inline]
494 fn render_char_mod<'a>(
495 &self,
496 op: &'a str,
497 chr: char,
498 arg: &Simple<'a>,
499 ) -> RenderChars<SimpleUnaryIter<'a>> {
500 match arg {
501 sgroup!(expr) if self.strip_brackets => {
502 let rendered = self.render_expression(expr);
503 if rendered.len == 1 {
504 rendered
505 .map(Box::new)
506 .chain(RenderChars::from(chr))
507 .map(SimpleUnaryIter::StrippedSingle)
508 } else {
509 self.render_ugeneric(op, arg)
510 }
511 }
512 arg => {
513 let rendered = self.render_simple(arg);
514 if rendered.len == 1 {
515 rendered
516 .map(Box::new)
517 .chain(RenderChars::from(chr))
518 .map(SimpleUnaryIter::Single)
519 } else {
520 self.render_ugeneric(op, arg)
521 }
522 }
523 }
524 }
525
526 #[inline]
527 fn render_ugeneric<'a>(
528 &self,
529 op: &'a str,
530 arg: &Simple<'a>,
531 ) -> RenderChars<SimpleUnaryIter<'a>> {
532 RenderChars::from(op)
533 .chain(RenderChars::from(' '))
534 .chain(self.render_simple(arg).map(Box::new))
535 .map(SimpleUnaryIter::Generic)
536 }
537
538 #[allow(clippy::too_many_lines)]
539 fn render_simpleunary<'a>(&self, simple: &SimpleUnary<'a>) -> RenderChars<SimpleUnaryIter<'a>> {
540 match (simple.op, simple.arg()) {
541 ("sqrt", arg) => RenderChars::from('√')
543 .chain(self.render_simple(arg).map(Box::new))
544 .map(SimpleUnaryIter::Simple),
545 ("bb" | "mathbf", arg) => self.render_font(bold_map, arg),
547 ("bbb" | "mathbb", arg) => self.render_font(double_map, arg),
548 ("cc" | "mathcal", arg) => self.render_font(cal_map, arg),
549 ("tt" | "mathtt", arg) => self.render_font(mono_map, arg),
550 ("fr" | "mathfrak", arg) => self.render_font(frak_map, arg),
551 ("sf" | "mathsf", arg) => self.render_font(sans_map, arg),
552 ("it" | "mathit", arg) => self.render_font(italic_map, arg),
553 ("abs" | "Abs", arg) => self.render_sfunc("|", arg, "|"),
555 ("ceil", arg) => self.render_sfunc("⌈", arg, "⌉"),
556 ("floor", arg) => self.render_sfunc("⌊", arg, "⌋"),
557 ("norm", arg) => self.render_sfunc("||", arg, "||"),
558 ("text", arg) => self.render_sfunc("", arg, ""),
559 ("overline", arg) => self.render_mod('\u{0305}', arg),
561 ("underline" | "ul", arg) => self.render_mod('\u{0332}', arg),
562 (o @ "hat", arg) => self.render_char_mod(o, '\u{0302}', arg),
564 (o @ "tilde", arg) => self.render_char_mod(o, '\u{0303}', arg),
565 (o @ "bar", arg) => self.render_char_mod(o, '\u{0304}', arg),
566 (o @ "dot", arg) => self.render_char_mod(o, '\u{0307}', arg),
567 (o @ "ddot", arg) => self.render_char_mod(o, '\u{0308}', arg),
568 (o @ ("overarc" | "overparen"), arg) => self.render_char_mod(o, '\u{0311}', arg),
569 (op, arg) => self.render_ugeneric(op, arg),
571 }
572 }
573
574 fn render_matrix<'a>(&self, matrix: &Matrix<'a>) -> RenderChars<MatIter<'a>> {
575 let num_cols = matrix.num_cols();
576 let num_rows = matrix.num_rows();
577 let left_rend = RenderChars::from(left_bracket_str(matrix.left_bracket));
578 let right_rend = RenderChars::from(right_bracket_str(matrix.right_bracket));
579
580 let mut rendered = Vec::with_capacity(matrix.num_rows());
581 let mut len =
582 (num_rows + 1) * (left_rend.len + right_rend.len) + (num_rows - 1) * (num_cols - 1);
583 for row in matrix.rows() {
584 let mut rends = Vec::with_capacity(row.len());
585 for expr in row {
586 let rend = self.render_expression(expr);
587 len += rend.len;
588 rends.push(rend.iter);
589 }
590 rendered.push(
591 left_rend
592 .iter
593 .clone()
594 .chain(Interleave::new(rends, ','))
595 .chain(right_rend.iter.clone()),
596 );
597 }
598 RenderChars {
599 iter: left_rend
600 .iter
601 .chain(Box::new(Interleave::new(rendered, ',')))
602 .chain(right_rend.iter),
603 len,
604 sub: false,
605 sup: false,
606 }
607 }
608
609 fn render_group<'a>(&self, group: &Group<'a>) -> RenderChars<GroupIter<'a>> {
610 RenderChars::from(left_bracket_str(group.left_bracket))
611 .chain(self.render_expression(&group.expr).map(Box::new))
612 .chain(RenderChars::from(right_bracket_str(group.right_bracket)))
613 }
614
615 fn render_simple<'a>(&self, simple: &Simple<'a>) -> RenderChars<SimpleIter<'a>> {
616 match simple {
617 Simple::Missing => RenderChars::from("").map(SimpleIter::Chars),
618 &Simple::Number(num) => RenderChars::from(num).map(SimpleIter::Chars),
619 &Simple::Text(text) => RenderChars::from(text).map(SimpleIter::Chars),
620 &Simple::Ident(ident) => RenderChars::from(ident).map(SimpleIter::Chars),
621 &Simple::Symbol(symbol) => {
622 RenderChars::from(symbol_str(symbol, self.skin_tone)).map(SimpleIter::Chars)
623 }
624 Simple::Func(func) => self.render_simplefunc(func).map(SimpleIter::Func),
625 Simple::Unary(unary) => self.render_simpleunary(unary).map(SimpleIter::Unary),
626 Simple::Binary(binary) => self.render_simplebinary(binary).map(SimpleIter::Binary),
627 Simple::Group(group) => self.render_group(group).map(SimpleIter::Group),
628 Simple::Matrix(matrix) => self.render_matrix(matrix).map(SimpleIter::Matrix),
629 }
630 }
631
632 fn render_script<'a>(&self, script: &Script<'a>) -> RenderChars<ScriptIter<'a>> {
633 match script {
634 Script::None => RenderChars::from("").map(ScriptIter::Empty),
635 Script::Sub(sub) => {
636 let rendered = self.render_simple(sub);
637 if rendered.sub {
638 rendered
639 .map(|iter| ScriptIter::Mapped(iter.map(|c| subscript_char(c).unwrap())))
640 } else {
641 RenderChars::from('_')
642 .chain(rendered)
643 .map(ScriptIter::Untouched)
644 }
645 }
646 Script::Super(sup) => {
647 let rendered = self.render_simple(sup);
648 if rendered.sup {
649 rendered
650 .map(|iter| ScriptIter::Mapped(iter.map(|c| superscript_char(c).unwrap())))
651 } else {
652 RenderChars::from('^')
653 .chain(rendered)
654 .map(ScriptIter::Untouched)
655 }
656 }
657 Script::Subsuper(sub, supersc) => {
658 let rend_sub = self.render_simple(sub);
659 let rend_super = self.render_simple(supersc);
660 if rend_sub.sub && rend_super.sup {
661 rend_sub
662 .map(|iter| SimpMappedIter(iter.map(|c| subscript_char(c).unwrap())))
663 .chain(
664 rend_super.map(|iter| {
665 SimpMappedIter(iter.map(|c| superscript_char(c).unwrap()))
666 }),
667 )
668 .map(ScriptIter::SubsupMapped)
669 } else {
670 RenderChars::from('_')
671 .chain(rend_sub)
672 .chain(RenderChars::from('^'))
673 .chain(rend_super)
674 .map(ScriptIter::SubsupUntouched)
675 }
676 }
677 }
678 }
679
680 fn render_simplescript<'a>(
681 &self,
682 simple: &SimpleScript<'a>,
683 ) -> RenderChars<SimpleScriptIter<'a>> {
684 self.render_simple(&simple.simple)
685 .chain(self.render_script(&simple.script))
686 }
687
688 fn render_func<'a>(&self, func: &Func<'a>) -> RenderChars<FuncIter<'a>> {
689 RenderChars::from(func.func)
690 .chain(self.render_script(&func.script))
691 .chain(RenderChars::from(' '))
692 .chain(self.render_scriptfunc(func.arg()).map(Box::new))
693 }
694
695 fn render_scriptfunc<'a>(&self, func: &ScriptFunc<'a>) -> RenderChars<ScriptFuncIter<'a>> {
696 match func {
697 ScriptFunc::Simple(simple) => {
698 self.render_simplescript(simple).map(ScriptFuncIter::Simple)
699 }
700 ScriptFunc::Func(func) => self.render_func(func).map(ScriptFuncIter::Func),
701 }
702 }
703
704 #[inline]
705 fn render_sone<'a>(
706 &self,
707 num: &Simple<'a>,
708 den: &Simple<'a>,
709 ) -> RenderChars<SimpleFracIter<'a>> {
710 match den {
711 sgroup!(expr) if self.strip_brackets => {
712 let rend_den = self.render_expression(expr);
713 if rend_den.sub {
714 RenderChars::from('⅟')
715 .chain(rend_den.map(|iter| {
716 Box::new(ExprMappedIter(iter.map(|c| subscript_char(c).unwrap())))
717 }))
718 .map(SimpleFracIter::StrippedVulgOne)
719 } else {
720 gsfrac(self.render_simple(num), self.render_simple(den))
721 }
722 }
723 den => {
724 let rend_den = self.render_simple(den);
725 if rend_den.sub {
726 RenderChars::from('⅟')
727 .chain(
728 rend_den.map(|iter| {
729 SimpMappedIter(iter.map(|c| subscript_char(c).unwrap()))
730 }),
731 )
732 .map(SimpleFracIter::VulgOne)
733 } else {
734 gsfrac(self.render_simple(num), rend_den)
735 }
736 }
737 }
738 }
739
740 #[allow(clippy::too_many_lines)]
741 fn render_simplefrac<'a>(
742 &self,
743 numer: &Simple<'a>,
744 denom: &Simple<'a>,
745 ) -> RenderChars<SimpleFracIter<'a>> {
746 let vsf = self.vulgar_fracs && self.script_fracs;
747 let vs = self.vulgar_fracs && self.strip_brackets;
748 match (numer, denom) {
749 (num!("0"), num!("3")) if self.vulgar_fracs => vulg('↉'),
751 (num!("1"), num!("10")) if self.vulgar_fracs => vulg('⅒'),
752 (num!("1"), num!("9")) if self.vulgar_fracs => vulg('⅑'),
753 (num!("1"), num!("8")) if self.vulgar_fracs => vulg('⅛'),
754 (num!("1"), num!("7")) if self.vulgar_fracs => vulg('⅐'),
755 (num!("1"), num!("6")) if self.vulgar_fracs => vulg('⅙'),
756 (num!("1"), num!("5")) if self.vulgar_fracs => vulg('⅕'),
757 (num!("1"), num!("4")) if self.vulgar_fracs => vulg('¼'),
758 (num!("1"), num!("3")) if self.vulgar_fracs => vulg('⅓'),
759 (num!("1"), num!("2")) if self.vulgar_fracs => vulg('½'),
760 (num!("2"), num!("5")) if self.vulgar_fracs => vulg('⅖'),
761 (num!("2"), num!("3")) if self.vulgar_fracs => vulg('⅔'),
762 (num!("3"), num!("8")) if self.vulgar_fracs => vulg('⅜'),
763 (num!("3"), num!("5")) if self.vulgar_fracs => vulg('⅗'),
764 (num!("3"), num!("4")) if self.vulgar_fracs => vulg('¾'),
765 (num!("4"), num!("5")) if self.vulgar_fracs => vulg('⅘'),
766 (num!("5"), num!("8")) if self.vulgar_fracs => vulg('⅝'),
767 (num!("5"), num!("6")) if self.vulgar_fracs => vulg('⅚'),
768 (num!("7"), num!("8")) if self.vulgar_fracs => vulg('⅞'),
769 (sgroup!(num), num!("3")) if xnum!(num, "0") && vs => vulg('↉'),
770 (sgroup!(num), num!("10")) if xnum!(num, "1") && vs => vulg('⅒'),
771 (sgroup!(num), num!("9")) if xnum!(num, "1") && vs => vulg('⅑'),
772 (sgroup!(num), num!("8")) if xnum!(num, "1") && vs => vulg('⅛'),
773 (sgroup!(num), num!("7")) if xnum!(num, "1") && vs => vulg('⅐'),
774 (sgroup!(num), num!("6")) if xnum!(num, "1") && vs => vulg('⅙'),
775 (sgroup!(num), num!("5")) if xnum!(num, "1") && vs => vulg('⅕'),
776 (sgroup!(num), num!("4")) if xnum!(num, "1") && vs => vulg('¼'),
777 (sgroup!(num), num!("3")) if xnum!(num, "1") && vs => vulg('⅓'),
778 (sgroup!(num), num!("2")) if xnum!(num, "1") && vs => vulg('½'),
779 (sgroup!(num), num!("5")) if xnum!(num, "2") && vs => vulg('⅖'),
780 (sgroup!(num), num!("3")) if xnum!(num, "2") && vs => vulg('⅔'),
781 (sgroup!(num), num!("8")) if xnum!(num, "3") && vs => vulg('⅜'),
782 (sgroup!(num), num!("5")) if xnum!(num, "3") && vs => vulg('⅗'),
783 (sgroup!(num), num!("4")) if xnum!(num, "3") && vs => vulg('¾'),
784 (sgroup!(num), num!("5")) if xnum!(num, "4") && vs => vulg('⅘'),
785 (sgroup!(num), num!("8")) if xnum!(num, "5") && vs => vulg('⅝'),
786 (sgroup!(num), num!("6")) if xnum!(num, "5") && vs => vulg('⅚'),
787 (sgroup!(num), num!("8")) if xnum!(num, "7") && vs => vulg('⅞'),
788 (num!("0"), sgroup!(den)) if xnum!(den, "3") && vs => vulg('↉'),
789 (num!("1"), sgroup!(den)) if xnum!(den, "10") && vs => vulg('⅒'),
790 (num!("1"), sgroup!(den)) if xnum!(den, "9") && vs => vulg('⅑'),
791 (num!("1"), sgroup!(den)) if xnum!(den, "8") && vs => vulg('⅛'),
792 (num!("1"), sgroup!(den)) if xnum!(den, "7") && vs => vulg('⅐'),
793 (num!("1"), sgroup!(den)) if xnum!(den, "6") && vs => vulg('⅙'),
794 (num!("1"), sgroup!(den)) if xnum!(den, "5") && vs => vulg('⅕'),
795 (num!("1"), sgroup!(den)) if xnum!(den, "4") && vs => vulg('¼'),
796 (num!("1"), sgroup!(den)) if xnum!(den, "3") && vs => vulg('⅓'),
797 (num!("1"), sgroup!(den)) if xnum!(den, "2") && vs => vulg('½'),
798 (num!("2"), sgroup!(den)) if xnum!(den, "5") && vs => vulg('⅖'),
799 (num!("2"), sgroup!(den)) if xnum!(den, "3") && vs => vulg('⅔'),
800 (num!("3"), sgroup!(den)) if xnum!(den, "8") && vs => vulg('⅜'),
801 (num!("3"), sgroup!(den)) if xnum!(den, "5") && vs => vulg('⅗'),
802 (num!("3"), sgroup!(den)) if xnum!(den, "4") && vs => vulg('¾'),
803 (num!("4"), sgroup!(den)) if xnum!(den, "5") && vs => vulg('⅘'),
804 (num!("5"), sgroup!(den)) if xnum!(den, "8") && vs => vulg('⅝'),
805 (num!("5"), sgroup!(den)) if xnum!(den, "6") && vs => vulg('⅚'),
806 (num!("7"), sgroup!(den)) if xnum!(den, "8") && vs => vulg('⅞'),
807 (sgroup!(num), sgroup!(den)) if xnum!(num, "0") && xnum!(den, "3") && vs => vulg('↉'),
808 (sgroup!(num), sgroup!(den)) if xnum!(num, "1") && xnum!(den, "10") && vs => vulg('⅒'),
809 (sgroup!(num), sgroup!(den)) if xnum!(num, "1") && xnum!(den, "9") && vs => vulg('⅑'),
810 (sgroup!(num), sgroup!(den)) if xnum!(num, "1") && xnum!(den, "8") && vs => vulg('⅛'),
811 (sgroup!(num), sgroup!(den)) if xnum!(num, "1") && xnum!(den, "7") && vs => vulg('⅐'),
812 (sgroup!(num), sgroup!(den)) if xnum!(num, "1") && xnum!(den, "6") && vs => vulg('⅙'),
813 (sgroup!(num), sgroup!(den)) if xnum!(num, "1") && xnum!(den, "5") && vs => vulg('⅕'),
814 (sgroup!(num), sgroup!(den)) if xnum!(num, "1") && xnum!(den, "4") && vs => vulg('¼'),
815 (sgroup!(num), sgroup!(den)) if xnum!(num, "1") && xnum!(den, "3") && vs => vulg('⅓'),
816 (sgroup!(num), sgroup!(den)) if xnum!(num, "1") && xnum!(den, "2") && vs => vulg('½'),
817 (sgroup!(num), sgroup!(den)) if xnum!(num, "2") && xnum!(den, "5") && vs => vulg('⅖'),
818 (sgroup!(num), sgroup!(den)) if xnum!(num, "2") && xnum!(den, "3") && vs => vulg('⅔'),
819 (sgroup!(num), sgroup!(den)) if xnum!(num, "3") && xnum!(den, "8") && vs => vulg('⅜'),
820 (sgroup!(num), sgroup!(den)) if xnum!(num, "3") && xnum!(den, "5") && vs => vulg('⅗'),
821 (sgroup!(num), sgroup!(den)) if xnum!(num, "3") && xnum!(den, "4") && vs => vulg('¾'),
822 (sgroup!(num), sgroup!(den)) if xnum!(num, "4") && xnum!(den, "5") && vs => vulg('⅘'),
823 (sgroup!(num), sgroup!(den)) if xnum!(num, "5") && xnum!(den, "8") && vs => vulg('⅝'),
824 (sgroup!(num), sgroup!(den)) if xnum!(num, "5") && xnum!(den, "6") && vs => vulg('⅚'),
825 (sgroup!(num), sgroup!(den)) if xnum!(num, "7") && xnum!(den, "8") && vs => vulg('⅞'),
826 (iden!("a"), iden!("c")) if self.vulgar_fracs => vulg('℀'),
828 (iden!("a"), iden!("s")) if self.vulgar_fracs => vulg('℁'),
829 (iden!("A"), iden!("S")) if self.vulgar_fracs => vulg('⅍'),
830 (iden!("c"), iden!("o")) if self.vulgar_fracs => vulg('℅'),
831 (iden!("c"), iden!("u")) if self.vulgar_fracs => vulg('℆'),
832 (sgroup!(num), iden!("c")) if xiden!(num, "a") && vs => vulg('℀'),
833 (sgroup!(num), iden!("s")) if xiden!(num, "a") && vs => vulg('℁'),
834 (sgroup!(num), iden!("S")) if xiden!(num, "A") && vs => vulg('⅍'),
835 (sgroup!(num), iden!("o")) if xiden!(num, "c") && vs => vulg('℅'),
836 (sgroup!(num), iden!("u")) if xiden!(num, "c") && vs => vulg('℆'),
837 (iden!("a"), sgroup!(den)) if xiden!(den, "c") && vs => vulg('℀'),
838 (iden!("a"), sgroup!(den)) if xiden!(den, "s") && vs => vulg('℁'),
839 (iden!("A"), sgroup!(den)) if xiden!(den, "S") && vs => vulg('⅍'),
840 (iden!("c"), sgroup!(den)) if xiden!(den, "o") && vs => vulg('℅'),
841 (iden!("c"), sgroup!(den)) if xiden!(den, "u") && vs => vulg('℆'),
842 (sgroup!(num), sgroup!(den)) if xiden!(num, "a") && xiden!(den, "c") && vs => vulg('℀'),
843 (sgroup!(num), sgroup!(den)) if xiden!(num, "a") && xiden!(den, "s") && vs => vulg('℁'),
844 (sgroup!(num), sgroup!(den)) if xiden!(num, "A") && xiden!(den, "S") && vs => vulg('⅍'),
845 (sgroup!(num), sgroup!(den)) if xiden!(num, "c") && xiden!(den, "o") && vs => vulg('℅'),
846 (sgroup!(num), sgroup!(den)) if xiden!(num, "c") && xiden!(den, "u") && vs => vulg('℆'),
847 (num!("1"), den) if vsf => self.render_sone(numer, den),
849 (sgroup!(num), den) if vsf && self.strip_brackets && xnum!(num, "1") => {
850 self.render_sone(numer, den)
851 }
852 (sgroup!(num), sgroup!(den)) if self.strip_brackets && self.script_fracs => {
854 let rend_num = self.render_expression(num);
855 let rend_den = self.render_expression(den);
856 if rend_num.sup && rend_den.sub {
857 rend_num
858 .map(|iter| ExprMappedIter(iter.map(|c| superscript_char(c).unwrap())))
859 .chain(RenderChars::from('⁄'))
860 .chain(
861 rend_den.map(|iter| {
862 ExprMappedIter(iter.map(|c| subscript_char(c).unwrap()))
863 }),
864 )
865 .map(|iter| SimpleFracIter::StrippedScript(Box::new(iter)))
866 } else {
867 gsfrac(self.render_simple(numer), self.render_simple(denom))
868 }
869 }
870 (num, sgroup!(den)) if self.strip_brackets && self.script_fracs => {
871 let rend_num = self.render_simple(num);
872 let rend_den = self.render_expression(den);
873 if rend_num.sup && rend_den.sub {
874 rend_num
875 .map(|iter| SimpMappedIter(iter.map(|c| superscript_char(c).unwrap())))
876 .chain(RenderChars::from('⁄'))
877 .chain(rend_den.map(|iter| {
878 Box::new(ExprMappedIter(iter.map(|c| subscript_char(c).unwrap())))
879 }))
880 .map(SimpleFracIter::DenomStrippedScript)
881 } else {
882 gsfrac(rend_num, self.render_simple(denom))
883 }
884 }
885 (sgroup!(num), den) if self.strip_brackets && self.script_fracs => {
886 let rend_num = self.render_expression(num);
887 let rend_den = self.render_simple(den);
888 if rend_num.sup && rend_den.sub {
889 rend_num
890 .map(|iter| {
891 Box::new(ExprMappedIter(iter.map(|c| superscript_char(c).unwrap())))
892 })
893 .chain(RenderChars::from('⁄'))
894 .chain(
895 rend_den.map(|iter| {
896 SimpMappedIter(iter.map(|c| subscript_char(c).unwrap()))
897 }),
898 )
899 .map(SimpleFracIter::NumerStrippedScript)
900 } else {
901 gsfrac(self.render_simple(numer), rend_den)
902 }
903 }
904 (num, den) => {
905 let rend_num = self.render_simple(num);
906 let rend_den = self.render_simple(den);
907 if self.script_fracs && rend_num.sup && rend_den.sub {
908 rend_num
909 .map(|iter| SimpMappedIter(iter.map(|c| superscript_char(c).unwrap())))
910 .chain(RenderChars::from('⁄'))
911 .chain(
912 rend_den.map(|iter| {
913 SimpMappedIter(iter.map(|c| subscript_char(c).unwrap()))
914 }),
915 )
916 .map(SimpleFracIter::Script)
917 } else {
918 gsfrac(rend_num, rend_den)
919 }
920 }
921 }
922 }
923
924 #[inline]
925 fn render_fone<'a>(&self, den: &ScriptFunc<'a>) -> RenderChars<FracIter<'a>> {
926 let rend_den = self.render_scriptfunc(den);
927 if rend_den.sub {
928 RenderChars::from('⅟')
929 .chain(
930 rend_den.map(|iter| FuncMappedIter(iter.map(|c| subscript_char(c).unwrap()))),
931 )
932 .map(FracIter::VulgOne)
933 } else {
934 RenderChars::from("1/").chain(rend_den).map(FracIter::One)
935 }
936 }
937
938 #[allow(clippy::too_many_lines)]
939 fn render_frac<'a>(&self, frac: &Frac<'a>) -> RenderChars<FracIter<'a>> {
940 let sv = self.script_fracs && self.vulgar_fracs;
941 match (&frac.numer, &frac.denom) {
942 (script_func!(num), script_func!(den)) => {
944 self.render_simplefrac(num, den).map(FracIter::Simple)
945 }
946 (script_func!(num!("1")), den) if sv => self.render_fone(den),
948 (script_func!(sgroup!(num)), den) if sv && self.strip_brackets && xnum!(num, "1") => {
949 self.render_fone(den)
950 }
951 (script_func!(sgroup!(num)), den) if self.strip_brackets && self.script_fracs => {
953 let rend_num = self.render_expression(num);
954 let rend_den = self.render_scriptfunc(den);
955 if rend_num.sup && rend_den.sub {
956 rend_num
957 .map(|iter| {
958 Box::new(ExprMappedIter(iter.map(|c| superscript_char(c).unwrap())))
959 })
960 .chain(RenderChars::from('⁄'))
961 .chain(
962 rend_den.map(|iter| {
963 FuncMappedIter(iter.map(|c| subscript_char(c).unwrap()))
964 }),
965 )
966 .map(FracIter::NumerStrippedScript)
967 } else {
968 gfrac(self.render_scriptfunc(&frac.numer), rend_den)
969 }
970 }
971 (num, script_func!(sgroup!(den))) if self.strip_brackets && self.script_fracs => {
972 let rend_num = self.render_scriptfunc(num);
973 let rend_den = self.render_expression(den);
974 if rend_num.sup && rend_den.sub {
975 rend_num
976 .map(|iter| FuncMappedIter(iter.map(|c| superscript_char(c).unwrap())))
977 .chain(RenderChars::from('⁄'))
978 .chain(rend_den.map(|iter| {
979 Box::new(ExprMappedIter(iter.map(|c| subscript_char(c).unwrap())))
980 }))
981 .map(FracIter::DenomStrippedScript)
982 } else {
983 gfrac(rend_num, self.render_scriptfunc(&frac.denom))
984 }
985 }
986 (num, den) => {
987 let rend_num = self.render_scriptfunc(num);
988 let rend_den = self.render_scriptfunc(den);
989 if self.script_fracs && rend_num.sup && rend_den.sub {
990 rend_num
991 .map(|iter| FuncMappedIter(iter.map(|c| superscript_char(c).unwrap())))
992 .chain(RenderChars::from('⁄'))
993 .chain(
994 rend_den.map(|iter| {
995 FuncMappedIter(iter.map(|c| subscript_char(c).unwrap()))
996 }),
997 )
998 .map(FracIter::Script)
999 } else {
1000 gfrac(rend_num, rend_den)
1001 }
1002 }
1003 }
1004 }
1005
1006 fn render_intermediate<'a>(
1007 &self,
1008 inter: &Intermediate<'a>,
1009 ) -> RenderChars<IntermediateIter<'a>> {
1010 match inter {
1011 Intermediate::ScriptFunc(sf) => {
1012 self.render_scriptfunc(sf).map(IntermediateIter::ScriptFunc)
1013 }
1014 Intermediate::Frac(frac) => self.render_frac(frac).map(IntermediateIter::Frac),
1015 }
1016 }
1017
1018 fn render_expression<'a>(&self, expr: &Expression<'a>) -> RenderChars<ExpressionIter<'a>> {
1019 let inters: RenderChars<_> = expr
1020 .iter()
1021 .map(|inter| self.render_intermediate(inter))
1022 .collect();
1023 inters
1024 }
1025
1026 #[must_use]
1028 pub fn render<'a>(&self, inp: &'a str) -> RenderedUnicode<'a> {
1029 let parsed = parse_unicode(inp);
1030 let rendered = self.render_expression(&parsed);
1031 RenderedUnicode(rendered.iter)
1032 }
1033}
1034
1035#[derive(Debug, Clone)]
1040pub struct RenderedUnicode<'a>(ExpressionIter<'a>);
1041
1042impl Iterator for RenderedUnicode<'_> {
1043 type Item = char;
1044
1045 fn next(&mut self) -> Option<Self::Item> {
1046 self.0.next()
1047 }
1048}
1049
1050impl FusedIterator for RenderedUnicode<'_> {}
1051
1052impl RenderedUnicode<'_> {
1053 pub fn into_write<O: Write>(self, out: &mut O) -> io::Result<()> {
1061 for chr in self {
1062 write!(out, "{chr}")?;
1063 }
1064 Ok(())
1065 }
1066}
1067
1068impl fmt::Display for RenderedUnicode<'_> {
1069 fn fmt(&self, out: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
1070 for chr in self.clone() {
1071 write!(out, "{chr}")?;
1072 }
1073 Ok(())
1074 }
1075}
1076
1077#[must_use]
1079pub fn parse_unicode(inp: &str) -> Expression {
1080 asciimath_parser::parse_tokens(Tokenizer::with_tokens(inp, &*TOKEN_MAP, true))
1081}
1082
1083pub fn write_unicode<O: Write>(inp: &str, out: &mut O) -> io::Result<()> {
1089 InlineRenderer::default().render(inp).into_write(out)
1090}
1091
1092#[must_use]
1094pub fn convert_unicode(inp: &str) -> String {
1095 InlineRenderer::default().render(inp).collect()
1096}
1097
1098#[cfg(test)]
1099mod tests {
1100 use super::{InlineRenderer, SkinTone};
1101
1102 #[test]
1103 fn example() {
1104 let ex = "sum_(i=1)^n i^3=((n(n+1))/2)^2";
1105 let expected = "∑₍ᵢ₌₁₎ⁿi³=(ⁿ⁽ⁿ⁺¹⁾⁄₂)²";
1106
1107 let res = super::convert_unicode(ex);
1108 assert_eq!(res, expected);
1109
1110 let mut res = Vec::new();
1111 super::write_unicode(ex, &mut res).unwrap();
1112 assert_eq!(res, expected.as_bytes());
1113
1114 let rend = InlineRenderer::default().render(ex);
1115 assert_eq!(format!("{rend}"), expected);
1116
1117 let mut res = Vec::new();
1118 rend.into_write(&mut res).unwrap();
1119 assert_eq!(res, expected.as_bytes());
1120 }
1121
1122 #[test]
1123 fn vulgar_fracs() {
1124 let opts = InlineRenderer {
1125 vulgar_fracs: true,
1126 ..Default::default()
1127 };
1128 let res: String = opts.render("1/2").collect();
1129 assert_eq!(res, "½");
1130
1131 let res: String = opts.render("a / s").collect();
1132 assert_eq!(res, "℁");
1133 }
1134
1135 #[test]
1136 fn stripped_vulgar_fracs() {
1137 let opts = InlineRenderer {
1138 vulgar_fracs: true,
1139 strip_brackets: true,
1140 ..Default::default()
1141 };
1142 let res: String = opts.render("(1)/2").collect();
1143 assert_eq!(res, "½");
1144
1145 let res: String = opts.render("7/[8]").collect();
1146 assert_eq!(res, "⅞");
1147
1148 let res: String = opts.render("{a} / (s)").collect();
1149 assert_eq!(res, "℁");
1150 }
1151
1152 #[test]
1153 fn script_fracs() {
1154 let opts = InlineRenderer {
1155 script_fracs: true,
1156 strip_brackets: false,
1157 ..Default::default()
1158 };
1159 let res: String = opts.render("y / x").collect();
1160 assert_eq!(res, "ʸ⁄ₓ");
1161
1162 let res: String = opts.render("(y) / x").collect();
1163 assert_eq!(res, "⁽ʸ⁾⁄ₓ");
1164 }
1165
1166 #[test]
1167 fn stripped_script_fracs() {
1168 let opts = InlineRenderer {
1169 script_fracs: true,
1170 ..Default::default()
1171 };
1172
1173 let res: String = opts.render("(y) / x").collect();
1174 assert_eq!(res, "ʸ⁄ₓ");
1175
1176 let res: String = opts.render("y / [x]").collect();
1177 assert_eq!(res, "ʸ⁄ₓ");
1178
1179 let res: String = opts.render("(y)/[x]").collect();
1180 assert_eq!(res, "ʸ⁄ₓ");
1181 }
1182
1183 #[test]
1184 fn one_fracs() {
1185 let res = super::convert_unicode("1/x");
1186 assert_eq!(res, "⅟ₓ");
1187
1188 let res = super::convert_unicode("1 / sinx");
1189 assert_eq!(res, "⅟ₛᵢₙ ₓ");
1190
1191 let opts = InlineRenderer {
1192 script_fracs: false,
1193 vulgar_fracs: false,
1194 strip_brackets: false,
1195 ..Default::default()
1196 };
1197 let res: String = opts.render("1 / sinx").collect();
1198 assert_eq!(res, "1/sin x");
1199 }
1200
1201 #[test]
1202 fn normal_fracs() {
1203 let opts = InlineRenderer {
1204 script_fracs: false,
1205 vulgar_fracs: false,
1206 strip_brackets: false,
1207 ..Default::default()
1208 };
1209
1210 let res: String = opts.render("sinx / cosy").collect();
1211 assert_eq!(res, "sin x/cos y");
1212 }
1213
1214 #[test]
1215 fn unary() {
1216 let res = super::convert_unicode("sqrt x");
1217 assert_eq!(res, "√x");
1218
1219 let res = super::convert_unicode("vec x");
1220 assert_eq!(res, "vec x");
1221
1222 let res = super::convert_unicode("bbb E");
1223 assert_eq!(res, "𝔼");
1224
1225 let res = super::convert_unicode("bbb (E)");
1226 assert_eq!(res, "𝔼");
1227
1228 let res = super::convert_unicode("dot x");
1229 assert_eq!(res, "ẋ");
1230
1231 let res = super::convert_unicode("dot{x}");
1232 assert_eq!(res, "ẋ");
1233
1234 let res = super::convert_unicode("norm x");
1235 assert_eq!(res, "||x||");
1236
1237 let res = super::convert_unicode("sqrt overline x");
1238 assert_eq!(res, "√x̅");
1239
1240 let res = super::convert_unicode("sqrt overline(x)");
1241 assert_eq!(res, "√x̅");
1242 }
1243
1244 #[test]
1245 fn binary() {
1246 let res = super::convert_unicode("root 3 x");
1247 assert_eq!(res, "∛x");
1248
1249 let res = super::convert_unicode("root {4} x");
1250 assert_eq!(res, "∜x");
1251
1252 let res = super::convert_unicode("stackrel *** =");
1253 assert_eq!(res, "≛");
1254
1255 let res = super::convert_unicode("overset a x");
1256 assert_eq!(res, "x\u{0363}");
1257
1258 let res = super::convert_unicode("overset (e) {y}");
1259 assert_eq!(res, "y\u{0364}");
1260
1261 let res = super::convert_unicode("oversetasinx");
1262 assert_eq!(res, "overset a sin x");
1263 }
1264
1265 #[test]
1266 fn functions() {
1267 let res = super::convert_unicode("sin x/x");
1268 assert_eq!(res, "ˢⁱⁿ ˣ⁄ₓ");
1269 }
1270
1271 #[test]
1272 fn script() {
1273 let res = super::convert_unicode("x^sin x");
1274 assert_eq!(res, "xˢⁱⁿ ˣ");
1275
1276 let res = super::convert_unicode("x^vec(x)");
1277 assert_eq!(res, "xᵛᵉᶜ ⁽ˣ⁾");
1278
1279 let res = super::convert_unicode("x_x^y");
1280 assert_eq!(res, "xₓʸ");
1281
1282 let res = super::convert_unicode("x_y^sin x");
1283 assert_eq!(res, "x_y^sin x");
1284
1285 let res = super::convert_unicode("x^sin rho");
1286 assert_eq!(res, "x^sin ρ");
1287
1288 let res = super::convert_unicode("x_x");
1289 assert_eq!(res, "xₓ");
1290
1291 let res = super::convert_unicode("x_y");
1292 assert_eq!(res, "x_y");
1293 }
1294
1295 #[test]
1296 fn text() {
1297 let res = super::convert_unicode("\"text\"");
1298 assert_eq!(res, "text");
1299 }
1300
1301 #[test]
1302 fn matrix() {
1303 let opts = InlineRenderer::default();
1304
1305 let res: String = opts.render("[ [x, y], [a, b] ]").collect();
1306 assert_eq!(res, "[[x,y],[a,b]]");
1307 }
1308
1309 #[test]
1310 fn skin_tone() {
1311 let opts = InlineRenderer {
1312 skin_tone: SkinTone::Default,
1313 ..Default::default()
1314 };
1315 let res: String = opts.render(":hand:").collect();
1316 assert_eq!(res, "✋");
1317
1318 let opts = InlineRenderer {
1319 skin_tone: SkinTone::Dark,
1320 ..Default::default()
1321 };
1322 let res: String = opts.render(":hand:").collect();
1323 assert_eq!(res, "✋🏿");
1324 }
1325}