use crate::KatexContext;
use crate::define_environment::EnvContext;
use crate::define_function::{FunctionDefSpec, FunctionPropSpec};
use crate::parser::parse_node::{AnyParseNode, NodeType, ParseNode, ParseNodeEnvironment};
use crate::types::{ArgType, Mode, ParseError, ParseErrorKind};
pub fn define_environment(ctx: &mut KatexContext) {
let spec = FunctionDefSpec {
node_type: Some(NodeType::Environment),
names: &["\\begin", "\\end"],
props: FunctionPropSpec {
num_args: 1,
arg_types: Some(vec![ArgType::Mode(Mode::Text)]),
..Default::default()
},
handler: Some(|context, args, _opt_args| {
let func_name = context.func_name;
let parser = context.parser;
let ParseNode::OrdGroup(name_group) = &args[0] else {
return Err(ParseError::new(ParseErrorKind::InvalidEnvironmentName {
value: format!("{:?}", args[0]),
}));
};
let mut env_name = String::new();
for item in &name_group.body {
if let AnyParseNode::TextOrd(text_ord) = item {
env_name.push_str(&text_ord.text);
} else {
return Err(ParseError::new(ParseErrorKind::InvalidEnvironmentName {
value: format!("{:?}", args[0]),
}));
}
}
if func_name != "\\begin" {
let env = ParseNodeEnvironment {
mode: parser.mode,
loc: None,
name: env_name.clone(),
name_group: args[0].clone().into(),
};
return Ok(env.into());
}
let Some(env_spec) = parser.ctx.environments.get(&env_name) else {
return Err(ParseError::new(ParseErrorKind::NoSuchEnvironment {
name: env_name.clone(),
}));
};
let (args, opt_args) =
parser.parse_arguments(&format!("\\begin{{{env_name}}}"), env_spec.as_ref())?;
let env_context = EnvContext {
mode: parser.mode,
parser,
env_name: env_name.clone(),
};
let result = (env_spec.handler)(env_context, args, opt_args)?;
parser.expect("\\end", false)?;
let end_name_token = parser.next_token.clone();
let Some(ParseNode::Environment(end_node)) = parser.parse_function(None, None)? else {
return Err(ParseError::new(
ParseErrorKind::ExpectedEnvironmentAfterEnd {
found: format!("{end_name_token:?}"),
},
));
};
if end_node.name != env_name {
return Err(ParseError::new(ParseErrorKind::MismatchedEnvironmentEnd {
begin: env_name,
end: end_node.name,
}));
}
Ok(result)
}),
html_builder: None, mathml_builder: None,
};
ctx.define_function(spec);
}