diff --git a/mathics/builtin/box/compilation.py b/mathics/builtin/box/compilation.py
index ce2a2fe7a..4a45a9b1f 100644
--- a/mathics/builtin/box/compilation.py
+++ b/mathics/builtin/box/compilation.py
@@ -21,7 +21,7 @@ class CompiledCodeBox(BoxExpression):
def init(self, *args, **kwargs):
self._elements = args
- self.box_options = kwargs
+ self.box_attributes = kwargs
def boxes_to_text(self, elements=None, **options):
if elements is None:
diff --git a/mathics/builtin/box/layout.py b/mathics/builtin/box/layout.py
index 23423eb8d..e34b6c3d8 100644
--- a/mathics/builtin/box/layout.py
+++ b/mathics/builtin/box/layout.py
@@ -122,7 +122,7 @@ class FormBox(BoxExpression):
summary_text = "wrap boxes with an association to a particular form"
def init(self, *elems, **kwargs):
- self.box_options = kwargs
+ self.box_attributes = kwargs
self.form = elems[1]
self.boxes = elems[0]
assert isinstance(self.boxes, BoxElementMixin), f"{type(self.boxes)}"
@@ -136,7 +136,7 @@ def elements(self):
self.boxes,
self.form,
),
- self.box_options,
+ self.box_attributes,
)
return self._elements
@@ -178,7 +178,7 @@ def elements(self):
self.num,
self.den,
),
- self.box_options,
+ self.box_attributes,
)
return self._elements
@@ -193,7 +193,7 @@ def eval(self, num, den, evaluation: Evaluation, options: dict):
def init(self, num, den, **options):
self.num = num
self.den = den
- self.box_options = options
+ self.box_attributes = options
class GridBox(BoxExpression):
@@ -228,11 +228,13 @@ class GridBox(BoxExpression):
@property
def elements(self):
if self._elements is None:
- self._elements = elements_to_expressions(self, self.items, self.box_options)
+ self._elements = elements_to_expressions(
+ self, self.items, self.box_attributes
+ )
return self._elements
def init(self, *elems, **kwargs):
- self.box_options = kwargs
+ self.box_attributes = kwargs
self.items = elems
self._elements = elems
@@ -240,7 +242,7 @@ def get_array(self, elements, evaluation):
if not elements:
raise BoxConstructError
- options = self.box_options
+ options = self.box_attributes
expr = elements[0]
if not expr.has_form("List", None):
@@ -293,13 +295,13 @@ class InterpretationBox(BoxExpression):
def __repr__(self):
result = "InterpretationBox\n " + repr(self.boxes)
- result += f"\n {self.box_options}"
+ result += f"\n {self.box_attributes}"
return result
def init(self, *expr, **options):
self.boxes = expr[0]
self.expr = expr[1]
- self.box_options = options
+ self.box_attributes = options
@property
def elements(self):
@@ -310,7 +312,7 @@ def elements(self):
self.boxes,
self.expr,
),
- self.box_options,
+ self.box_attributes,
)
return self._elements
@@ -365,13 +367,13 @@ class PaneBox(BoxExpression):
def elements(self):
if self._elements is None:
self._elements = elements_to_expressions(
- self, (self.boxes,), self.box_options
+ self, (self.boxes,), self.box_attributes
)
return self._elements
def init(self, expr, **options):
self.boxes = expr
- self.box_options = options
+ self.box_attributes = options
def eval_panebox1(self, expr, evaluation, options):
"PaneBox[expr_String, OptionsPattern[]]"
@@ -409,6 +411,16 @@ class RowBox(BoxExpression):
def __repr__(self):
return f"RowBox[{self.elements[0].__repr__()}]"
+ def __init__(self, *args, **kwargs):
+ # indent level nesting level used in rendering MathML boxes
+ self.indent_level: int = 0
+
+ # Consider adding.
+ # self.width: int = 0
+
+ # Pass all arguments to the parent class.
+ super().__init__(*args, **kwargs)
+
@property
def elements(self):
if self._elements is None:
@@ -433,7 +445,7 @@ def eval_list(self, boxes, evaluation):
def init(self, *items, **kwargs):
# TODO: check that each element is an string or a BoxElementMixin
- self.box_options = {}
+ self.box_attributes = {}
if len(items) == 0:
self.items = tuple()
return
@@ -509,13 +521,13 @@ def elements(self):
if self._elements is None:
index = self.index
if index is None:
- # self.box_options
+ # self.box_attributes
self._elements = elements_to_expressions(
- self, (self.radicand,), self.box_options
+ self, (self.radicand,), self.box_attributes
)
else:
self._elements = elements_to_expressions(
- self, (self.radicand, index), self.box_options
+ self, (self.radicand, index), self.box_attributes
)
return self._elements
@@ -535,7 +547,7 @@ def eval(self, radicand, evaluation: Evaluation, options: dict):
def init(self, radicand, index=None, **options):
self.radicand = radicand
self.index = index
- self.box_options = options
+ self.box_attributes = options
class StyleBox(BoxExpression):
@@ -567,11 +579,11 @@ def elements(self):
boxes = self.boxes
if style:
self._elements = elements_to_expressions(
- self, (boxes, style), self.box_options
+ self, (boxes, style), self.box_attributes
)
else:
self._elements = elements_to_expressions(
- self, (boxes,), self.box_options
+ self, (boxes,), self.box_attributes
)
return self._elements
@@ -596,10 +608,10 @@ def get_string_value(self) -> str:
def init(self, boxes, style=None, **options):
# This implementation supersedes Expression.process_style_box
if isinstance(boxes, StyleBox):
- options.update(boxes.box_options)
+ options.update(boxes.box_attributes)
boxes = boxes.boxes
self.style = style
- self.box_options = options
+ self.box_attributes = options
assert options is not None
self.boxes = boxes
assert isinstance(
@@ -635,7 +647,7 @@ class SubscriptBox(BoxExpression):
def elements(self):
if self._elements is None:
self._elements = elements_to_expressions(
- self, (self.base, self.subindex), self.box_options
+ self, (self.base, self.subindex), self.box_attributes
)
return self._elements
@@ -648,7 +660,7 @@ def eval(self, a, b, evaluation: Evaluation, options: dict):
return SubscriptBox(a_box, b_box, **options)
def init(self, a, b, **options):
- self.box_options = options.copy()
+ self.box_attributes = options.copy()
if not (isinstance(a, BoxElementMixin) and isinstance(b, BoxElementMixin)):
raise Exception((a, b), "are not boxes")
self.base = a
@@ -674,7 +686,7 @@ class SubsuperscriptBox(BoxExpression):
@property
def elements(self):
if self._elements is None:
- # self.box_options
+ # self.box_attributes
self._elements = elements_to_expressions(
(
self,
@@ -682,7 +694,7 @@ def elements(self):
self.subindex,
self.superindex,
),
- self.box_options,
+ self.box_attributes,
)
return self._elements
@@ -696,7 +708,7 @@ def eval(self, a, b, c, evaluation: Evaluation, options: dict):
return SubsuperscriptBox(a_box, b_box, c_box, **options)
def init(self, a, b, c, **options):
- self.box_options = options.copy()
+ self.box_attributes = options.copy()
if not all(isinstance(x, BoxElementMixin) for x in (a, b, c)):
raise Exception((a, b, c), "are not boxes")
self.base = a
@@ -729,7 +741,7 @@ def elements(self):
self.base,
self.superindex,
),
- self.box_options,
+ self.box_attributes,
)
return self._elements
@@ -742,7 +754,7 @@ def eval(self, a, b, evaluation: Evaluation, options: dict):
return SuperscriptBox(a_box, b_box, **options)
def init(self, a, b, **options):
- self.box_options = options.copy()
+ self.box_attributes = options.copy()
if not all(isinstance(x, BoxElementMixin) for x in (a, b)):
raise Exception((a, b), "are not boxes")
self.base = a
@@ -766,7 +778,7 @@ class TagBox(BoxExpression):
summary_text = "box tag with a head"
def init(self, *elems, **kwargs):
- self.box_options = kwargs
+ self.box_attributes = kwargs
self.form = elems[1]
self.boxes = elems[0]
assert isinstance(self.boxes, BoxElementMixin), f"{type(self.boxes)}"
@@ -780,7 +792,7 @@ def elements(self):
self.boxes,
self.form,
),
- self.box_options,
+ self.box_attributes,
)
return self._elements
diff --git a/mathics/format/box/outputforms.py b/mathics/format/box/outputforms.py
index 60d187f4d..09de275d9 100644
--- a/mathics/format/box/outputforms.py
+++ b/mathics/format/box/outputforms.py
@@ -30,7 +30,7 @@ def eval_mathmlform(expr: BaseElement, evaluation: Evaluation) -> BoxElementMixi
boxes = format_element(expr, evaluation, SymbolTraditionalForm)
try:
- mathml = boxes.boxes_to_mathml(evaluation=evaluation)
+ mathml = boxes.boxes_to_mathml(evaluation=evaluation, indent_level=1)
except BoxError:
evaluation.message(
"General",
@@ -44,9 +44,15 @@ def eval_mathmlform(expr: BaseElement, evaluation: Evaluation) -> BoxElementMixi
# #convert_box(boxes)
query = evaluation.parse("Settings`$UseSansSerif")
usesansserif = query.evaluate(evaluation).to_python()
- if not is_a_picture:
- if isinstance(usesansserif, bool) and usesansserif:
- mathml = '%s' % mathml
+ if is_a_picture:
+ usesansserif = False
+ elif not isinstance(usesansserif, bool):
+ usesansserif = False
+
+ if usesansserif:
+ mathml = '\n%s\n' % mathml
+ else:
+ mathml = "\n%s\n" % mathml
mathml = '' % mathml # convert_box(boxes)
return InterpretationBox(
diff --git a/mathics/format/render/latex.py b/mathics/format/render/latex.py
index 8cf27c403..a936ad587 100644
--- a/mathics/format/render/latex.py
+++ b/mathics/format/render/latex.py
@@ -174,7 +174,7 @@ def interpretation_box(self, **options):
def pane_box(self, **options):
content = lookup_conversion_method(self.boxes, "latex")(self.boxes, **options)
- options = self.box_options
+ options = self.box_attributes
size = options.get("System`ImageSize", SymbolAutomatic).to_python()
if size == "System`Automatic":
@@ -211,7 +211,7 @@ def pane_box(self, **options):
def fractionbox(self, **options) -> str:
- _options = self.box_options.copy()
+ _options = self.box_attributes.copy()
_options.update(options)
options = _options
return "\\frac{%s}{%s}" % (
@@ -223,17 +223,17 @@ def fractionbox(self, **options) -> str:
add_conversion_fn(FractionBox, fractionbox)
-def gridbox(self, elements=None, **box_options) -> str:
+def gridbox(self, elements=None, **box_attributes) -> str:
def boxes_to_tex(box, **options):
return lookup_conversion_method(box, "latex")(box, **options)
if not elements:
elements = self._elements
- evaluation = box_options.get("evaluation")
+ evaluation = box_attributes.get("evaluation")
items, options = self.get_array(elements, evaluation)
- box_options.update(options)
- box_options["inside_list"] = True
- column_alignments = box_options["System`ColumnAlignments"].get_name()
+ box_attributes.update(options)
+ box_attributes["inside_list"] = True
+ column_alignments = box_attributes["System`ColumnAlignments"].get_name()
try:
column_alignments = {
"System`Center": "c",
@@ -251,12 +251,12 @@ def boxes_to_tex(box, **options):
result = r"\begin{array}{%s} " % (column_alignments * column_count)
for index, row in enumerate(items):
if isinstance(row, tuple):
- result += " & ".join(boxes_to_tex(item, **box_options) for item in row)
+ result += " & ".join(boxes_to_tex(item, **box_attributes) for item in row)
else:
result += r"\multicolumn{%s}{%s}{%s}" % (
str(column_count),
column_alignments,
- boxes_to_tex(row, **box_options),
+ boxes_to_tex(row, **box_attributes),
)
if index != len(items) - 1:
result += "\\\\ "
@@ -268,7 +268,7 @@ def boxes_to_tex(box, **options):
def sqrtbox(self, **options):
- _options = self.box_options.copy()
+ _options = self.box_attributes.copy()
_options.update(options)
options = _options
if self.index:
@@ -285,7 +285,7 @@ def sqrtbox(self, **options):
def superscriptbox(self, **options):
- _options = self.box_options.copy()
+ _options = self.box_attributes.copy()
_options.update(options)
options = _options
base_to_tex = lookup_conversion_method(self.base, "latex")
@@ -315,7 +315,7 @@ def superscriptbox(self, **options):
def subscriptbox(self, **options):
- _options = self.box_options.copy()
+ _options = self.box_attributes.copy()
_options.update(options)
options = _options
base_to_tex = lookup_conversion_method(self.base, "latex")
@@ -330,7 +330,7 @@ def subscriptbox(self, **options):
def subsuperscriptbox(self, **options):
- _options = self.box_options.copy()
+ _options = self.box_attributes.copy()
_options.update(options)
options = _options
base_to_tex = lookup_conversion_method(self.base, "latex")
@@ -348,7 +348,7 @@ def subsuperscriptbox(self, **options):
def rowbox(self, **options) -> str:
- _options = self.box_options.copy()
+ _options = self.box_attributes.copy()
_options.update(options)
options = _options
parts_str = [
@@ -382,7 +382,7 @@ def rowbox(self, **options) -> str:
def stylebox(self, **options) -> str:
- _options = self.box_options.copy()
+ _options = self.box_attributes.copy()
_options.update(options)
options = _options
return lookup_conversion_method(self.boxes, "latex")(self.boxes, **options)
diff --git a/mathics/format/render/mathml.py b/mathics/format/render/mathml.py
index a9ecb2297..5a943e1d7 100644
--- a/mathics/format/render/mathml.py
+++ b/mathics/format/render/mathml.py
@@ -1,31 +1,32 @@
# -*- coding: utf-8 -*-
"""
-Lower-level formatter of Mathics objects as MathML strings.
+Lower-level formatter of Mathics3 into MathML strings.
MathML formatting is usually initiated in Mathics via MathMLForm[].
-For readability, and following WMA MathML generated code, tags \
+Following WMA MathML generated text, and for readability, MathML tags
containing sub-tags are split on several lines, one by
-sub element. For example, the Box expression
+sub element, and indented according to nesting level. The
+indentation step size is one space.
+
+For example, the Box expression
>> FractionBox[RowBox[{"a", "+", SuperscriptBox["b", "c"]}], "d"]
produces
```
-
-a
-+
-
-b
-c
-
-
-d
+
+ a
+ +
+
+ b
+ c
+
+
+ d
```
-In WMA, each line would be also indented adding one space on each \
-level of indentation.
"""
@@ -90,20 +91,22 @@ def encode_mathml(text: str) -> str:
}
-def string(self, **options) -> str:
- text = self.value
+def string(s: String, **options) -> str:
+ text = s.value
number_as_text = options.get("number_as_text", None)
show_string_characters = (
options.get("System`ShowStringCharacters", None) is SymbolTrue
)
- if isinstance(self, BoxElementMixin):
- if number_as_text is None:
- number_as_text = SymbolFalse
+ if number_as_text is None:
+ number_as_text = SymbolFalse
+
+ indent_level = options.get("indent_level", 0)
+ indent_spaces = " " * indent_level
- def render(format, string):
- encoded_text = encode_mathml(string)
- return format % encoded_text
+ def render(format, s):
+ encoded_text = encode_mathml(s)
+ return indent_spaces + format % encoded_text
if text.startswith('"') and text.endswith('"'):
text = text[1:-1]
@@ -144,9 +147,9 @@ def render(format, string):
add_conversion_fn(String, string)
-def interpretation_box(self, **options):
- boxes = self.boxes
- origin = self.expr
+def interpretation_box(box: InterpretationBox, **options):
+ boxes = box.boxes
+ origin = box.expr
if origin.has_form("InputForm", None):
# InputForm produce outputs of the form
# InterpretationBox[Style[_String, ...], origin_InputForm, opts___]
@@ -170,9 +173,13 @@ def interpretation_box(self, **options):
add_conversion_fn(InterpretationBox, interpretation_box)
-def pane_box(self, **options):
- content = lookup_conversion_method(self.boxes, "mathml")(self.boxes, **options)
- options = self.box_options
+def pane_box(box, **options):
+ indent_level = options.get("indent_level", 0)
+ indent_spaces = " " * indent_level
+ options["indent_level"] = indent_level + 1
+
+ content = lookup_conversion_method(box.boxes, "mathml")(box.boxes, **options)
+ options = box.box_attributes
size = options.get("System`ImageSize", SymbolAutomatic).to_python()
if size is SymbolAutomatic:
width = ""
@@ -201,34 +208,49 @@ def pane_box(self, **options):
dims += "overflow:hidden;"
dims = f' style="{dims}" '
if dims:
- return f"\n{content}\n"
- return content
+ return f"{indent_spaces}\n{content}\n{indent_spaces}"
+ return f"{indent_spaces}{content}"
add_conversion_fn(PaneBox, pane_box)
-def fractionbox(self, **options) -> str:
- _options = self.box_options.copy()
- _options.update(options)
- options = _options
- return "\n%s\n%s\n" % (
- lookup_conversion_method(self.num, "mathml")(self.num, **options),
- lookup_conversion_method(self.den, "mathml")(self.den, **options),
+def fractionbox(box: FractionBox, **options) -> str:
+ indent_level = box.box_attributes.get(
+ "indent_level", options.get("indent_level", 0)
+ )
+ indent_spaces = " " * indent_level
+ indent_level += 1
+ has_nonbox_children = False
+
+ for child_box in (box.num, box.den):
+ if hasattr(child_box, "box_attributes"):
+ child_box.box_attributes["indent_level"] = indent_level
+ else:
+ has_nonbox_children = True
+
+ if has_nonbox_children:
+ # non_boxed children have to get indent_level information passed down
+ # via a parameter. Here it is the "options" variable. (Which is a bad name).
+ child_options = {**options, "indent_level": indent_level}
+
+ return f"{indent_spaces}\n%s\n%s\n{indent_spaces}" % (
+ lookup_conversion_method(box.num, "mathml")(box.num, **child_options),
+ lookup_conversion_method(box.den, "mathml")(box.den, **child_options),
)
add_conversion_fn(FractionBox, fractionbox)
-def gridbox(self, elements=None, **box_options) -> str:
+def gridbox(box: GridBox, elements=None, **box_attributes) -> str:
def boxes_to_mathml(box, **options):
return lookup_conversion_method(box, "mathml")(box, **options)
if not elements:
- elements = self._elements
- evaluation = box_options.get("evaluation")
- items, options = self.get_array(elements, evaluation)
+ elements = box._elements
+ evaluation = box_attributes.get("evaluation")
+ items, options = box.get_array(elements, evaluation)
num_fields = max(len(item) if isinstance(item, tuple) else 1 for item in items)
attrs = {}
@@ -243,18 +265,23 @@ def boxes_to_mathml(box, **options):
# invalid column alignment
raise BoxConstructError
joined_attrs = " ".join(f'{name}="{value}"' for name, value in attrs.items())
- result = f"\n"
- new_box_options = box_options.copy()
- new_box_options["inside_list"] = True
+ indent_level = options.get("indent_level", 0)
+ indent_spaces = " " * indent_level
+ result = f"{indent_spaces}\n"
+ new_box_attributes = box_attributes.copy()
+ new_box_attributes["inside_list"] = True
+ new_box_attributes["indent_level"] = indent_level + 3
+
for row in items:
- result += ""
+ result += f"{indent_spaces} "
if isinstance(row, tuple):
for item in row:
- result += f"{boxes_to_mathml(item, **new_box_options)}"
+ new_box_attributes["indent_level"] = indent_level + 4
+ result += f"\n{indent_spaces} \n{boxes_to_mathml(item, **new_box_attributes)}\n{indent_spaces} "
else:
- result += f"{boxes_to_mathml(row, **new_box_options)}"
- result += "\n"
- result += ""
+ result += f"\n{indent_spaces} \n{boxes_to_mathml(row, **new_box_attributes)}\n{indent_spaces} "
+ result += f"\n{indent_spaces} \n"
+ result += f"{indent_spaces}"
# print(f"gridbox: {result}")
return result
@@ -262,67 +289,84 @@ def boxes_to_mathml(box, **options):
add_conversion_fn(GridBox, gridbox)
-def sqrtbox(self, **options):
- _options = self.box_options.copy()
+def sqrtbox(box: SqrtBox, **options):
+ _options = box.box_attributes.copy()
_options.update(options)
options = _options
- if self.index:
- return " %s %s " % (
- lookup_conversion_method(self.radicand, "mathml")(self.radicand, **options),
- lookup_conversion_method(self.index, "mathml")(self.index, **options),
+ indent_level = options.get("indent_level", 0)
+ indent_spaces = " " * indent_level
+ options["indent_level"] = indent_level + 1
+
+ if box.index:
+ return f"{indent_spaces}\n%s\n%s\n{indent_spaces}" % (
+ lookup_conversion_method(box.radicand, "mathml")(box.radicand, **options),
+ lookup_conversion_method(box.index, "mathml")(box.index, **options),
)
- return "\n%s\n" % lookup_conversion_method(self.radicand, "mathml")(
- self.radicand, **options
+ return (
+ f"{indent_spaces}\n%s\n{indent_spaces}"
+ % lookup_conversion_method(box.radicand, "mathml")(box.radicand, **options)
)
add_conversion_fn(SqrtBox, sqrtbox)
-def subscriptbox(self, **options):
- _options = self.box_options.copy()
+def subscriptbox(box: SqrtBox, **options):
+ _options = box.box_attributes.copy()
_options.update(options)
options = _options
- return "\n%s\n%s\n" % (
- lookup_conversion_method(self.base, "mathml")(self.base, **options),
- lookup_conversion_method(self.subindex, "mathml")(self.subindex, **options),
+ indent_level = options.get("indent_level", 0)
+ indent_spaces = " " * indent_level
+ options["indent_level"] = indent_level + 1
+ return f"{indent_spaces}\n%s\n%s\n{indent_spaces}" % (
+ lookup_conversion_method(box.base, "mathml")(box.base, **options),
+ lookup_conversion_method(box.subindex, "mathml")(box.subindex, **options),
)
add_conversion_fn(SubscriptBox, subscriptbox)
-def superscriptbox(self, **options):
- _options = self.box_options.copy()
+def superscriptbox(box: SuperscriptBox, **options):
+ _options = box.box_attributes.copy()
_options.update(options)
options = _options
- return "\n%s\n%s\n" % (
- lookup_conversion_method(self.base, "mathml")(self.base, **options),
- lookup_conversion_method(self.superindex, "mathml")(self.superindex, **options),
+ indent_level = options.get("indent_level", 0)
+ indent_spaces = " " * indent_level
+ options["indent_level"] = indent_level + 1
+
+ return f"{indent_spaces}\n%s\n%s\n{indent_spaces}" % (
+ lookup_conversion_method(box.base, "mathml")(box.base, **options),
+ lookup_conversion_method(box.superindex, "mathml")(box.superindex, **options),
)
add_conversion_fn(SuperscriptBox, superscriptbox)
-def subsuperscriptbox(self, **options):
- _options = self.box_options.copy()
+def subsuperscriptbox(box: SubscriptBox, **options):
+ _options = box.box_attributes.copy()
_options.update(options)
options = _options
options["inside_row"] = True
- return "\n%s\n%s\n%s\n" % (
- lookup_conversion_method(self.base, "mathml")(self.base, **options),
- lookup_conversion_method(self.subindex, "mathml")(self.subindex, **options),
- lookup_conversion_method(self.superindex, "mathml")(self.superindex, **options),
+
+ indent_level = options.get("indent_level", 0)
+ indent_spaces = " " * indent_level
+ options["indent_level"] = indent_level + 1
+
+ return f"{indent_spaces}\n%s\n%s\n%s\n{indent_spaces}" % (
+ lookup_conversion_method(box.base, "mathml")(box.base, **options),
+ lookup_conversion_method(box.subindex, "mathml")(box.subindex, **options),
+ lookup_conversion_method(box.superindex, "mathml")(box.superindex, **options),
)
add_conversion_fn(SubsuperscriptBox, subsuperscriptbox)
-def rowbox(self, **options) -> str:
- _options = self.box_options.copy()
+def rowbox(box: RowBox, **options) -> str:
+ _options = box.box_attributes.copy()
_options.update(options)
options = _options
result = []
@@ -337,16 +381,16 @@ def is_list_interior(content):
is_list_row = False
if (
- len(self.items) >= 3
- and self.items[0].get_string_value() == "{"
- and self.items[2].get_string_value() == "}"
- and self.items[1].has_form("RowBox", 1, None)
+ len(box.items) >= 3
+ and box.items[0].get_string_value() == "{"
+ and box.items[2].get_string_value() == "}"
+ and box.items[1].has_form("RowBox", 1, None)
):
- content = self.items[1].items
+ content = box.items[1].items
if is_list_interior(content):
is_list_row = True
- if not inside_row and is_list_interior(self.items):
+ if not inside_row and is_list_interior(box.items):
is_list_row = True
if is_list_row:
@@ -354,31 +398,36 @@ def is_list_interior(content):
else:
options["inside_row"] = True
- for element in self.items:
+ indent_level = options.get("indent_level", 0)
+ indent_spaces = " " * indent_level
+ options["indent_level"] = indent_level + 1
+
+ for element in box.items:
+ # Propagate properties down to box children.
+ # The below test could also be done via isinstance of of Box.
result.append(lookup_conversion_method(element, "mathml")(element, **options))
# print(f"mrow: {result}")
-
- return "\n%s\n" % "\n".join(result)
+ return f"{indent_spaces}\n%s\n{indent_spaces}" % ("\n".join(result),)
add_conversion_fn(RowBox, rowbox)
-def stylebox(self, **options) -> str:
- _options = self.box_options.copy()
+def stylebox(box: StyleBox, **options) -> str:
+ _options = box.box_attributes.copy()
_options.update(options)
options = _options
- return lookup_conversion_method(self.boxes, "mathml")(self.boxes, **options)
+ return lookup_conversion_method(box.boxes, "mathml")(box.boxes, **options)
add_conversion_fn(StyleBox, stylebox)
-def graphicsbox(self, elements=None, **options) -> str:
+def graphicsbox(box: GraphicsBox, elements=None, **options) -> str:
# FIXME: SVG is the only thing we can convert MathML into.
# Handle other graphics formats.
- svg_body = self.boxes_to_svg(elements, **options)
+ svg_body = box.boxes_to_svg(elements, **options)
# mglyph, which is what we have been using, is bad because MathML standard changed.
# metext does not work because the way in which we produce the svg images is also based on this outdated mglyph
@@ -390,10 +439,14 @@ def graphicsbox(self, elements=None, **options) -> str:
)
# print(svg_body)
mathml = template % (
- int(self.width),
- int(self.height),
+ int(box.width),
+ int(box.height),
base64.b64encode(svg_body.encode("utf8")).decode("utf8"),
)
+ indent_level = options.get("indent_level", 0)
+ if indent_level:
+ mathml = " " * indent_level + mathml
+
# print("boxes_to_mathml", mathml)
return mathml
@@ -401,19 +454,22 @@ def graphicsbox(self, elements=None, **options) -> str:
add_conversion_fn(GraphicsBox, graphicsbox)
-def graphics3dbox(self, elements=None, **options) -> str:
+def graphics3dbox(box: Graphics3DBox, elements=None, **options) -> str:
"""Turn the Graphics3DBox into a MathML string"""
- json_repr = self.boxes_to_json(elements, **options)
+ json_repr = box.boxes_to_json(elements, **options)
mathml = f''
mathml = f"\n\n\n{mathml}\n\n\n"
+ indent_level = options.get("indent_level", 0)
+ if indent_level:
+ mathml = " " * indent_level + mathml
return mathml
add_conversion_fn(Graphics3DBox, graphics3dbox)
-def tag_and_form_box(self, **options):
- return lookup_conversion_method(self.boxes, "mathml")(self.boxes, **options)
+def tag_and_form_box(box, **options):
+ return lookup_conversion_method(box.boxes, "mathml")(box.boxes, **options)
add_conversion_fn(FormBox, tag_and_form_box)
diff --git a/mathics/format/render/text.py b/mathics/format/render/text.py
index 249a64dcb..fcd28dfc0 100644
--- a/mathics/format/render/text.py
+++ b/mathics/format/render/text.py
@@ -61,7 +61,7 @@ def pane_box(self, **options):
def fractionbox(self, **options) -> str:
- _options = self.box_options.copy()
+ _options = self.box_attributes.copy()
_options.update(options)
options = _options
num_text = boxes_to_text(self.num, **options)
@@ -77,13 +77,13 @@ def fractionbox(self, **options) -> str:
add_conversion_fn(FractionBox, fractionbox)
-def gridbox(self, elements=None, **box_options) -> str:
+def gridbox(self, elements=None, **box_attributes) -> str:
if not elements:
elements = self.items
- evaluation = box_options.get("evaluation", None)
+ evaluation = box_attributes.get("evaluation", None)
items, options = self.get_array(elements, evaluation)
- box_options.update(self.options)
+ box_attributes.update(self.options)
if not items:
return ""
@@ -92,11 +92,11 @@ def gridbox(self, elements=None, **box_options) -> str:
(
[
# TODO: check if this evaluation is necessary.
- boxes_to_text(item, **box_options)
+ boxes_to_text(item, **box_attributes)
for item in row
]
if isinstance(row, tuple)
- else boxes_to_text(row, **box_options)
+ else boxes_to_text(row, **box_attributes)
)
for row in items
]
@@ -111,7 +111,7 @@ def gridbox(self, elements=None, **box_options) -> str:
def sqrtbox(self, **options) -> str:
- _options = self.box_options.copy()
+ _options = self.box_attributes.copy()
_options.update(options)
options = _options
if self.index:
@@ -126,7 +126,7 @@ def sqrtbox(self, **options) -> str:
def superscriptbox(self, **options) -> str:
- _options = self.box_options.copy()
+ _options = self.box_attributes.copy()
_options.update(options)
options = _options
no_parenthesize = True
@@ -150,7 +150,7 @@ def superscriptbox(self, **options) -> str:
def subscriptbox(self, **options) -> str:
- _options = self.box_options.copy()
+ _options = self.box_attributes.copy()
_options.update(options)
options = _options
return "Subscript[%s, %s]" % (
@@ -163,7 +163,7 @@ def subscriptbox(self, **options) -> str:
def subsuperscriptbox(self, **options) -> str:
- _options = self.box_options.copy()
+ _options = self.box_attributes.copy()
_options.update(options)
options = _options
return "Subsuperscript[%s, %s, %s]" % (
@@ -177,7 +177,7 @@ def subsuperscriptbox(self, **options) -> str:
def rowbox(self, elements=None, **options) -> str:
- _options = self.box_options.copy()
+ _options = self.box_attributes.copy()
_options.update(options)
options = _options
parts_str = [boxes_to_text(element, **options) for element in self.items]
@@ -209,7 +209,7 @@ def rowbox(self, elements=None, **options) -> str:
def stylebox(self, **options) -> str:
options.pop("evaluation", None)
- _options = self.box_options.copy()
+ _options = self.box_attributes.copy()
_options.update(options)
options = _options
return boxes_to_text(self.boxes, **options)
diff --git a/test/format/format_tests.yaml b/test/format/format_tests.yaml
index 6254bbd02..b4bcd921d 100644
--- a/test/format/format_tests.yaml
+++ b/test/format/format_tests.yaml
@@ -139,8 +139,8 @@
mathml:
System`InputForm: -4
System`OutputForm: -4
- System`StandardForm: "\n-\n4\n"
- System`TraditionalForm: "\n-\n4\n"
+ System`StandardForm: "\n -\n 4\n"
+ System`TraditionalForm: "\n -\n 4\n"
text:
System`InputForm: '-4'
System`OutputForm: '-4'
@@ -158,8 +158,8 @@
mathml:
System`InputForm: -4.32
System`OutputForm: -4.32
- System`StandardForm: "\n-\n4.32\n"
- System`TraditionalForm: "\n-\n4.32\n"
+ System`StandardForm: "\n -\n 4.32\n"
+ System`TraditionalForm: "\n -\n 4.32\n"
text:
System`InputForm: '-4.32'
System`OutputForm: '-4.32'
@@ -177,8 +177,8 @@
mathml:
System`InputForm: -4.33
System`OutputForm: -4.3
- System`StandardForm: "\n-\n4.33\n"
- System`TraditionalForm: "\n-\n4.33\n"
+ System`StandardForm: "\n -\n 4.33\n"
+ System`TraditionalForm: "\n -\n 4.33\n"
text:
System`InputForm: -4.33`2.
System`OutputForm: '-4.3'
@@ -196,8 +196,8 @@
mathml:
System`InputForm: -4.32
System`OutputForm: -4.320
- System`StandardForm: "\n-\n4.32\n"
- System`TraditionalForm: "\n-\n4.32\n"
+ System`StandardForm: "\n -\n 4.32\n"
+ System`TraditionalForm: "\n -\n 4.32\n"
text:
System`InputForm: -4.32`4.
System`OutputForm: '-4.320'
@@ -271,10 +271,12 @@
System`OutputForm:
- '1 / (1 + 1 / (1 + 1 / a))'
- Fragile!
- System`StandardForm: &id001
- - "\n1\n\n1\n+\n\n1\n\n1\n+\n\n1\na\n\n\n\n\n"
+ System`StandardForm:
+ - "\n 1\n \n 1\n +\n \n 1\n \n 1\n +\n \n 1\n a\n \n \n \n \n"
+ - Fragile!
+ System`TraditionalForm:
+ - "\n 1\n \n 1\n +\n \n 1\n \n 1\n +\n \n 1\n a\n \n \n \n \n"
- Fragile!
- System`TraditionalForm: *id001
text:
System`InputForm: 1/(1 + 1/(1 + 1/a))
System`OutputForm: 1 / (1 + 1 / (1 + 1 / a))
@@ -292,8 +294,8 @@
mathml:
System`InputForm: <|a -> x, b -> y, c -> <|d -> t|>|>
System`OutputForm: '<|a -> x, b -> y, c -> <|d -> t|>|>'
- System`StandardForm: "\n<|\n\n\na\n->\nx\n\n,\n\nb\n->\ny\n\n,\n\nc\n->\n\n<|\n\nd\n->\nt\n\n|>\n\n\n\n|>\n"
- System`TraditionalForm: "\n<|\n\n\na\n->\nx\n\n,\n\nb\n->\ny\n\n,\n\nc\n->\n\n<|\n\nd\n->\nt\n\n|>\n\n\n\n|>\n"
+ System`StandardForm: "\n <|\n \n \n a\n ->\n x\n \n ,\n \n b\n ->\n y\n \n ,\n \n c\n ->\n \n <|\n \n d\n ->\n t\n \n |>\n \n \n \n |>\n"
+ System`TraditionalForm: "\n <|\n \n \n a\n ->\n x\n \n ,\n \n b\n ->\n y\n \n ,\n \n c\n ->\n \n <|\n \n d\n ->\n t\n \n |>\n \n \n \n |>\n"
text:
System`InputForm: <|a -> x, b -> y, c -> <|d -> t|>|>
System`OutputForm: <|a -> x, b -> y, c -> <|d -> t|>|>
@@ -311,8 +313,8 @@ Association[a -> x, b -> y, c -> Association[d -> t, Association[e -> u]]]:
mathml:
System`InputForm: "<|a -> x, b -> y, c -> <|d -> t, e -> u|>|>"
System`OutputForm: '<|a -> x, b -> y, c -> <|d -> t, e -> u|>|>'
- System`StandardForm: "\n<|\n\n\na\n->\nx\n\n,\n\nb\n->\ny\n\n,\n\nc\n->\n\n<|\n\n\nd\n->\nt\n\n,\n\ne\n->\nu\n\n\n|>\n\n\n\n|>\n"
- System`TraditionalForm: "\n<|\n\n\na\n->\nx\n\n,\n\nb\n->\ny\n\n,\n\nc\n->\n\n<|\n\n\nd\n->\nt\n\n,\n\ne\n->\nu\n\n\n|>\n\n\n\n|>\n"
+ System`StandardForm: "\n <|\n \n \n a\n ->\n x\n \n ,\n \n b\n ->\n y\n \n ,\n \n c\n ->\n \n <|\n \n \n d\n ->\n t\n \n ,\n \n e\n ->\n u\n \n \n |>\n \n \n \n |>\n"
+ System`TraditionalForm: "\n <|\n \n \n a\n ->\n x\n \n ,\n \n b\n ->\n y\n \n ,\n \n c\n ->\n \n <|\n \n \n d\n ->\n t\n \n ,\n \n e\n ->\n u\n \n \n |>\n \n \n \n |>\n"
text:
System`InputForm: <|a -> x, b -> y, c -> <|d -> t, e -> u|>|>
System`OutputForm: <|a -> x, b -> y, c -> <|d -> t, e -> u|>|>
@@ -330,8 +332,8 @@ Complex[1.09*^12, 3.]:
mathml:
System`InputForm: 1.09*^12 + 3.*I
System`OutputForm: '1.09×10^12 + 3. I'
- System`StandardForm: "\n\n1.09\n*^\n12\n\n+\n\n3.\n \nI\n\n"
- System`TraditionalForm: "\n\n1.09\n×\n\n10\n12\n\n\n+\n\n3.\n\nI\n\n"
+ System`StandardForm: "\n \n 1.09\n *^\n 12\n \n +\n \n 3.\n \n I\n \n"
+ System`TraditionalForm: "\n \n 1.09\n ×\n \n 10\n 12\n \n \n +\n \n 3.\n \n I\n \n"
text:
System`InputForm: 1.09*^12 + 3.*I
System`OutputForm: "1.09\xD710^12 + 3. I"
@@ -458,18 +460,8 @@ Graphics[{}]:
mathml:
System`InputForm: "Grid[{{"Spanish", "Hola!"}, {"Portuguese", "Olà!"}, {"English", "Hi!"}}]"
System`OutputForm: 'Spanish Hola!Portuguese Olà!English Hi!'
- System`StandardForm: "\nSpanishHola!\n\
- PortugueseOl\xE0!\nEnglishHi!\n\
- "
- System`TraditionalForm: "\nSpanishHola!\n\
- PortugueseOl\xE0!\nEnglishHi!\n\
- "
+ System`StandardForm: "\n \n \n Spanish\n \n \n Hola!\n \n \n \n \n Portuguese\n \n \n Olà!\n \n \n \n \n English\n \n \n Hi!\n \n \n"
+ System`TraditionalForm: "\n \n \n Spanish\n \n \n Hola!\n \n \n \n \n Portuguese\n \n \n Olà!\n \n \n \n \n English\n \n \n Hi!\n \n \n"
text:
System`InputForm: "Grid[{{\"Spanish\", \"Hola!\"}, {\"Portuguese\", \"Ol\xE0!\"\
}, {\"English\", \"Hi!\"}}]"
@@ -497,20 +489,8 @@ Grid[{{a,b},{c,d}}]:
mathml:
System`InputForm: Grid[{{a, b}, {c, d}}]
System`OutputForm: 'a bc d'
- System`StandardForm: '
-
- ab
-
- cd
-
- '
- System`TraditionalForm: '
-
- ab
-
- cd
-
- '
+ System`StandardForm: "\n \n \n a\n \n \n b\n \n \n \n \n c\n \n \n d\n \n \n"
+ System`TraditionalForm: "\n \n \n a\n \n \n b\n \n \n \n \n c\n \n \n d\n \n \n"
text:
System`InputForm: Grid[{{a, b}, {c, d}}]
System`OutputForm: 'a b
@@ -543,8 +523,8 @@ Integrate[F[x], {x, a, g[b]}]:
mathml:
System`InputForm: 'Integrate[F[x], {x, a, g[b]}]'
System`OutputForm: 'Integrate[F[x], {x, a, g[b]}]'
- System`StandardForm: "\n\n∫\na\n\ng\n[\nb\n]\n\n\n\n\nF\n[\nx\n]\n\n\n\n𝑑\nx\n\n"
- System`TraditionalForm: "\n\n∫\na\n\ng\n(\nb\n)\n\n\n\n\nF\n(\nx\n)\n\n\n\n𝑑\nx\n\n"
+ System`StandardForm: "\n \n ∫\n a\n \n g\n [\n b\n ]\n \n \n \u2062\n \n F\n [\n x\n ]\n \n \u2062\n \n 𝑑\n x\n \n"
+ System`TraditionalForm: "\n \n ∫\n a\n \n g\n (\n b\n )\n \n \n \u2062\n \n F\n (\n x\n )\n \n \u2062\n \n 𝑑\n x\n \n"
text:
System`InputForm: Integrate[F[x], {x, a, g[b]}]
System`OutputForm: Integrate[F[x], {x, a, g[b]}]
@@ -568,8 +548,8 @@ MatrixForm[{{a,b},{c,d}}]:
mathml:
System`InputForm: MatrixForm[{{a, b}, {c, d}}]
System`OutputForm: 'a bc d'
- System`StandardForm: "\n(\n\nab\ncd\n\n)\n"
- System`TraditionalForm: "\n(\n\nab\ncd\n\n)\n"
+ System`StandardForm: "\n (\n\n \n \n a\n \n \n b\n \n \n \n \n c\n \n \n d\n \n \n\n )\n"
+ System`TraditionalForm: "\n (\n\n \n \n a\n \n \n b\n \n \n \n \n c\n \n \n d\n \n \n\n )\n"
text:
System`InputForm: MatrixForm[{{a, b}, {c, d}}]
System`OutputForm: 'a b
@@ -607,10 +587,10 @@ Sqrt[1/(1+1/(1+1/a))]:
- 'Sqrt[1 / (1 + 1 / (1 + 1 / a))]'
- Fragile!
System`StandardForm:
- - "\n\n1\n\n1\n+\n\n1\n\n1\n+\n\n1\na\n\n\n\n\n\n"
+ - "\n \n 1\n \n 1\n +\n \n 1\n \n 1\n +\n \n 1\n a\n \n \n \n \n \n"
- Fragile!
System`TraditionalForm:
- - "\n\n1\n\n1\n+\n\n1\n\n1\n+\n\n1\na\n\n\n\n\n\n"
+ - "\n \n 1\n \n 1\n +\n \n 1\n \n 1\n +\n \n 1\n a\n \n \n \n \n \n"
- Fragile!
text:
System`InputForm: Sqrt[1/(1 + 1/(1 + 1/a))]
@@ -633,8 +613,8 @@ Subscript[a, 4]:
System`OutputForm:
- 'Subscript[a, 4]'
- Fragile!
- System`StandardForm: "\na\n4\n"
- System`TraditionalForm: "\na\n4\n"
+ System`StandardForm: "\n a\n 4\n"
+ System`TraditionalForm: "\n a\n 4\n"
text:
System`InputForm: Subscript[a, 4]
System`OutputForm: Subscript[a, 4]
@@ -654,8 +634,8 @@ Subsuperscript[a, p, q]:
mathml:
System`InputForm: Subsuperscript[a, p, q]
System`OutputForm: 'Subsuperscript[a, p, q]'
- System`StandardForm: "\na\np\nq\n"
- System`TraditionalForm: "\na\np\nq\n"
+ System`StandardForm: "\n a\n p\n q\n"
+ System`TraditionalForm: "\n a\n p\n q\n"
text:
System`InputForm: Subsuperscript[a, p, q]
System`OutputForm: Subsuperscript[a, p, q]
@@ -716,8 +696,8 @@ TableForm[{{a,b},{c,d}}]:
mathml:
System`InputForm: TableForm[{{a, b}, {c, d}}]
System`OutputForm: 'a bc d'
- System`StandardForm: "\nab\ncd\n"
- System`TraditionalForm: "\nab\ncd\n"
+ System`StandardForm: "\n \n \n a\n \n \n b\n \n \n \n \n c\n \n \n d\n \n \n"
+ System`TraditionalForm: "\n \n \n a\n \n \n b\n \n \n \n \n c\n \n \n d\n \n \n"
text:
System`InputForm: TableForm[{{a, b}, {c, d}}]
System`OutputForm: 'a b
@@ -807,7 +787,7 @@ a^(g[b]/c):
mathml:
System`InputForm: a^(g[b]/c)
System`OutputForm: 'a ^ (g[b] / c)'
- System`TraditionalForm: "\na\n\n\ng\n(\nb\n)\n\nc\n\n"
+ System`TraditionalForm: "\n a\n \n \n g\n (\n b\n )\n \n c\n \n"
text:
System`InputForm: a^(g[b]/c)
System`OutputForm: a ^ (g[b] / c)
@@ -825,8 +805,8 @@ a^4:
mathml:
System`InputForm: 'a^4'
System`OutputForm: 'a ^ 4'
- System`StandardForm: "\na\n4\n"
- System`TraditionalForm: "\na\n4\n"
+ System`StandardForm: "\n a\n 4\n"
+ System`TraditionalForm: "\n a\n 4\n"
text:
System`InputForm: a^4
System`OutputForm: a ^ 4
@@ -870,7 +850,7 @@ a+PrecedenceForm[b+c,10]:
System`StandardForm: 'a+\left(b+c\right)'
mathml:
System`OutputForm: 'a + (b + c)'
- System`StandardForm: "\na\n+\n\n(\n\nb\n+\nc\n\n)\n\n"
+ System`StandardForm: "\n a\n +\n \n (\n \n b\n +\n c\n \n )\n \n"
text:
System`InputForm: 'a + (PrecedenceForm[b + c, 10])'
System`OutputForm: 'a + (b + c)'
diff --git a/test/format/test_format.py b/test/format/test_format.py
index ba469dafc..adf27bbc9 100644
--- a/test/format/test_format.py
+++ b/test/format/test_format.py
@@ -50,8 +50,6 @@ def load_tests(key):
of the final formats ("text", "latex", "mathml") and produce two list:
the first with the mandatory tests, and the other with "fragile" tests
"""
- global all_tests
- global MATHML_STRICT
def is_fragile(assert_msg: str) -> bool:
"""
diff --git a/test/test_session.py b/test/test_session.py
index 4f04fb0df..08d779a1f 100644
--- a/test/test_session.py
+++ b/test/test_session.py
@@ -55,7 +55,7 @@ def test_session_format_evaluation():
assert session.format_result(form="text") == "a / b"
assert session.format_result(form="latex") == "\\frac{a}{b}"
assert session.format_result(form="xml") == (
- ''
+ ''
)