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

Nested Math in Non-Default Text Fix #1111

Merged
merged 15 commits into from Feb 19, 2018

Conversation

ry-randall
Copy link
Member

@ry-randall ry-randall commented Jan 28, 2018

@ry-randall
Copy link
Member Author

ry-randall commented Jan 28, 2018

One difference with math vs text font commands, is text commands change one aspect of the font (weight, shape, or family). Math commands change all aspects of the font (weight, shape, and family). I'm wondering, probably as a cleanup item, if we'd want to leverage options.withFont() for math, and options.withFontFamily/Shape/Weight for text. Currently options.withFontFamily is being used for math fonts as well a text families.

Edit - Opened a separate issue here: #1112 for tracking purposes. Not sure it's a high priority though, nor do I think it should block this.

Edit 2 - This PR takes care of this.

Copy link
Member

@kevinbarabash kevinbarabash left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Glad to see that the change was relatively straightforward.

src/Options.js Outdated
withMathMode(): Options {
return this.extend({
fontFamily: 'mathit',
});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this also reset the fontShape and fontWeight?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. I actually thought the same thing until I broke the tests.

it("should render \\textsf{\\textbf{$\\mathrm{\\textsf{A}}$}} with the correct font", function() {
        const markup = katex.renderToString("\\textsf{\\textbf{$\\mathrm{\\textsf{A}}$}}");
        expect(markup).toContain("<span class=\"mord textsf textbf\">A</span>");
});

Basically when going from text mode, to math mode, then back to text mode, it should retain the font weight/shape from the first time it was in text mode. Hope that makes sense.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should it not also retain the fontFamily? What happens in this case?

\textsf{\textbf{$\textbf{A}$}}

It feels like we need to:

  • store font styles separate for math and text modes
  • store which mode we're currently in

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great catch. This means I'll probably resolve #1112 in the process.

@@ -259,7 +259,9 @@ groupTypes.styling = function(group, options) {
};

const newStyle = styleMap[group.value.style];
const newOptions = options.havingStyle(newStyle);
const newOptions = group.value.mathStart ?
options.havingStyle(newStyle).withMathMode() :
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would've expected options.withMathMode() to be sufficient for this case.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I follow this. options.withMathMode() instead of options.havingStyle(newStyle)?

src/Options.js Outdated
fontFamily: string | void;
font: string;
oldTextFont: boolean;
fontFamily: string;
fontWeight: string;
fontShape: string;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking we'd have properties like:

mathFont: string;
textFontFamily: string;
textFontWeight: string;
textFontShape: string;
mode: "text" | "math";

and then the API, would look something like:

.withMathFont(font: string);
.withTextFontFamily(family: string);
.withTextFontWeight(weight: string);
.withTextFontShape(shape: string);

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, how would the old text fonts be handled? I.e. \rm \it. They behave similar to math fonts in that they change all aspects of the font.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I forgot about \rm \it, but I think we could modify the suggested API in the following way:

.withTextFontFamily(family: string, isOldCommand: boolean = false);
.withTextFontWeight(weight: string, isOldCommand: boolean = false);
.withTextFontShape(shape: string, isOldCommand: boolean = false);

If isOldCommand is true, we would reset the other text font properties back to their defaults.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think withTextFontFamily/Weight/Shape would make sense with old font commands. Old font commands effectively change all 3, not just one. Additionally you'd lose the state when you exit the old font mode (i.e. \textbf{{\it hello} world}). They behave much more similar to the math commands, which is why I opted to leave the naming conventions generic.

Really wish LaTeX fonts weren't so confusing :(

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

withTextFontFamily would look something like:

withTextFontFamily(family: string, isOldCommand: boolean) {
   if (isOldCommand) {
       this.extend({
           fontFamily: fontFamily || this.fontFontFamily,
           fontWeight: "",
           fontStyle: "",
      });
   } else {
        this.extend({
            fontFamily: fontFamily || this.fontFamily,
        });
   }
};

As for the question of losing state, {\rm hello} creates a new options object when processing that group which shouldn't affect the options object for the \textbf group.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I'll give this more thought either later today or tomorrow. Thanks for the quick review.

@edemaine
Copy link
Member

#1073 points out some inconsistencies (compared to LaTeX) in the font size when using \llap. Will this PR help with this? Or perhaps unrelated.

@ry-randall
Copy link
Member Author

@edemaine I don't believe this is related. This PR isn't concerned with the font sizing.

@kevinbarabash
Copy link
Member

@rrandallcainc friendly ping to see where things are at with this PR.

@ry-randall
Copy link
Member Author

@kevinbarabash I expect to get back to this early this week. Thanks for checking in.

@codecov
Copy link

codecov bot commented Feb 19, 2018

Codecov Report

Merging #1111 into master will increase coverage by 0.02%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #1111      +/-   ##
==========================================
+ Coverage   79.59%   79.61%   +0.02%     
==========================================
  Files          59       59              
  Lines        3871     3876       +5     
  Branches      648      652       +4     
==========================================
+ Hits         3081     3086       +5     
  Misses        656      656              
  Partials      134      134
Impacted Files Coverage Δ
src/functions/operatorname.js 45.16% <ø> (ø) ⬆️
src/buildMathML.js 93.5% <100%> (ø) ⬆️
src/functions/text.js 100% <100%> (ø) ⬆️
src/functions/font.js 95.45% <100%> (+0.45%) ⬆️
src/functions/styling.js 100% <100%> (ø) ⬆️
src/Options.js 92.45% <100%> (+0.29%) ⬆️
src/buildCommon.js 84.97% <100%> (+0.06%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update b341034...953eab0. Read the comment docs.

@ry-randall
Copy link
Member Author

@kevinbarabash I apologize for the delay on this one. This should be ready for another look.

Copy link
Member

@kevinbarabash kevinbarabash left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The more I look at the implementation of makOrd the more I don't like it, but this PR was meant to fix a particular problem in the behavior, not refactor all of the code. I would like to tackle that eventually, but not right now.

For now this is looking pretty good. It could use a some comments and/or better typing to reduce confusion between font, fontFamily, and fontName. After that this should be good to go.

@@ -33,7 +33,7 @@ const mainitLetters = [
const lookupSymbol = function(
value: string,
// TODO(#963): Use a union type for this.
fontFamily: string,
fontName: string,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does fontFamily in Options.js differ from fontName here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A fontFamily applies to a group of fonts. For example, the SansSerif family can be: regular, bold, or italic. In order to properly lookup the symbol, we need a specific font, not a font family.

// string value.
fontFamily?: string | void;
font?: string;
fontFamily?: string;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does font differ from fontFamily? Maybe add some comments and/or be more specific about the types.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Font families are a group of fonts, not a specific font. I'll add a comment.

return this.extend({
fontFamily: fontFamily || this.fontFamily,
font,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we aren't resetting the values of fontFamily, fontWeight, etc. I assume that font takes precedence.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct. Also, we can't safely reset the values of fontFamily/weight/etc.

Consider the following: \textbf{$\mathsf{\textsf{a}$}. This should render as a bold, sans-serif "a", but if we reset, we would get a regular sans-serif "a"

@@ -88,7 +88,7 @@ exports[`An implicit group parser within optional groups should work with \\colo
]
`;

exports[`An implicit group parser within optional groups should work with sizing commands: \\sqrt[\\small 3]{x} 1`] = `
exports[`An implicit group parser within optional groups should work with old font functions: \\sqrt[\\tt 3]{x} 1`] = `
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like the order of these changed, but the parse trees look the same.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I fixed a typo, assuming that's why?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I didn't mean to suggest that anything needed changing here.

\begin{matrix}
\text{for $a < b$ and $ c < d $}. \\
\textsf{for $a < b$ and $ c < d $}. \\
\textsf{for $a < b \textbf{ and } c < d $}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to have some tests for the behavior of old fonts.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll update.

@ry-randall
Copy link
Member Author

@kevinbarabash Updated.

Definitely agree that the makeOrd implementation could be cleaned up. I think it's current state was a side effect of the assumption that math/text fonts behaved similar. That being said, it looks like a lot of solid cleanup has been done around fonts recently (i.e. pulling out the oldFonts from the parser, separating the text functions, etc.). I don't think the cleanup for makeOrd should be too bad.

@kevinbarabash kevinbarabash merged commit 7de91f7 into KaTeX:master Feb 19, 2018
@kevinbarabash
Copy link
Member

@rrandallcainc glad to see this PR finally merged. Thanks for seeing it through.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants