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",
12 "\\mathit",
13 "\\mathbf",
14 "\\mathnormal",
15 "\\mathsfit",
16 "\\mathbb",
17 "\\mathcal",
18 "\\mathfrak",
19 "\\mathscr",
20 "\\mathsf",
21 "\\mathtt",
22 "\\Bbb",
23 "\\bold",
24 "\\frak",
25 ],
26 "font",
27 1,
28 0,
29 None,
30 true, false,
32 true,
33 false,
34 false,
35 handle_font,
36 );
37
38 define_function_full(
40 map,
41 &["\\boldsymbol", "\\bm"],
42 "mclass",
43 1,
44 0,
45 None,
46 false,
47 false,
48 true,
49 false,
50 false,
51 handle_boldsymbol,
52 );
53
54 define_function_full(
56 map,
57 &["\\emph"],
58 "text",
59 1,
60 0,
61 Some(vec![ArgType::Text]),
62 false,
63 true,
64 true,
65 false,
66 false,
67 handle_emph,
68 );
69
70 define_function_full(
72 map,
73 &["\\rm", "\\sf", "\\tt", "\\bf", "\\it", "\\cal"],
74 "font",
75 0,
76 0,
77 None,
78 false,
79 true,
80 true,
81 false,
82 false,
83 handle_old_font,
84 );
85}
86
87fn handle_font(
88 ctx: &mut FunctionContext,
89 args: Vec<ParseNode>,
90 _opt_args: Vec<Option<ParseNode>>,
91) -> ParseResult<ParseNode> {
92 let body = ParseNode::normalize_argument(args.into_iter().next().unwrap());
93
94 let font_aliases: &[(&str, &str)] = &[
95 ("\\Bbb", "\\mathbb"),
96 ("\\bold", "\\mathbf"),
97 ("\\frak", "\\mathfrak"),
98 ("\\bm", "\\boldsymbol"),
99 ];
100
101 let mut func = ctx.func_name.clone();
102 for &(alias, target) in font_aliases {
103 if func == alias {
104 func = target.to_string();
105 break;
106 }
107 }
108
109 let font_name = func.strip_prefix('\\').unwrap_or(func.as_str()).to_string();
110
111 Ok(ParseNode::Font {
112 mode: ctx.parser.mode,
113 font: font_name,
114 body: Box::new(body),
115 loc: None,
116 })
117}
118
119fn handle_old_font(
120 ctx: &mut FunctionContext,
121 _args: Vec<ParseNode>,
122 _opt_args: Vec<Option<ParseNode>>,
123) -> ParseResult<ParseNode> {
124 let font_name = format!("math{}", &ctx.func_name[1..]);
125 let break_on = ctx.break_on_token_text.clone();
126 let body = ctx.parser.parse_expression(true, break_on.as_deref())?;
127
128 Ok(ParseNode::Font {
129 mode: ctx.parser.mode,
130 font: font_name,
131 body: Box::new(ParseNode::OrdGroup {
132 mode: ctx.parser.mode,
133 body,
134 semisimple: None,
135 loc: None,
136 }),
137 loc: None,
138 })
139}
140
141fn handle_boldsymbol(
142 ctx: &mut FunctionContext,
143 args: Vec<ParseNode>,
144 _opt_args: Vec<Option<ParseNode>>,
145) -> ParseResult<ParseNode> {
146 let body = args.into_iter().next().unwrap();
147
148 Ok(ParseNode::MClass {
149 mode: ctx.parser.mode,
150 mclass: "mord".to_string(),
151 body: vec![ParseNode::Font {
152 mode: ctx.parser.mode,
153 font: "boldsymbol".to_string(),
154 body: Box::new(body),
155 loc: None,
156 }],
157 is_character_box: false,
158 loc: None,
159 })
160}
161
162fn handle_emph(
163 ctx: &mut FunctionContext,
164 args: Vec<ParseNode>,
165 _opt_args: Vec<Option<ParseNode>>,
166) -> ParseResult<ParseNode> {
167 let body = args.into_iter().next().unwrap();
168 let body_vec = ParseNode::ord_argument(body);
169 Ok(ParseNode::Text {
170 mode: ctx.parser.mode,
171 body: body_vec,
172 font: Some("\\emph".to_string()),
173 loc: None,
174 })
175}