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", "\\grave", "\\ddot", "\\tilde", "\\bar", "\\breve",
9 "\\check", "\\hat", "\\vec", "\\dot", "\\mathring",
10];
11
12pub fn register(map: &mut HashMap<&'static str, FunctionSpec>) {
13 define_function_full(
15 map,
16 &[
17 "\\acute", "\\grave", "\\ddot", "\\tilde", "\\bar", "\\breve",
18 "\\check", "\\hat", "\\vec", "\\dot", "\\mathring", "\\widecheck",
19 "\\widehat", "\\widetilde", "\\overrightarrow", "\\overleftarrow",
20 "\\Overrightarrow", "\\overleftrightarrow", "\\overgroup",
21 "\\overlinesegment", "\\overleftharpoon", "\\overrightharpoon",
22 ],
23 "accent",
24 1, 0, None,
25 false, false, true, false, false,
26 handle_accent,
27 );
28
29 define_function_full(
31 map,
32 &[
33 "\\'", "\\`", "\\^", "\\~", "\\=", "\\u", "\\.", "\\\"",
34 "\\c", "\\r", "\\H", "\\v", "\\textcircled",
35 ],
36 "accent",
37 1, 0,
38 Some(vec![ArgType::Primitive]),
39 false,
40 true, true, false, false,
43 handle_text_accent,
44 );
45
46 define_function_full(
48 map,
49 &[
50 "\\underleftarrow", "\\underrightarrow", "\\underleftrightarrow",
51 "\\undergroup", "\\underlinesegment", "\\utilde",
52 ],
53 "accentUnder",
54 1, 0, None,
55 false, false, true, false, false,
56 handle_accent_under,
57 );
58}
59
60fn handle_accent(
61 ctx: &mut FunctionContext,
62 args: Vec<ParseNode>,
63 _opt_args: Vec<Option<ParseNode>>,
64) -> ParseResult<ParseNode> {
65 let base = ParseNode::normalize_argument(args.into_iter().next().unwrap());
66 let func_name = &ctx.func_name;
67 let is_stretchy = !NON_STRETCHY.contains(&func_name.as_str());
68 let is_shifty = !is_stretchy
69 || func_name == "\\widehat"
70 || func_name == "\\widetilde"
71 || func_name == "\\widecheck";
72
73 Ok(ParseNode::Accent {
74 mode: ctx.parser.mode,
75 label: func_name.clone(),
76 is_stretchy: Some(is_stretchy),
77 is_shifty: Some(is_shifty),
78 base: Box::new(base),
79 loc: None,
80 })
81}
82
83fn handle_text_accent(
84 ctx: &mut FunctionContext,
85 args: Vec<ParseNode>,
86 _opt_args: Vec<Option<ParseNode>>,
87) -> ParseResult<ParseNode> {
88 let base = args.into_iter().next().unwrap();
89 let mode = Mode::Text;
91
92 Ok(ParseNode::Accent {
93 mode,
94 label: ctx.func_name.clone(),
95 is_stretchy: Some(false),
96 is_shifty: Some(true),
97 base: Box::new(base),
98 loc: None,
99 })
100}
101
102fn handle_accent_under(
103 ctx: &mut FunctionContext,
104 args: Vec<ParseNode>,
105 _opt_args: Vec<Option<ParseNode>>,
106) -> ParseResult<ParseNode> {
107 let base = args.into_iter().next().unwrap();
108
109 Ok(ParseNode::AccentUnder {
110 mode: ctx.parser.mode,
111 label: ctx.func_name.clone(),
112 is_stretchy: Some(true),
113 is_shifty: Some(false),
114 base: Box::new(base),
115 loc: None,
116 })
117}