Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v4-beta.3 linebreak not respected with \text (and other issues) #3098

Open
TrebledJ opened this issue Sep 12, 2023 · 7 comments
Open

v4-beta.3 linebreak not respected with \text (and other issues) #3098

TrebledJ opened this issue Sep 12, 2023 · 7 comments
Labels
Accepted Issue has been reproduced by MathJax team Code Example Contains an illustrative code example, solution, or work-around Expected Behavior This is how MathJax works v4
Milestone

Comments

@TrebledJ
Copy link

TrebledJ commented Sep 12, 2023

Issue Summary

Linebreak issue with text elements.

Steps to Reproduce:

  1. Open web page.
  2. See math sticking out of container and not breaking.
  3. Cry.

Linebreak not working with text. Math is a bit better, but also sticks out a bit.

For example:

$\texttt{The quick brown } \text{fox jumps } \textsf{over the lazy dog}\dots\ \texttt{And } \texttt{over } \texttt{the } \texttt{rainbow } \texttt{dost } \texttt{thy } \texttt{chicken } \texttt{poop } \texttt{fly}\dots$

There are also instances when output errors occur for regular LaTeX and for \breaks.

$$
e^{i\pi} + 1 = 0
\qquad
\begin{align}
x + y + z &= 1 \\\\
2x - y + 3z &= 2 \\\\
4x - 5y + 10z &= 3 \\\\
\end{align}
$$

$\texttt{Maybe (Either (a, a) (Bool, a))} \break \equiv \texttt{(Maybe a, Maybe a)}$
$\texttt{Maybe (Either (a, a) (Bool, a))} \break = \texttt{(Maybe a, Maybe a)}$

All of these are shown in the supporting demo.

Technical details:

  • MathJax Version: 4.0.0-beta.3
  • Client OS: MacOS 12.6.8
  • Browser: Chrome Version 116.0.5845.179 (Official Build) (x86_64)

I am using the following MathJax configuration:

MathJax = {
    tex: {
        inlineMath: [
            [
                '$', '$'
            ],
            [
                '\\(', '\\)'
            ]
        ],
    },
    svg: {
        fontCache: 'global',
        displayOverflow: 'linebreak',
    },
};

and loading MathJax via

<script defer id="MathJax-script" src="https://cdn.jsdelivr.net/npm/mathjax@4.0.0-beta.3/tex-mml-svg.js" type="text/javascript"></script>

Supporting information:

  • Example Page: https://trebledj.github.io/mathjax/
  • Source: https://github.com/TrebledJ/trebledj.github.io/blob/abbe08f751793bff666545ebbbcd4b0acd129aab/content/pages/1970-01-01-mathjax.md
  • Screenshot below. Blue region is the .post-body container.
    Screenshot 2023-09-13 at 2 18 55 AM
  • Console errors:
    tex-mml-svg.js:1 Uncaught TypeError: Cannot set property FontData of #<Object> which has only a getter
        at $a (tex-mml-svg.js:1:25309)
        at $a (tex-mml-svg.js:1:25316)
        at $a (tex-mml-svg.js:1:25316)
        at $a (tex-mml-svg.js:1:25316)
        at $a (tex-mml-svg.js:1:25316)
        at Ka (tex-mml-svg.js:1:25511)
        at chtml.js:1:164264
        at chtml.js:1:171060
    tex-mml-svg.js:1 Uncaught (in promise) Error: Component chtml not loaded
        at tex-mml-svg.js:1:1258697
        at tex-mml-svg.js:1:1260555
    tex-mml-svg.js:1 Uncaught (in promise) Error: Component chtml not loaded
        at tex-mml-svg.js:1:1258697
        at tex-mml-svg.js:1:1260555
    
@TrebledJ TrebledJ changed the title v4-beta.3 linebreak not respected (and other issues) v4-beta.3 linebreak not respected with \text (and other issues) Sep 12, 2023
@pkra
Copy link
Contributor

pkra commented Sep 14, 2023

I believe you need to load the textmacros extension to get \\ to work inside \text.

@dpvc
Copy link
Member

dpvc commented Sep 14, 2023

I believe you need to load the textmacros extension to get \\ to work inside \text.

While true, none of the example use \\ inside \text.

@dpvc
Copy link
Member

dpvc commented Sep 14, 2023

MathJax's rules for breaking in-line math are based on the TeX rules for in-line breaks, which are basically that breaks can occur at characters that have class BIN or REL (binary operators and relations) at the top level of the expression. Your first example has no binary or relational operator (the \dots produce characters with class INNER), so there is no valid breakpoint in that expression. In particular, the spaces inside the \text elements are not valid breakpoints in TeX; if you put this expression into actual TeX, it also will not break. So MathJax is doing what it was intended to do in this case.

Your second example, with the align environment, is not valid LaTeX markup; the error message is correct and similar to the one you get if you put this expression into actual LaTeX. The align environment is a top-level environment, and can't be placed inside other expressions. For that, you need to use the aligned environment. If you switch to that, the expression should work for you.

Your third and fourth examples that use \break are more subtle. MathJax translates your expressions into MathML internally, and there are some side-effects of the MathML that are occurring here. MathML has a concept called an embellished operator, which is intended to allow things like an equal sign with a question mark over top to be treated (for spacing and line-breaking purposes) as the operator at their core, so that the embellishments don't interfere with the spacing. An operator is embellished if it is in a container whose only other elements are "spacelike" elements (there are also some other ways to be embellished). A spacelike element is either an mspace or an mtext element (or some other more complicated things), and a container can be the expression itself. It is natural to consider mspace to be spacelike, but I've never fully understood why the specification makes mtext be spacelike. Apparently, it is because some people use mtext with space characters to perform spacing, but that seems a poor reason to make all mtext elements be spacelike.

In your expression \texttt{Maybe (Either (a, a) (Bool, a))} \break \equiv \texttt{(Maybe a, Maybe a)}, the underlying MathML is

<math xmlns="http://www.w3.org/1998/Math/MathML">
  <mtext mathvariant="monospace">Maybe (Either (a, a) (Bool, a))</mtext>
  <mspace linebreak="newline"></mspace>
  <mo>&#x2261;</mo>
  <mtext mathvariant="monospace">(Maybe a, Maybe a)</mtext>
</math>

Note that this consists of an operator (the equivalent sign) together with mtext and mspace elements, all contained in the math element container, so the mo is considered an embellished operator. That means that it, together with its embellishments (the mspace and mtext elements) are all treated as a unit. That is why the break indicated by the mspace is not being shown.

This is the same issue for your case that involves the equal sign as well. Ironically, it is also the case for the long text example at the bottom of your supporting demo page. There is one operator in that expression (the period), and the rest are text elements, so the entire sentence is an embellished operator, and treated as a single (unbreakable) unit, so no line-breaking occurs. This illustrates why I find the idea that mtext elements are to be "spacelike" to be so inappropriate.

One way around the problem is to add any non-text, non-space element into the expression. For example, adding {} to the beginning of the expression, as in

{}\texttt{Maybe (Either (a, a) (Bool, a))} \break \equiv \texttt{(Maybe a, Maybe a)}

would make the operator no longer be an embellished one, and so line breaking would occur as expected. The same goes for the long expression in your demo (or you could put the period inside one of the preceding \text{} macro, so there would be no operator at all).

Alternatively, you could adjust how MathJax interprets "spacelike" to make mtext elements spacelike only if they consist only of actual space characters, and not make mspace spacelike if it is specifying a line break. To do that, you can incorporate

MathJax = {
  startup: {
    ready() {
      const {MML} = MathJax._.core.MmlTree.MML;
      MML.mspace = class myMmlMspace extends MML.mspace {
        get isSpacelike() {
          return this.attributes.getExplicit('linebreak') === undefined && this.canBreak;
        }
      }
      MML.mtext = class myMmlMtext extends MML.mtext {
        get isSpacelike() {
          const attributes = this.attributes;
          const spaces = !!this.getText().match(/^\s*$/);
          return spaces && (attributes.getExplicit('mathbackground') === undefined &&
                            attributes.getExplicit('background') === undefined &&
                            attributes.getExplicit('style') === undefined);
        }
      }
      MathJax.startup.defaultReady();
    }
  }
};

into your MathJax configuration. Then the expression you have used should break as you would expect.

@dpvc dpvc added Accepted Issue has been reproduced by MathJax team Expected Behavior This is how MathJax works v4 labels Sep 14, 2023
@dpvc
Copy link
Member

dpvc commented Sep 14, 2023

I forgot to mention the error messages you received. That is due to having switched to CHTML output using the contextual menu. It turns out that the way exports are handled in ESM modules is causing a problem loading the output/chtml and output/svg extensions used to switch renderers. I will have a fix for that in the next beta release, but for now, you can use the contextual menu to switch back to SVG and the message should go away.

@dpvc
Copy link
Member

dpvc commented Sep 14, 2023

Finally, it would help us if you only include one type of problem in one issue post. Your line-break issues could all be in one, but the problem with the expression involving the align environment, and the issue with the error messages in the console would be better in separate issues, as they are unrelated to the line breaking. Having a separate issue tracker for each makes it easier for us to track and resolve them independently. Thanks!

@TrebledJ
Copy link
Author

Thanks for the comprehensive explanation!

After some testing, placing {} at the start didn't seem to work for me, but placing it somewhere in the middle works. E.g.

\texttt{Maybe (Either (a, a) (Bool, a))} {} \break \equiv \texttt{(Maybe a, Maybe a)}

Another thing I forgot to mention was automatic linebreaking (i.e. without \break). I've put that in a different issue: #3099.

P.S. Apologies for not testing my align tex beforehand and conflating this issue. I had assumed the example would work. 🥲

@dpvc
Copy link
Member

dpvc commented Sep 15, 2023

It shouldn't matter where the {} is, but wherever it works for you is fine.

Note that it should only matter when there is only one operator in the expression. If you have \text{...} \equiv \text{...} \equiv \text{...} it should not be needed.

@dpvc dpvc added this to the v4.0 milestone Sep 15, 2023
dpvc added a commit to mathjax/MathJax-src that referenced this issue Sep 15, 2023
Prevent setting a propery that has a getter.  (mathjax/MathJax#3098)
dpvc added a commit to mathjax/MathJax-src that referenced this issue Sep 19, 2023
Update check for spacelike mml nodes to be more sensible.  (mathjax/MathJax#3098)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Accepted Issue has been reproduced by MathJax team Code Example Contains an illustrative code example, solution, or work-around Expected Behavior This is how MathJax works v4
Projects
None yet
Development

No branches or pull requests

3 participants