diff --git a/admin-tools/make-JSON-tables.sh b/admin-tools/make-JSON-tables.sh
index 8a166d9da..5172988e8 100755
--- a/admin-tools/make-JSON-tables.sh
+++ b/admin-tools/make-JSON-tables.sh
@@ -6,6 +6,8 @@ PYTHON=${PYTHON:-python}
cd $mydir/../mathics/data
mathics3-generate-json-table \
+ --field=latex-named-characters \
+ --field=unicode-to-latex \
--field=ascii-operator-to-symbol \
--field=ascii-operator-to-unicode \
--field=ascii-operator-to-wl-unicode \
diff --git a/mathics/core/convert/op.py b/mathics/core/convert/op.py
index f93b0d7a8..c0fad95b1 100644
--- a/mathics/core/convert/op.py
+++ b/mathics/core/convert/op.py
@@ -29,10 +29,12 @@
unicode_operator_to_ascii = {
val: operator_to_ascii[key] for key, val in operator_to_unicode.items()
}
-unicode_to_amslatex = OPERATOR_CONVERSION_TABLES["unicode-to-amslatex"]
+UNICODE_TO_AMSLATEX = OPERATOR_CONVERSION_TABLES["unicode-to-amslatex"]
+UNICODE_TO_LATEX = OPERATOR_CONVERSION_TABLES["unicode-to-latex"]
-amstex_operators = {
+
+AMSTEX_OPERATORS = {
"\u2032": "'",
"\u2032\u2032": "''",
"\u2062": " ",
@@ -92,7 +94,7 @@ def hex_form_code(char_str):
return hex(ord(char_str))[2:]
for candidate_dict in (
- unicode_to_amslatex,
+ UNICODE_TO_AMSLATEX,
# amstex_operators,
unicode_operator_to_ascii,
):
@@ -106,10 +108,12 @@ def hex_form_code(char_str):
# if it is already an ascii, return without changes.
if unicode_op.isascii():
return unicode_op
-
- # the `unicode_op` cannot be converted into an ascii string. Show a
- # warning and return a `\symbol{code}` expression.
- logging.warning(
- "Unicode op" + unicode_op + "(" + hex_form_code(unicode_op) + ") not found."
- )
- return '\\symbol{"' + hex_form_code(unicode_op) + "}"
+ try:
+ return r"\text{" + UNICODE_TO_LATEX[unicode_op] + "}"
+ except KeyError:
+ # the `unicode_op` cannot be converted into an ascii string. Show a
+ # warning and return a `\symbol{code}` expression.
+ logging.warning(
+ "Unicode op" + unicode_op + "(" + hex_form_code(unicode_op) + ") not found."
+ )
+ return '\\symbol{"' + hex_form_code(unicode_op) + "}"
diff --git a/mathics/format/render/latex.py b/mathics/format/render/latex.py
index fe9adc75c..e432992ca 100644
--- a/mathics/format/render/latex.py
+++ b/mathics/format/render/latex.py
@@ -31,7 +31,12 @@
)
from mathics.builtin.colors.color_directives import RGBColor
from mathics.core.atoms import String
-from mathics.core.convert.op import amstex_operators, get_latex_operator
+from mathics.core.convert.op import (
+ AMSTEX_OPERATORS,
+ UNICODE_TO_AMSLATEX,
+ UNICODE_TO_LATEX,
+ get_latex_operator,
+)
from mathics.core.exceptions import BoxConstructError
from mathics.core.formatter import (
add_conversion_fn,
@@ -57,26 +62,38 @@
"^": r"{}^{\wedge}",
"~": r"\sim{}",
"|": r"\vert{}",
- "\u222b": r"\int ",
- "\u2146": r"\, d",
- "\uF74C": r"\, d",
- "\U0001D451": r"\, d",
- "\u00d7": r"\times ",
}
-TEX_TEXT_REPLACE = TEX_REPLACE.copy()
+TEX_TEXT_REPLACE = {
+ r"{": r"\{",
+ r"}": r"\}",
+ r"_": r"\_",
+ "<": r"$<$",
+ ">": r"$>$",
+ "~": r"$\sim$",
+ "|": r"$\vert$",
+ "\\": r"$\backslash$",
+ "^": r"${}^{\wedge}$",
+}
+
+TEX_REPLACE.update(UNICODE_TO_AMSLATEX)
+TEX_REPLACE.update(
+ {
+ key: r"\text{" + val + "}"
+ for key, val in UNICODE_TO_LATEX.items()
+ if key not in TEX_REPLACE
+ }
+)
+
+TEX_TEXT_REPLACE.update(UNICODE_TO_LATEX)
TEX_TEXT_REPLACE.update(
{
- "<": r"$<$",
- ">": r"$>$",
- "~": r"$\sim$",
- "|": r"$\vert$",
- "\\": r"$\backslash$",
- "^": r"${}^{\wedge}$",
- "\u222b": r"$\int$ ",
- "\uF74C": r"\, d",
- "\u00d7": r"$\times$",
+ key: f"${val}$"
+ for key, val in UNICODE_TO_AMSLATEX.items()
+ if key not in TEX_TEXT_REPLACE
}
)
+
+
TEX_REPLACE_RE = re.compile("([" + "".join([re.escape(c) for c in TEX_REPLACE]) + "])")
@@ -117,7 +134,7 @@ def render(format, string, in_text=False):
return render("%s", text)
else:
# First consider the special cases
- op_string = amstex_operators.get(text, None)
+ op_string = AMSTEX_OPERATORS.get(text, None)
if op_string:
return op_string
diff --git a/test/format/format_tests.yaml b/test/format/format_tests.yaml
index b8eb032e6..a94ae3af1 100644
--- a/test/format/format_tests.yaml
+++ b/test/format/format_tests.yaml
@@ -64,10 +64,10 @@
'"\[Pi] is a trascendental number"':
msg: A String
latex:
- System`InputForm: "\\text{``\u03C0 is a trascendental number''}"
- System`OutputForm: "\\text{\u03C0 is a trascendental number}"
- System`StandardForm: "\\text{\u03C0 is a trascendental number}"
- System`TraditionalForm: "\\text{\u03C0 is a trascendental number}"
+ System`InputForm: "\\text{``$\\pi$ is a trascendental number''}"
+ System`OutputForm: "\\text{$\\pi$ is a trascendental number}"
+ System`StandardForm: "\\text{$\\pi$ is a trascendental number}"
+ System`TraditionalForm: "\\text{$\\pi$ is a trascendental number}"
mathml:
System`InputForm: "\u03C0 is a trascendental number"
System`OutputForm: "\u03C0 is a trascendental number"
@@ -455,12 +455,12 @@ Graphics[{}]:
"Grid[{{\"Spanish\", \"Hola!\"},{\"Portuguese\", \"Ol\xE0!\"},{\"English\", \"Hi!\"}}]":
msg: Strings in a GridBox
latex:
- System`InputForm: \text{Grid[\{\{"Spanish", "Hola!"\}, \{"Portuguese", "Olà!"\}, \{"English", "Hi!"\}\}]}
+ System`InputForm: \text{Grid[\{\{"Spanish", "Hola!"\}, \{"Portuguese", "Ol\`{a}!"\}, \{"English", "Hi!"\}\}]}
System`OutputForm: '\text{Spanish Hola!\newline
\newline
- Portuguese Olà!\newline
+ Portuguese Ol\`{a}!\newline
\newline
@@ -469,9 +469,9 @@ Graphics[{}]:
}
'
System`StandardForm: "\\begin{array}{cc} \\text{Spanish} & \\text{Hola!}\\\\ \\\
- text{Portuguese} & \\text{Ol\xE0!}\\\\ \\text{English} & \\text{Hi!}\\end{array}"
+ text{Portuguese} & \\text{Ol\\`{a}!}\\\\ \\text{English} & \\text{Hi!}\\end{array}"
System`TraditionalForm: "\\begin{array}{cc} \\text{Spanish} & \\text{Hola!}\\\\\
- \ \\text{Portuguese} & \\text{Ol\xE0!}\\\\ \\text{English} & \\text{Hi!}\\end{array}"
+ \ \\text{Portuguese} & \\text{Ol\\`{a}!}\\\\ \\text{English} & \\text{Hi!}\\end{array}"
mathml:
System`InputForm: "Grid[{{"Spanish", "Hola!"}, {"Portuguese", "Olà!"}, {"English", "Hi!"}}]"
System`OutputForm: 'Spanish Hola!Portuguese Olà!English Hi!'
@@ -800,7 +800,7 @@ TableForm[{{a,b},{c,d}}]:
msg: A greek letter symbol
latex:
System`InputForm: \alpha
- System`OutputForm: \text{α}
+ System`OutputForm: \text{$\alpha$}
System`StandardForm: \alpha
System`TraditionalForm: \alpha
mathml:
diff --git a/test/format/test_latex.py b/test/format/test_latex.py
index bd631a191..d7e851e9e 100644
--- a/test/format/test_latex.py
+++ b/test/format/test_latex.py
@@ -22,6 +22,8 @@ def get_latex(wl_expression):
@pytest.mark.parametrize(
("testcase", "expected"),
[
+ ("_", r"\_"),
+ ('"_"', r"\text{\_}"),
('"["', r"\text{[}"),
('"]"', r"\text{]}"),
("HoldForm[A[[1,2]]]", r"A\left[\left[1, 2\right]\right]"),
@@ -31,6 +33,22 @@ def get_latex(wl_expression):
("CupCap[c,b]", r"c \stackrel{\smile}{\frown} b"),
("Congruent[c,b]", r"c \equiv b"),
("Pi", r"\pi"),
+ # In symbols and expressions
+ (r"\[Alpha]", r"\alpha"),
+ # In this case, without the linebreak, the tokeniser
+ # produce an error...
+ ("\\[Alpha]s\n", r"\text{$\alpha$s}"),
+ (r"\[Alpha] s", r"s \alpha"),
+ (r"\[AAcute]", r"\text{\'{a}}"),
+ # In this case, without the linebreak, the tokeniser
+ # produce an error...
+ ("\\[AAcute]s\n", r"\text{\'{a}s}"),
+ (r"\[AAcute] s", r"s \text{\'{a}}"),
+ # In strings
+ (r'"\[Alpha]"', r"\text{$\alpha$}"),
+ (r'"\[Alpha]s"', r"\text{$\alpha$s}"),
+ (r'"\[AAcute]"', r"\text{\'{a}}"),
+ (r'"M\[AAcute]s!"', r"\text{M\'{a}s!}"),
],
)
def test_expressions(testcase, expected):