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, false, true, false, false,
20 handle_font,
21 );
22
23 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 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 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}