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

allow sizing commands inside optional groups #885

Merged
merged 3 commits into from
Oct 3, 2017

Conversation

kevinbarabash
Copy link
Member

@kevinbarabash kevinbarabash commented Sep 15, 2017

Fixes #650 and #516.

TODO:

  • unit tests
  • screenshot tests
  • \color
  • style commands e.g. \textstyle
  • old font functions, e.g. \tt

src/Parser.js Outdated
@@ -165,7 +165,8 @@ class Parser {
if (breakOnInfix && functions[lex.text] && functions[lex.text].infix) {
break;
}
const atom = this.parseAtom();
const optional = breakOnTokenText === "]";
const atom = this.parseAtom(optional);
Copy link
Member

Choose a reason for hiding this comment

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

I haven't thought about this deeply, but is there a reason to just pass in ] and not just breakOnTokenText in general? I think the latter might be useful for more general macro support in the future... Maybe worth reviewing what other values this currently takes on in the code, if any.

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 idea. I'll look into this evening.

"type": "sizing",
"value": Object {
"size": 5,
"value": Array [
Copy link
Member Author

Choose a reason for hiding this comment

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

This is kind of weird. I hope that in the future that sizing nodes could maybe look like:

ParseNode: {
   mode: "math",
   type: "sizing",
   size: 5,
   body: Array [ ... ],
}

@kevinbarabash
Copy link
Member Author

I'm going to update the jsDocs to include the new breakOnTokenText. @marcianx would you be able to review this PR?

@marcianx
Copy link
Collaborator

Will do. I'll do one pass now. And if there are any changes. Then one in the morning.

src/Parser.js Outdated
@@ -165,7 +165,8 @@ class Parser {
if (breakOnInfix && functions[lex.text] && functions[lex.text].infix) {
break;
}
const atom = this.parseAtom();
// const optional = breakOnTokenText === "]";
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should this now be removed?

src/Parser.js Outdated
@@ -308,10 +309,10 @@ class Parser {
*
* @return {?ParseNode}
*/
parseAtom() {
parseAtom(breakOnTokenText) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: Mind adding a @param documenting the type of the new parameter?

src/Parser.js Outdated
@@ -425,7 +426,7 @@ class Parser {
*
* @return {?ParseNode}
*/
parseImplicitGroup() {
parseImplicitGroup(breakOnTokenText) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same here, please.

},
],
},
"type": "sqrt",
Copy link
Collaborator

Choose a reason for hiding this comment

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

(optional) I don't know whether an arbitrary strict order is enforced here, but if not, moving this up would make it much easier to see which level it is 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.

I can set up a custom formatter for the snapshots to always put "type" first.

// The body of an atom is an implicit group, so that things like
// \left(x\right)^2 work correctly.
const base = this.parseImplicitGroup();
const base = this.parseImplicitGroup(breakOnTokenText);
Copy link
Collaborator

Choose a reason for hiding this comment

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

It might be worth adding a comment somewhere as to why it's okay not to pass this parameter down to other methods below. The reason seems to be subtle: as handleSupSubscript can call parseGroup which can call parseExpression, but parseExpression is only called in parseGroup only if a { or [ is encountered, opening a deeper layer. But I haven't yet done an exhaustive check.

I'm also fine with completely deferring this if we intend to formalize the various non-obvious invariants in this file some point to aid comprehensibility so that they aren't violated in the future.

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 add a comment. handleSupSubscript should always be parsing non-optional groups afaict because x^[2] isn't valid (or rather it's valid it's treated as x^{[}2]).

@@ -834,7 +836,7 @@ export default class Parser {
if (this.nextToken.text === (optional ? "[" : "{")) {
// If we get a brace, parse an expression
this.consume();
const expression = this.parseExpression(false, optional ? "]" : null);
const expression = this.parseExpression(false, optional ? "]" : "}");
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'm not sure why this was null.

Copy link
Member

Choose a reason for hiding this comment

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

Parsing always ends on }, so I'm not sure specifying "}" is necessary... hence the null. (It's been a while since I've looked at this code, so I forget the exact details...)

Copy link
Member Author

Choose a reason for hiding this comment

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

It feels nice to have symmetry the ? "[" : "{" check above.

@@ -527,7 +529,7 @@ export default class Parser {
} else if (utils.contains(Parser.sizeFuncs, func)) {
// If we see a sizing function, parse out the implicit body
this.consumeSpaces();
const body = this.parseExpression(false);
const body = this.parseExpression(false, breakOnTokenText);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why does this only apply to this block and not to the rest below: styleFuncs, oldFontFuncs, and \color? Are they not similarly affected? Or do none of our functions currently want to allow these in optional groups?
Otherwise, this PR mostly LGTM.

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 was fixing only the issue, but I'm sure there are places where KA also uses \color inside of optional groups (apparently LaTeX supports this too). LaTeX also supports style functions within optional blocks too.

Copy link
Collaborator

@marcianx marcianx left a comment

Choose a reason for hiding this comment

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

LGTM

@kevinbarabash kevinbarabash merged commit 71e0b35 into master Oct 3, 2017
@kevinbarabash
Copy link
Member Author

kevinbarabash commented Oct 3, 2017

@marcianx thanks for the review. Feel free to merge PRs as well.

@kevinbarabash kevinbarabash deleted the sizing_in_option_groups branch November 27, 2017 01:03
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.

3 participants