Skip to content

simplify combining chars#1633

Merged
k4b7 merged 9 commits intomasterfrom
domtree_refactor_1
Aug 23, 2018
Merged

simplify combining chars#1633
k4b7 merged 9 commits intomasterfrom
domtree_refactor_1

Conversation

@k4b7
Copy link
Member

@k4b7 k4b7 commented Aug 18, 2018

In preparation of refactoring domTree classes into POJOs as described in my comments in #1618, this PR removes the tryCombine method all of these classes. All of the checks we were doing in symbolNode's tryCombine method weren't actually necessary b/c we were only combining characters within the same group which means that they all had the same style/options to begin with.

This diff also merges mathDefault into makeOrd (fixes #1299) which makes it easier to see more of the font picking logic in one place.

@codecov
Copy link

codecov bot commented Aug 18, 2018

Codecov Report

Merging #1633 into master will increase coverage by 8.71%.
The diff coverage is 97.14%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #1633      +/-   ##
==========================================
+ Coverage   85.13%   93.84%   +8.71%     
==========================================
  Files          78       78              
  Lines        4573     4568       -5     
  Branches      801      801              
==========================================
+ Hits         3893     4287     +394     
+ Misses        585      248     -337     
+ Partials       95       33      -62
Impacted Files Coverage Δ
src/tree.js 82.35% <ø> (+26.79%) ⬆️
src/functions/verb.js 100% <ø> (+87.5%) ⬆️
src/functions/text.js 100% <100%> (ø) ⬆️
src/domTree.js 92.59% <100%> (+27.62%) ⬆️
src/functions/op.js 96.9% <100%> (+2.06%) ⬆️
src/buildCommon.js 98.46% <96.87%> (+7.36%) ⬆️
src/buildHTML.js 99.23% <0%> (+1.53%) ⬆️
src/MacroExpander.js 95.68% <0%> (+1.72%) ⬆️
src/functions/operatorname.js 94.73% <0%> (+2.63%) ⬆️
... and 24 more

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 7ca6f51...518f4cb. Read the comment docs.

htmlBuilder(group, options) {
const newOptions = optionsWithFont(group, options);
// TODO(kevinb): split group.body into combinable parts to avoid having
// complicated checks in buildCommon.tryCombineChars.
Copy link
Member Author

Choose a reason for hiding this comment

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

The only things we can combine are textords and spacings so if we create groups of consecutive textords and spacings we can pass each of those groups off to buildExpression and combine the symbolNodes that are returned without doing all of complex checks we're doing right now in tryCombineChars.

Copy link
Member

Choose a reason for hiding this comment

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

I worry that some other functions might return the equivalent of a textord that wouldn't be caught before running the function...

Copy link
Member Author

Choose a reason for hiding this comment

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

That's a good point. I'll remove this TODO and make sure that the new tryCombineChars covers all the cases that symbolNode.tryCombineChar was checking before.

@k4b7 k4b7 self-assigned this Aug 18, 2018
@edemaine edemaine changed the title simplify comibining chars simplify combining chars Aug 18, 2018
Copy link
Member

@edemaine edemaine left a comment

Choose a reason for hiding this comment

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

Nice transform.

for (const style in prev.style) {
if (prev.style.hasOwnProperty(style)
&& prev.style[style] !== next.style[style]) {
skip = true;
Copy link
Member

Choose a reason for hiding this comment

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

Instead of using skip (and should probably use break) here, you can just continue charloop if you label the for loop block with charloop:. (I've never done this myself, but see these docs.)

By the way, odd that there is no domTree.createStyle...

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 call. I too have never done that either. I might move these checks into a separate function.

&& next instanceof domTree.symbolNode) {

if (domTree.createClass(prev.classes) !==
domTree.createClass(next.classes)) {
Copy link
Member

Choose a reason for hiding this comment

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

I realize that this check is somewhat oversensitive, because the classes aren't sorted. But I guess that's fine.


prev.text += next.text;
prev.height = Math.max(prev.height, next.height);
prev.depth = Math.max(prev.depth, next.depth);
Copy link
Member

Choose a reason for hiding this comment

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

You seem to be missing prev.italic = next.italic;

/**
* Combine as many characters as possible in the given array of characters
* via their tryCombine method.
* Combine consequetive domTree.symbolNodes into a single symbolNode.
Copy link
Member

Choose a reason for hiding this comment

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

Maybe add a comment that chars is modified in place, as well as returned? The former could be dangerous (and now the code that uses tryCombineChars doesn't make it obvious that it's changing in-place.)

Copy link
Member Author

@k4b7 k4b7 Aug 18, 2018

Choose a reason for hiding this comment

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

Yeah... I'll mademake a note that this function mutates the input. Maybe I can make a copy fo the array so that we don't mutate the input.

Copy link
Member

Choose a reason for hiding this comment

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

I guess you could assembly the nodes into a new array and return that. In some ways that might be better -- splice is pretty inefficient. In reality, speed is going to depend on whether there's anything to combine ever. If there is, assembling into a new array would be faster; otherwise, the current approach is probably slightly faster.

@k4b7 k4b7 assigned edemaine and unassigned k4b7 Aug 18, 2018
@k4b7
Copy link
Member Author

k4b7 commented Aug 18, 2018

@edemaine I've assigned this to you to indicate that it's ready for review again.

@ylemkimon
Copy link
Member

There seems to be no commit pushed after #1633 (review).

@k4b7
Copy link
Member Author

k4b7 commented Aug 19, 2018

I forgot to push. I've pushed the changes I had locally now.

@k4b7
Copy link
Member Author

k4b7 commented Aug 19, 2018

I'll resolve the merge conflicts later today.

@k4b7 k4b7 assigned k4b7 and unassigned edemaine Aug 19, 2018

prev.text += next.text;
prev.height = Math.max(prev.height, next.height);
prev.depth = Math.max(prev.depth, next.depth);
Copy link
Member

Choose a reason for hiding this comment

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

#1633 (comment) by @edemaine

You seem to be missing prev.italic = next.italic;

Copy link
Member Author

Choose a reason for hiding this comment

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

The previous code check if this.italic > 0 which felt weird so I left it out. prev.italic = next.italic seems like a better way to go.

@k4b7 k4b7 removed their assignment Aug 20, 2018
const prev = chars[i];
const next = chars[i + 1];
if (prev instanceof SymbolNode
&& next instanceof SymbolNode
Copy link
Member

Choose a reason for hiding this comment

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

How about moving instanceof checks to canCombine?

Copy link
Member Author

@k4b7 k4b7 Aug 21, 2018

Choose a reason for hiding this comment

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

I wanted to do that originally, but if we do that flow doesn't know that prev and next are SymbolNodes inside of tryCombineChars which means it doesn't recognize the props that we use on prev and next following this check. It's a bummer b/c the code would look a lot cleaner.

It would be cool if flow had a way to describe "if this function returns true then the args of of these types".

Copy link
Member

Choose a reason for hiding this comment

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

@kevinbarabash AFAIK, after if (!(prev instanceof SymbolNode) || !(next instanceof SymbolNode)) return;, flow would refine them as SymbolNode.

Copy link
Member Author

@k4b7 k4b7 Aug 21, 2018

Choose a reason for hiding this comment

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

~Ugh, I forgot to change the param types to canCombine to prev: any, next: any. Also, I am impressed with flow ability to make a type refinement based on that check. Thank you for prodding me on this.~Double ugh... the flow plugin in my editor was lagging... this check still doesn't refine the types.

@k4b7
Copy link
Member Author

k4b7 commented Aug 23, 2018

@edemaine can you have another look when you have a chance?

Copy link
Member

@edemaine edemaine left a comment

Choose a reason for hiding this comment

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

Sorry for the delay. One more comment about where to call tryCombineChars.

} else {
base = buildCommon.makeSpan(["mop"], inner, options);
base = buildCommon.makeSpan(
["mop"], buildCommon.tryCombineChars(inner), options);
Copy link
Member

Choose a reason for hiding this comment

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

This is a new call to tryCombineChars, right? This suggests to me that it should be called in buildExpression, not anywhere else. For example, \text{{hello}} probably won't combine the characters in the current code, because of the ordgroup in the way, but would if we called it in buildExpression.

Perhaps it should only be called in text mode, though? How is that currently detected? (Vague worry that that's what the italic > 0 check was for...)

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 is a new call. It would be nice to handle cases like \text{{hello}}. I tried collating ordgroups but I had taken some of the checks out. I should try again now that all of the checks are back in. There are situations where I could see us not wanting to combine ordgroups though. As an example: {xyz}... in this situation we might want to keep those characters separate in case someone wants to be able to highlight each variable on hover or click to select an individual variable in the term. I think calling it for this particular case of op makes sense b/c it handles things like sin, cos, etc. and I think we should be treating those things as atomic units as opposed to separate letters.

Copy link
Member

Choose a reason for hiding this comment

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

I don't see a use-case for keeping letters as separate objects in text mode -- but I agree there's a use in math mode where each letter represents a separate variable. See buildMathML.buildExpression which does a similar transform of combining mtexts (but of course MathML is trying to represent semantics here; HTML could have different, more visual purposes). But we can discuss this as a separate PR.

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 get what you're saying... try to combine characters inside of ordgroup if we're in text mode. I'll make an issue for it. Having fewer spans should improve performance. The fewer DOM nodes we have to create the better.

@k4b7 k4b7 merged commit 5391720 into master Aug 23, 2018
@ylemkimon ylemkimon deleted the domtree_refactor_1 branch September 2, 2018 03:21
k4b7 pushed a commit that referenced this pull request Nov 1, 2018
* Support \includegraphics

* Update screenshots

* Fix lint errors

* Fix more lint errors

* Fix lint errors take 3

* Add documentation, error messages

* Improve CSS

* Update domTree to coordinate with PR #1633

* Update screenshots

* fix flow errors

* Use same RegEx as href

* Fix lint error

* Accept raw ArgType

* Fix lint error

* fix flow error

* Add test
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.

Combine mathDefault with makeOrd

3 participants