use std::collections::HashMap;
use crate::error::ParseResult;
use crate::functions::{define_function_full, ArgType, FunctionContext, FunctionSpec};
use crate::parse_node::{Mode, ParseNode};
static NON_STRETCHY: &[&str] = &[
"\\acute",
"\\grave",
"\\ddot",
"\\tilde",
"\\bar",
"\\breve",
"\\check",
"\\hat",
"\\vec",
"\\dot",
"\\mathring",
"\\dddot",
"\\ddddot",
];
pub fn register(map: &mut HashMap<&'static str, FunctionSpec>) {
define_function_full(
map,
&[
"\\acute",
"\\grave",
"\\ddot",
"\\tilde",
"\\bar",
"\\breve",
"\\check",
"\\hat",
"\\vec",
"\\dot",
"\\mathring",
"\\dddot",
"\\ddddot",
"\\widecheck",
"\\widehat",
"\\widetilde",
"\\overrightarrow",
"\\overleftarrow",
"\\Overrightarrow",
"\\overleftrightarrow",
"\\overgroup",
"\\overlinesegment",
"\\overleftharpoon",
"\\overrightharpoon",
],
"accent",
1,
0,
None,
false,
false,
true,
false,
false,
handle_accent,
);
define_function_full(
map,
&[
"\\'",
"\\`",
"\\^",
"\\~",
"\\=",
"\\u",
"\\.",
"\\\"",
"\\c",
"\\r",
"\\H",
"\\v",
"\\textcircled",
],
"accent",
1,
0,
Some(vec![ArgType::Primitive]),
false,
true, true, false,
false,
handle_text_accent,
);
define_function_full(
map,
&[
"\\underleftarrow",
"\\underrightarrow",
"\\underleftrightarrow",
"\\undergroup",
"\\underlinesegment",
"\\utilde",
],
"accentUnder",
1,
0,
None,
false,
false,
true,
false,
false,
handle_accent_under,
);
}
fn handle_accent(
ctx: &mut FunctionContext,
args: Vec<ParseNode>,
_opt_args: Vec<Option<ParseNode>>,
) -> ParseResult<ParseNode> {
let base = ParseNode::normalize_argument(args.into_iter().next().unwrap());
let func_name = &ctx.func_name;
let is_stretchy = !NON_STRETCHY.contains(&func_name.as_str());
let is_shifty = !is_stretchy
|| func_name == "\\widehat"
|| func_name == "\\widetilde"
|| func_name == "\\widecheck";
Ok(ParseNode::Accent {
mode: ctx.parser.mode,
label: func_name.clone(),
is_stretchy: Some(is_stretchy),
is_shifty: Some(is_shifty),
base: Box::new(base),
loc: None,
})
}
fn handle_text_accent(
ctx: &mut FunctionContext,
args: Vec<ParseNode>,
_opt_args: Vec<Option<ParseNode>>,
) -> ParseResult<ParseNode> {
let base = args.into_iter().next().unwrap();
let mode = Mode::Text;
Ok(ParseNode::Accent {
mode,
label: ctx.func_name.clone(),
is_stretchy: Some(false),
is_shifty: Some(true),
base: Box::new(base),
loc: None,
})
}
fn handle_accent_under(
ctx: &mut FunctionContext,
args: Vec<ParseNode>,
_opt_args: Vec<Option<ParseNode>>,
) -> ParseResult<ParseNode> {
let base = args.into_iter().next().unwrap();
Ok(ParseNode::AccentUnder {
mode: ctx.parser.mode,
label: ctx.func_name.clone(),
is_stretchy: Some(true),
is_shifty: Some(false),
base: Box::new(base),
loc: None,
})
}