Skip to main content

ratex_parser/functions/
font.rs

1use std::collections::HashMap;
2
3use crate::error::ParseResult;
4use crate::functions::{define_function_full, ArgType, FunctionContext, FunctionSpec};
5use crate::parse_node::ParseNode;
6
7pub fn register(map: &mut HashMap<&'static str, FunctionSpec>) {
8    define_function_full(
9        map,
10        &[
11            "\\mathrm", "\\mathit", "\\mathbf", "\\mathnormal", "\\mathsfit",
12            "\\mathbb", "\\mathcal", "\\mathfrak", "\\mathscr", "\\mathsf",
13            "\\mathtt",
14            "\\Bbb", "\\bold", "\\frak",
15        ],
16        "font",
17        1, 0, None,
18        true,  // allowed_in_argument
19        false, true, false, false,
20        handle_font,
21    );
22
23    // \boldsymbol and \bm produce mclass nodes
24    define_function_full(
25        map,
26        &["\\boldsymbol", "\\bm"],
27        "mclass",
28        1, 0, None,
29        false, false, true, false, false,
30        handle_boldsymbol,
31    );
32
33    // \emph — emphasis (italic in text mode)
34    define_function_full(
35        map,
36        &["\\emph"],
37        "text",
38        1, 0,
39        Some(vec![ArgType::Text]),
40        false,
41        true, true,
42        false, false,
43        handle_emph,
44    );
45
46    // Old-style font switching commands: \rm, \sf, \tt, \bf, \it, \cal
47    define_function_full(
48        map,
49        &["\\rm", "\\sf", "\\tt", "\\bf", "\\it", "\\cal"],
50        "font",
51        0, 0, None,
52        false,
53        true, true,
54        false, false,
55        handle_old_font,
56    );
57}
58
59fn handle_font(
60    ctx: &mut FunctionContext,
61    args: Vec<ParseNode>,
62    _opt_args: Vec<Option<ParseNode>>,
63) -> ParseResult<ParseNode> {
64    let body = ParseNode::normalize_argument(args.into_iter().next().unwrap());
65
66    let font_aliases: &[(&str, &str)] = &[
67        ("\\Bbb", "\\mathbb"),
68        ("\\bold", "\\mathbf"),
69        ("\\frak", "\\mathfrak"),
70        ("\\bm", "\\boldsymbol"),
71    ];
72
73    let mut func = ctx.func_name.clone();
74    for &(alias, target) in font_aliases {
75        if func == alias {
76            func = target.to_string();
77            break;
78        }
79    }
80
81    let font_name = func.strip_prefix('\\').unwrap_or(func.as_str()).to_string();
82
83    Ok(ParseNode::Font {
84        mode: ctx.parser.mode,
85        font: font_name,
86        body: Box::new(body),
87        loc: None,
88    })
89}
90
91fn handle_old_font(
92    ctx: &mut FunctionContext,
93    _args: Vec<ParseNode>,
94    _opt_args: Vec<Option<ParseNode>>,
95) -> ParseResult<ParseNode> {
96    let font_name = format!("math{}", &ctx.func_name[1..]);
97    let break_on = ctx.break_on_token_text.clone();
98    let body = ctx.parser.parse_expression(true, break_on.as_deref())?;
99
100    Ok(ParseNode::Font {
101        mode: ctx.parser.mode,
102        font: font_name,
103        body: Box::new(ParseNode::OrdGroup {
104            mode: ctx.parser.mode,
105            body,
106            semisimple: None,
107            loc: None,
108        }),
109        loc: None,
110    })
111}
112
113fn handle_boldsymbol(
114    ctx: &mut FunctionContext,
115    args: Vec<ParseNode>,
116    _opt_args: Vec<Option<ParseNode>>,
117) -> ParseResult<ParseNode> {
118    let body = args.into_iter().next().unwrap();
119
120    Ok(ParseNode::MClass {
121        mode: ctx.parser.mode,
122        mclass: "mord".to_string(),
123        body: vec![ParseNode::Font {
124            mode: ctx.parser.mode,
125            font: "boldsymbol".to_string(),
126            body: Box::new(body),
127            loc: None,
128        }],
129        is_character_box: false,
130        loc: None,
131    })
132}
133
134fn handle_emph(
135    ctx: &mut FunctionContext,
136    args: Vec<ParseNode>,
137    _opt_args: Vec<Option<ParseNode>>,
138) -> ParseResult<ParseNode> {
139    let body = args.into_iter().next().unwrap();
140    let body_vec = ParseNode::ord_argument(body);
141    Ok(ParseNode::Text {
142        mode: ctx.parser.mode,
143        body: body_vec,
144        font: Some("\\emph".to_string()),
145        loc: None,
146    })
147}