use std::collections::HashMap;
use crate::error::{ParseError, ParseResult};
use crate::functions::{define_function_full, ArgType, FunctionContext, FunctionSpec};
use crate::parse_node::ParseNode;
struct DelimInfo {
mclass: &'static str,
size: u8,
}
fn delim_info(name: &str) -> Option<DelimInfo> {
match name {
"\\bigl" => Some(DelimInfo {
mclass: "mopen",
size: 1,
}),
"\\Bigl" => Some(DelimInfo {
mclass: "mopen",
size: 2,
}),
"\\biggl" => Some(DelimInfo {
mclass: "mopen",
size: 3,
}),
"\\Biggl" => Some(DelimInfo {
mclass: "mopen",
size: 4,
}),
"\\bigr" => Some(DelimInfo {
mclass: "mclose",
size: 1,
}),
"\\Bigr" => Some(DelimInfo {
mclass: "mclose",
size: 2,
}),
"\\biggr" => Some(DelimInfo {
mclass: "mclose",
size: 3,
}),
"\\Biggr" => Some(DelimInfo {
mclass: "mclose",
size: 4,
}),
"\\bigm" => Some(DelimInfo {
mclass: "mrel",
size: 1,
}),
"\\Bigm" => Some(DelimInfo {
mclass: "mrel",
size: 2,
}),
"\\biggm" => Some(DelimInfo {
mclass: "mrel",
size: 3,
}),
"\\Biggm" => Some(DelimInfo {
mclass: "mrel",
size: 4,
}),
"\\big" => Some(DelimInfo {
mclass: "mord",
size: 1,
}),
"\\Big" => Some(DelimInfo {
mclass: "mord",
size: 2,
}),
"\\bigg" => Some(DelimInfo {
mclass: "mord",
size: 3,
}),
"\\Bigg" => Some(DelimInfo {
mclass: "mord",
size: 4,
}),
_ => None,
}
}
pub fn register(map: &mut HashMap<&'static str, FunctionSpec>) {
define_function_full(
map,
&[
"\\bigl", "\\Bigl", "\\biggl", "\\Biggl", "\\bigr", "\\Bigr", "\\biggr", "\\Biggr",
"\\bigm", "\\Bigm", "\\biggm", "\\Biggm", "\\big", "\\Big", "\\bigg", "\\Bigg",
],
"delimsizing",
1,
0,
Some(vec![ArgType::Primitive]),
false,
false,
true,
false,
false,
handle_delimsizing,
);
}
fn handle_delimsizing(
ctx: &mut FunctionContext,
args: Vec<ParseNode>,
_opt_args: Vec<Option<ParseNode>>,
) -> ParseResult<ParseNode> {
let delim = check_delimiter(&args[0], &ctx.func_name)?;
let info = delim_info(&ctx.func_name).unwrap();
Ok(ParseNode::DelimSizing {
mode: ctx.parser.mode,
size: info.size,
mclass: info.mclass.to_string(),
delim,
loc: None,
})
}
fn check_delimiter(node: &ParseNode, func_name: &str) -> ParseResult<String> {
if let Some(text) = node.symbol_text() {
if is_valid_delimiter(text) {
return Ok(text.to_string());
}
return Err(ParseError::msg(format!(
"Invalid delimiter '{}' after '{}'",
text, func_name
)));
}
Err(ParseError::msg(format!(
"Invalid delimiter type '{}' after '{}'",
node.type_name(),
func_name
)))
}
fn is_valid_delimiter(text: &str) -> bool {
matches!(
text,
"(" | "\\lparen"
| ")"
| "\\rparen"
| "["
| "\\lbrack"
| "]"
| "\\rbrack"
| "\\{"
| "\\lbrace"
| "\\}"
| "\\rbrace"
| "\\lfloor"
| "\\rfloor"
| "\\lceil"
| "\\rceil"
| "<"
| ">"
| "\\langle"
| "\\rangle"
| "\\lt"
| "\\gt"
| "\\lvert"
| "\\rvert"
| "\\lVert"
| "\\rVert"
| "\\lgroup"
| "\\rgroup"
| "\\lmoustache"
| "\\rmoustache"
| "/"
| "\\backslash"
| "|"
| "\\vert"
| "\\|"
| "\\Vert"
| "\\uparrow"
| "\\Uparrow"
| "\\downarrow"
| "\\Downarrow"
| "\\updownarrow"
| "\\Updownarrow"
| "."
)
}