"""
Legacy adapter for backward compatibility.
This module provides a drop-in replacement for the original MathMLToTeXConverter
that internally uses the refactored architecture.
Examples:
Legacy API usage:
>>> from omml2tex.compat import LegacyMathMLToTeXConverter
>>> converter = LegacyMathMLToTeXConverter(subject_mode='chemistry')
>>> latex = converter.convert('')
>>> latex
'\\mathrm{H}_2\\mathrm{O}'
"""
from typing import Optional, List, Tuple
from lxml import etree as ET
from ..core.interfaces import Strategy
from ..utils.debug import debug_print
from ..strategies import (
MathStrategy,
ChemistryStrategy,
PhysicsStrategy,
StatisticsStrategy,
StrategyFactory,
)
from ..visitors import (
VisitorRegistry,
MiVisitor,
MoVisitor,
MnVisitor,
MfracVisitor,
MsupVisitor,
MsubVisitor,
MrowVisitor,
MsqrtVisitor,
MrootVisitor,
MsubsupVisitor,
MoverVisitor,
MunderVisitor,
MunderoverVisitor,
MfencedVisitor,
MtextVisitor,
MtableVisitor,
MtrVisitor,
MtdVisitor,
MspaceVisitor,
MstyleVisitor,
MerrorVisitor,
MencloseVisitor,
MmultiscriptsVisitor,
MpaddedVisitor,
MphantomVisitor,
MactionVisitor,
MsVisitor,
MglyphVisitor,
MlabeledtrVisitor,
MaligngroupVisitor,
MalignmarkVisitor,
)
class LegacyMathMLToTeXConverter:
"""
Backward-compatible adapter for the original MathMLToTeXConverter.
This class maintains the same API as the original converter but internally
uses the refactored visitor/strategy architecture.
Args:
wrap_identifiers_in_mathrm: Whether to wrap multi-char identifiers in \\mathrm{}
prefer_xlongequal: Whether to use \\xlongequal for reaction arrows
subject_mode: Subject-specific formatting mode (auto, math, physics, chemistry, statistics)
Examples:
Basic usage:
>>> converter = LegacyMathMLToTeXConverter()
>>> latex = converter.convert('')
>>> latex
'\\sin x'
Chemistry mode:
>>> converter = LegacyMathMLToTeXConverter(subject_mode='chemistry')
>>> latex = converter.convert('')
>>> latex
'\\mathrm{Fe}'
"""
def __init__(
self,
wrap_identifiers_in_mathrm: bool = False, # CRITICAL FIX: Default should be False like original
prefer_xlongequal: bool = True,
subject_mode: str = "auto",
universal_delimiter_scaling: bool = True, # NEW: Add \left\right to ALL delimiters
) -> None:
"""Initialize the legacy converter with original API parameters."""
self.wrap_identifiers_in_mathrm = wrap_identifiers_in_mathrm
self.prefer_xlongequal = prefer_xlongequal
self.subject_mode = subject_mode
self.universal_delimiter_scaling = universal_delimiter_scaling
# Internal state (mimics original converter)
self._script_context_stack = []
self._symbol_contexts = {}
self._fraction_symbols = set()
self._set_theory_mode = False
self._equation_symbols = set()
self._equation_text = ""
self._uniform_equation_color = ""
self._suppress_leaf_colors = False
self._uniform_background_color = "" # Background/highlight color from OMML
# Initialize strategy based on subject mode
self._strategy = self._create_strategy()
# Initialize visitor registry with all visitors
self._visitor_registry = self._create_visitor_registry()
def _create_strategy(self) -> Strategy:
"""
Create conversion strategy based on subject mode.
Returns:
Strategy instance for the configured subject mode
"""
if self.subject_mode == "auto":
# Auto-detection will be done per equation in convert()
return MathStrategy(wrap_identifiers_in_mathrm=self.wrap_identifiers_in_mathrm) # Default fallback
elif self.subject_mode == "chemistry":
return ChemistryStrategy()
elif self.subject_mode == "physics":
return PhysicsStrategy()
elif self.subject_mode == "statistics":
return StatisticsStrategy()
elif self.subject_mode == "math":
return MathStrategy(wrap_identifiers_in_mathrm=self.wrap_identifiers_in_mathrm)
else:
# Unknown mode - default to math
return MathStrategy(wrap_identifiers_in_mathrm=self.wrap_identifiers_in_mathrm)
def _create_visitor_registry(self, context: 'ConversionContext' = None) -> VisitorRegistry:
"""
Create and populate visitor registry with all known visitors.
Args:
context: Optional conversion context to pass to all visitors
Returns:
Configured VisitorRegistry instance
"""
registry = VisitorRegistry(context)
# Register all MathML element visitors
# Namespace handling: strip namespace prefix if present
registry.register('mi', MiVisitor)
registry.register('mo', MoVisitor)
registry.register('mn', MnVisitor)
registry.register('mfrac', MfracVisitor)
registry.register('msup', MsupVisitor)
registry.register('msub', MsubVisitor)
registry.register('mrow', MrowVisitor)
registry.register('msqrt', MsqrtVisitor)
registry.register('mroot', MrootVisitor)
registry.register('msubsup', MsubsupVisitor)
registry.register('mover', MoverVisitor)
registry.register('munder', MunderVisitor)
registry.register('munderover', MunderoverVisitor)
registry.register('mfenced', MfencedVisitor)
registry.register('mtext', MtextVisitor)
registry.register('mtable', MtableVisitor)
registry.register('mtr', MtrVisitor)
registry.register('mtd', MtdVisitor)
registry.register('mspace', MspaceVisitor)
registry.register('mstyle', MstyleVisitor)
registry.register('merror', MerrorVisitor)
registry.register('menclose', MencloseVisitor)
registry.register('mmultiscripts', MmultiscriptsVisitor)
registry.register('mpadded', MpaddedVisitor)
registry.register('mphantom', MphantomVisitor)
registry.register('maction', MactionVisitor)
registry.register('ms', MsVisitor)
registry.register('mglyph', MglyphVisitor)
registry.register('mlabeledtr', MlabeledtrVisitor)
registry.register('maligngroup', MaligngroupVisitor)
registry.register('malignmark', MalignmarkVisitor)
# Use mrow as default visitor (handles container elements like