1use std::collections::HashMap;
2
3use crate::error::ParseResult;
4use crate::functions::{define_function_full, ArgType, FunctionContext, FunctionSpec};
5use crate::parse_node::{Mode, ParseNode};
6
7static NON_STRETCHY: &[&str] = &[
8 "\\acute",
9 "\\grave",
10 "\\ddot",
11 "\\tilde",
12 "\\bar",
13 "\\breve",
14 "\\check",
15 "\\hat",
16 "\\vec",
17 "\\dot",
18 "\\mathring",
19];
20
21pub fn register(map: &mut HashMap<&'static str, FunctionSpec>) {
22 define_function_full(
24 map,
25 &[
26 "\\acute",
27 "\\grave",
28 "\\ddot",
29 "\\tilde",
30 "\\bar",
31 "\\breve",
32 "\\check",
33 "\\hat",
34 "\\vec",
35 "\\dot",
36 "\\mathring",
37 "\\widecheck",
38 "\\widehat",
39 "\\widetilde",
40 "\\overrightarrow",
41 "\\overleftarrow",
42 "\\Overrightarrow",
43 "\\overleftrightarrow",
44 "\\overgroup",
45 "\\overlinesegment",
46 "\\overleftharpoon",
47 "\\overrightharpoon",
48 ],
49 "accent",
50 1,
51 0,
52 None,
53 false,
54 false,
55 true,
56 false,
57 false,
58 handle_accent,
59 );
60
61 define_function_full(
63 map,
64 &[
65 "\\'",
66 "\\`",
67 "\\^",
68 "\\~",
69 "\\=",
70 "\\u",
71 "\\.",
72 "\\\"",
73 "\\c",
74 "\\r",
75 "\\H",
76 "\\v",
77 "\\textcircled",
78 ],
79 "accent",
80 1,
81 0,
82 Some(vec![ArgType::Primitive]),
83 false,
84 true, true, false,
87 false,
88 handle_text_accent,
89 );
90
91 define_function_full(
93 map,
94 &[
95 "\\underleftarrow",
96 "\\underrightarrow",
97 "\\underleftrightarrow",
98 "\\undergroup",
99 "\\underlinesegment",
100 "\\utilde",
101 ],
102 "accentUnder",
103 1,
104 0,
105 None,
106 false,
107 false,
108 true,
109 false,
110 false,
111 handle_accent_under,
112 );
113}
114
115fn handle_accent(
116 ctx: &mut FunctionContext,
117 args: Vec<ParseNode>,
118 _opt_args: Vec<Option<ParseNode>>,
119) -> ParseResult<ParseNode> {
120 let base = ParseNode::normalize_argument(args.into_iter().next().unwrap());
121 let func_name = &ctx.func_name;
122 let is_stretchy = !NON_STRETCHY.contains(&func_name.as_str());
123 let is_shifty = !is_stretchy
124 || func_name == "\\widehat"
125 || func_name == "\\widetilde"
126 || func_name == "\\widecheck";
127
128 Ok(ParseNode::Accent {
129 mode: ctx.parser.mode,
130 label: func_name.clone(),
131 is_stretchy: Some(is_stretchy),
132 is_shifty: Some(is_shifty),
133 base: Box::new(base),
134 loc: None,
135 })
136}
137
138fn handle_text_accent(
139 ctx: &mut FunctionContext,
140 args: Vec<ParseNode>,
141 _opt_args: Vec<Option<ParseNode>>,
142) -> ParseResult<ParseNode> {
143 let base = args.into_iter().next().unwrap();
144 let mode = Mode::Text;
146
147 Ok(ParseNode::Accent {
148 mode,
149 label: ctx.func_name.clone(),
150 is_stretchy: Some(false),
151 is_shifty: Some(true),
152 base: Box::new(base),
153 loc: None,
154 })
155}
156
157fn handle_accent_under(
158 ctx: &mut FunctionContext,
159 args: Vec<ParseNode>,
160 _opt_args: Vec<Option<ParseNode>>,
161) -> ParseResult<ParseNode> {
162 let base = args.into_iter().next().unwrap();
163
164 Ok(ParseNode::AccentUnder {
165 mode: ctx.parser.mode,
166 label: ctx.func_name.clone(),
167 is_stretchy: Some(true),
168 is_shifty: Some(false),
169 base: Box::new(base),
170 loc: None,
171 })
172}