asciimath_unicode/lib.rs
1//! A module for converting asciimath to unicode
2//!
3//! To convert asciimath quickly, you can use [`parse_unicode`] to get an [`Asciimath`] value that
4//! implements [`fmt::Display`]. If you want more control, see the options exposed through [`Conf`]
5//! which can [`parse`][Conf::parse] input into [`Asciimath`] as well.
6//!
7//! # Usage
8//!
9//! ## Binary
10//!
11//! This crate provides a simple cli for converting asciimath to unicode:
12//!
13//! ```bash
14//! cargo install asciimath-unicode --features binary
15//! ```
16//!
17//! ```bash
18//! asciimath-unicode -h
19//! ```
20//!
21//! ## Library
22//!
23//! ```bash
24//! cargo add asciimath-unicode
25//! ```
26//!
27//! ```
28//! let res = asciimath_unicode::parse_unicode("1/2").to_string();
29//! assert_eq!(res, "½");
30//! ```
31//!
32//! ```
33//! use asciimath_unicode::Conf;
34//! let conf = Conf {
35//! vulgar_fracs: false,
36//! ..Default::default()
37//! };
38//! let res = conf.parse("1/2").to_string();
39//! assert_eq!(res, "¹⁄₂");
40//! ```
41#![forbid(unsafe_code)]
42#![warn(clippy::pedantic, missing_docs)]
43
44mod ast;
45mod block;
46mod inline;
47mod tokens;
48
49use asciimath_parser::tree::Expression;
50pub use emojis::SkinTone;
51use inline::Mapper;
52use std::fmt;
53
54/// Configuration for unicode rendering of asciimath
55#[derive(Debug, Clone, Copy, PartialEq, Eq)]
56#[allow(clippy::struct_excessive_bools)]
57pub struct Conf {
58 /// If true, this will strip unnecessary parenthesis in some contexts
59 pub strip_brackets: bool,
60 /// If true, this will try to render fractions as vulgar fractions
61 pub vulgar_fracs: bool,
62 /// If true, this will try to render fractions using super- and sub-scripts
63 pub script_fracs: bool,
64 /// Default skin tone for emojis
65 pub skin_tone: SkinTone,
66 /// If true, render as multi-line 2D block (stacked fractions, vertical scripts, matrix grids)
67 pub block: bool,
68}
69
70impl Default for Conf {
71 fn default() -> Self {
72 Conf {
73 strip_brackets: true,
74 vulgar_fracs: true,
75 script_fracs: true,
76 skin_tone: SkinTone::Default,
77 block: false,
78 }
79 }
80}
81
82impl Conf {
83 /// Parse an asciimath string into an [`Asciimath`] value that implements [`fmt::Display`]
84 #[must_use]
85 pub fn parse(self, inp: &str) -> Asciimath<'_> {
86 Asciimath {
87 conf: self,
88 expr: tokens::parse(inp),
89 }
90 }
91}
92
93/// Parsed asciimath expression ready for rendering
94///
95/// Implements [`fmt::Display`] so it can be used with `format!`, `write!`, or `.to_string()`.
96#[derive(Debug, Clone)]
97pub struct Asciimath<'a> {
98 /// Rendering configuration
99 pub conf: Conf,
100 /// The parsed expression
101 pub expr: Expression<'a>,
102}
103
104impl fmt::Display for Asciimath<'_> {
105 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106 if self.conf.block {
107 let block = self.conf.block_expression(&self.expr);
108 write!(f, "{block}")
109 } else {
110 self.conf.inline_expression(&self.expr, &mut Mapper::new(f))
111 }
112 }
113}
114
115/// Parse asciimath into an [`Asciimath`] value that implements [`fmt::Display`]
116#[must_use]
117pub fn parse_unicode(inp: &str) -> Asciimath<'_> {
118 Conf::default().parse(inp)
119}