use texform_knowledge::builtin::base;
use texform_knowledge::builtin::physics;
use crate::ast::{ContentMode, Node};
use crate::rewrite::helpers::{mandatory_content_slot, prefix_command_node};
use crate::rewrite::rule::{RuleConsumes, RuleEffect, RuleProduces};
use crate::rewrite::{cmd_targets, define_rule};
define_rule! {
pub static QCOMMA_EXPAND: QcommaExpandRule {
key: Physics / "qcomma-expand",
level: Expand,
summary: "Expand quick-quad punctuation helpers to explicit text punctuation plus trailing quad spacing.",
fidelity: Full,
enabled_by_packages: [Physics],
triggers: cmd_targets![&physics::cmd::QC, &physics::cmd::QCOMMA],
consumes: RuleConsumes {
eliminates: cmd_targets![&physics::cmd::QC, &physics::cmd::QCOMMA],
touches: &[],
},
produces: RuleProduces {
targets: cmd_targets![&base::cmd::TEXT, &base::cmd::QUAD],
},
apply(rule, cx, node_id) {
let Some(command) = cx
.match_command(node_id, &physics::cmd::QC)
.or_else(|| cx.match_command(node_id, &physics::cmd::QCOMMA))
else {
return Ok(RuleEffect::Skipped);
};
cx.for_rule(Self::KEY).expect_no_args(command.args, &command.subject())?;
let comma = cx.ast.new_node(Node::Text(",".to_string()));
let text_command = prefix_command_node(
&base::cmd::TEXT,
vec![mandatory_content_slot(comma, ContentMode::Text)],
);
let text_command = cx.ast.new_node(text_command);
let quad = cx.ast.new_node(prefix_command_node(&base::cmd::QUAD, vec![]));
cx.ast
.replace_with_math_sequence(node_id, Vec::new(), text_command, vec![quad]);
Ok(RuleEffect::Applied)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::parse::ParseContext;
use crate::rewrite::transform_examples;
use crate::rewrite::{run_one_rule_for_test, NormalizationLevel};
transform_examples! {
rule: QCOMMA_EXPAND,
level: Expand,
examples: [
{
label: qcomma_between_clauses,
packages: ["base", "physics"],
input: r"a=b \qc c=d",
expected: r"a=b \text{,}\quad c=d",
},
{
label: qcomma_long_alias,
packages: ["base", "physics"],
input: r"x>0 \qcomma y>0",
expected: r"x>0 \text{,}\quad y>0",
},
]
}
#[test]
fn groups_qcomma_expansion_when_not_a_sibling_node() {
let parse_ctx = ParseContext::from_packages(&["base", "physics"]);
let mut ast = crate::parse_to_ast_for_test(&parse_ctx, r"\qc^2", &texform_core::parse::ParseConfig::STRICT);
let output = run_one_rule_for_test(&mut ast, &parse_ctx, &QCOMMA_EXPAND, NormalizationLevel::Expand)
.expect("qcomma-expand transform should succeed");
assert_eq!(output.rewrite.rules.len(), 1);
assert_eq!(output.rewrite.rules[0].applied_count, 1);
}
}