Refactor buildExpression to depth-first traverse groups (nodes), fix spacings and \begingroup...\endgroup#1706
Refactor buildExpression to depth-first traverse groups (nodes), fix spacings and \begingroup...\endgroup#1706k4b7 merged 8 commits intoKaTeX:masterfrom ylemkimon:build-expression
buildExpression to depth-first traverse groups (nodes), fix spacings and \begingroup...\endgroup#1706Conversation
| export const getTypeOfDomTree = function( | ||
| node: ?HtmlDomNode, | ||
| side: Side, | ||
| side: ?Side, |
There was a problem hiding this comment.
It'd be very nice to get rid of its only usage:
https://github.com/Khan/KaTeX/blob/f71f469d4b3ca97654702a0807e736d176f4c4c5/src/functions/supsub.js#L183-L187
There was a problem hiding this comment.
The comment makes it sound kind of hacky. Is this how LaTeX resets text-align? Any thoughts on a better way to do this?
Codecov Report
@@ Coverage Diff @@
## master #1706 +/- ##
=========================================
- Coverage 94.01% 93.91% -0.1%
=========================================
Files 78 78
Lines 4558 4570 +12
Branches 792 796 +4
=========================================
+ Hits 4285 4292 +7
- Misses 242 246 +4
- Partials 31 32 +1
Continue to review full report at Codecov.
|
src/buildHTML.js
Outdated
| right.classes[0] = "mord"; | ||
| }, {node: dummyPrev}, dummyNext); | ||
|
|
||
| traverseNodes(groups, (node, prev) => { |
There was a problem hiding this comment.
It is possible to traverse only once, but it's more complicated since it needs to retain previous spacing information. I'm not sure which is more optimal.
There was a problem hiding this comment.
My preference is for multiple passes with simpler code.
buildExpression to depth-first traverse groups (nodes), fix spacingsbuildExpression to depth-first traverse groups (nodes), fix spacings and \begingroup...\endgroup
src/Parser.js
Outdated
| } else if (!optional && this.nextToken.text === "\\begingroup") { | ||
| // A group formed by /begingroup...\endgroup is a semi-simple group, | ||
| // which doesn't affect spacing in math mode, i.e., is transparent | ||
| semisimple = true; |
There was a problem hiding this comment.
Can you add a reference to the TeXBook or similar resource?
There was a problem hiding this comment.
@kevinbarabash Semi-simple group is mentioned in TeX: The Program, but I really cannot find a reference regarding its spacing or the fact that it doesn't create a mathord.
There was a problem hiding this comment.
Did you determine the behavior by seeing what LaTeX does for different test cases?
There was a problem hiding this comment.
FWIW, this behavior matches my experience testing with LaTeX. I don't see it documented in The TeXbook. But the TeX source code definitely calls groups started with \begingroup "semi-simple groups" (search for begin_group), and it definitely does something special with them (search for semi_simple_group). But I'm no expert at that code...
There was a problem hiding this comment.
@kevinbarabash I've added a link to stack exchange answer, as it has enough up-votes.
src/buildHTML.js
Outdated
|
|
||
| return groups; | ||
| // Check if given node is a partial group, i.e., does not affect spacing around, | ||
| // like fragment. |
There was a problem hiding this comment.
I mis-parsed this comment on the first read. The intent is that partial groups behave the same as fragment, i.e. they don't affect the spacing around it.
There was a problem hiding this comment.
@kevinbarabash I've removed like fragment.
| // like fragment. | ||
| const checkPartialGroup = function( | ||
| node: HtmlDomNode, | ||
| ): ?(DocumentFragment<HtmlDomNode> | Anchor) { |
There was a problem hiding this comment.
Maybe we should define type PartialGroup = DocumentFragment<HtmlDomNode> | Anchor.
There was a problem hiding this comment.
@kevinbarabash I think it's better to have it close to instanceof checks.
|
|
||
| traverseNodes(groups, (node, prev) => { | ||
| const prevType = getTypeOfDomTree(prev); | ||
| const type = getTypeOfDomTree(node); |
There was a problem hiding this comment.
Why don't we need the side argument here?
There was a problem hiding this comment.
@kevinbarabash The callback function will be only called on non-partial groups.
There was a problem hiding this comment.
That makes sense, but it's not obvious. Could you add a comment here before merging this?
src/buildHTML.js
Outdated
| // previous node as arguments, optionally returning a node to insert after the | ||
| // previous node. `prev` is an object with the previous node and `insertAfter` | ||
| // function to insert after it. `next` is a node that will be added to the right. | ||
| const traverseNodes = function( |
There was a problem hiding this comment.
It might be worth unit testing this. Also the name is very general but it some logic that's super specific to modifying spacing. Can you change the name and update the comment to reflect this?
There was a problem hiding this comment.
@kevinbarabash I've renamed the function to traverseNonSpaceNodes and added comments about its usage. We really need a way to unit-test functions.
test/katex-spec.js
Outdated
|
|
||
| it("should not affect spacing in math mode", function() { | ||
| const built = getBuilt`\begingroup x+ \endgroup y`; | ||
| expect(built).toMatchSnapshot(); |
There was a problem hiding this comment.
Maybe compare this build tree with that of x + y,
|
|
||
| it("should not affect spacing around", function() { | ||
| const built = getBuilt`a\href{http://example.com/}{+b}`; | ||
| expect(built).toMatchSnapshot(); |
k4b7
left a comment
There was a problem hiding this comment.
LGTM. Requesting one additional comment about why we don't need to pass the side argument to getTypeOfDomTree on lines 120-121 of buildHTML.js.
I forgot about this. I guess it wasn't that important. |
Fixes #1108 and fixes #1679. This also allows the implementation of semi-simple (partial, transparent, i.e., doesn't affect spacing around) groups like
\classand\cssIdin #1437.This PR refactors
buildExpressionto depth-first traverse (DFS) groups (nodes), going intoAnchorand possibly other nodes in the future.Also, this PR fixes
\begingroup...\endgroup, which only can be ended by\endgroupand is semi-simple group.