Skip to main content

ratex_parser/functions/
accent.rs

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    // Math-mode accents
23    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    // Text-mode accents
62    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, // allowed_in_text
85        true, // allowed_in_math
86        false,
87        false,
88        handle_text_accent,
89    );
90
91    // Under-accents
92    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    // Text accents always produce text-mode nodes, even in math mode
145    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}