-
Notifications
You must be signed in to change notification settings - Fork 319
KaTeX (3/n): Support negative margins for spans #1559
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
base: main
Are you sure you want to change the base?
Conversation
@rajveermalviya Copying here for visibility what you told me on our call today: the reason this is a draft (not ready to merge) is that you're still working on the widget test. Apart from that, you consider it ready to review. |
c33f5c2
to
6cfcc0d
Compare
843207d
to
d1f5d5c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! Here's small comments from a partial skim.
lib/widgets/katex.dart
Outdated
// Like [RenderPadding] but supports negative values. | ||
class RenderNegativePadding extends RenderShiftedBox { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's leave a TODO tracking our intention to get a version of this upstream:
// Like [RenderPadding] but supports negative values. | |
class RenderNegativePadding extends RenderShiftedBox { | |
// Like [RenderPadding] but supports negative values. | |
// TODO(upstream): give Padding an option to accept negative padding (at cost of hit-testing not working) | |
class RenderNegativePadding extends RenderShiftedBox { |
lib/widgets/katex.dart
Outdated
extension on EdgeInsetsGeometry { | ||
bool get isNegative => !isNonNegative; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is clearer (and hardly much longer) if just inlined.
In particular there's some ambiguity in that "is negative" sounds like it might require all the sides to be negative. So being more transparent, with one fewer layer of indirection, helps mitigate that.
92674c9
to
39d2937
Compare
39d2937
to
bf886a6
Compare
Thanks for the initial comments @gnprice. Revision pushed. |
bf886a6
to
e8cd58a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lib/widgets/content.dart
Outdated
final marginRight = switch (styles.marginRightEm) { | ||
double marginRightEm when marginRightEm >= 0 => marginRightEm * em, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it intended to be possible to get to this point and have a negative marginRightEm?
I believe not — and it looks like if it did happen, this code would just ignore it, which seems like clearly a bug.
So instead of this "when" condition, let's have an assertion:
assert((styles.marginLeftEm ?? 0) >= 0);
Similarly for right margin.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated so that parser makes sure not to emit a node with negative margin styles, as it already emits a separate KatexNegativeMarginNode
for handling that on the widget side. And widget side retains the assert(margin.isNonNegative);
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great, thanks — that definitely sounds cleaner.
bd56117
to
dfabd4d
Compare
Thanks for the review @gnprice! Pushed an update, PTAL. |
dfabd4d
to
2bae0c2
Compare
2bae0c2
to
2e60440
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! This logic looks good. Small comments below on the tests.
(I also have some ideas on how to refactor and simplify the logic — but for the same reasons as at #1698 (comment), because this has already shipped in recent releases, I'll want to save that kind of change for after this PR has been merged.)
test/model/content_test.dart
Outdated
MathBlockNode( | ||
texSource: '\\KaTeX', | ||
nodes: [ | ||
KatexSpanNode( | ||
styles: KatexSpanStyles(), | ||
text: null, | ||
nodes: [ | ||
KatexStrutNode(heightEm: 0.8988, verticalAlignEm: -0.2155), | ||
KatexSpanNode( | ||
styles: KatexSpanStyles(), | ||
text: null, | ||
nodes: [ | ||
KatexSpanNode( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Let's make the boring parts of this more compact, and also involve less indentation. Like so:
MathBlockNode( | |
texSource: '\\KaTeX', | |
nodes: [ | |
KatexSpanNode( | |
styles: KatexSpanStyles(), | |
text: null, | |
nodes: [ | |
KatexStrutNode(heightEm: 0.8988, verticalAlignEm: -0.2155), | |
KatexSpanNode( | |
styles: KatexSpanStyles(), | |
text: null, | |
nodes: [ | |
KatexSpanNode( | |
MathBlockNode(texSource: '\\KaTeX', nodes: [ | |
KatexSpanNode(styles: KatexSpanStyles(), text: null, nodes: [ | |
KatexStrutNode(heightEm: 0.8988, verticalAlignEm: -0.2155), | |
KatexSpanNode(styles: KatexSpanStyles(), text: null, nodes: [ | |
KatexSpanNode( |
and similarly below.
test/model/content_test.dart
Outdated
static const mathBlockKatexNegativeMargins = ContentExample( | ||
'math block katex negative margins', | ||
'```math\n\\KaTeX\n```', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This example is fine to have. But let's also have a more minimal, focused example that's just about negative margins. So:
static const mathBlockKatexNegativeMargins = ContentExample( | |
'math block katex negative margins', | |
'```math\n\\KaTeX\n```', | |
static const mathBlockKatexLogo = ContentExample( | |
'math block KaTeX logo', | |
'```math\n\\KaTeX\n```', |
and then for a minimal example, try $$ 1 \! 2 $$
. The minimal example can get a name like "katex negative margins".
For anyone who's investigating this in the future — or who makes a change, the change causes a regression here, and they need to investigate the regression to figure out the right fix — that minimal, focused example should be helpful as the place to look.
2e60440
to
d4ccfc8
Compare
Implement handling most common types of `vlist` spans.
Turns out that anything under KatexVlistRowNode wasn't being tested by content tests, fix that by implementing this method. Fortunately there were no fixes needed in the tests.
Also add a comment explaining the reason of ignoring the `height` inline styles value.
d4ccfc8
to
04f2e04
Compare
Negative margin spans on web render to the offset being applied to the specific span and all the adjacent spans, so mimic the same behaviour here.
…ontent Skipped currently, because the parser incorrectly doesn't filter the negative margin styles on the vlist row span after generating a `KatexNegativeMarginNode` to specifically handle negative margins.
This fixes a bug where if negative margin on a vlist row is present the widget side code would hit an assert. Displaying the error (red screen) in debug mode, but in release mode the negative padding would be applied twice, once by `_KatexNegativeMargin` and another by `Padding` widget.
04f2e04
to
0ec2cc5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the revision! Comments below, mainly on the two new commits.
MathBlockNode( | ||
texSource: 'X_n', | ||
nodes: [ | ||
KatexSpanNode( | ||
styles: KatexSpanStyles(), | ||
text: null, | ||
nodes: [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: same story as #1559 (comment) and #1698 (comment)
static const mathBlockKatexNegativeMargin = ContentExample( | ||
'math block, KaTeX negative margin', | ||
// https://chat.zulip.org/#narrow/channel/7-test-here/topic/Rajesh/near/2223563 | ||
'```math\n1 \\! 2\n```', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's be sure to include this new, minimal example (from #1559 (comment)) in the widget tests too, so that it can fully do its work.
styles: styles.filter(topEm: false, marginLeftEm: false), | ||
text: null, | ||
nodes: _parseChildSpans(otherSpans))])]); | ||
} else { | ||
innerSpanNode = KatexSpanNode( | ||
styles: styles.filter(topEm: false), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At this point styles
has already had topEm
filtered out, right? So I believe that filtering is redundant.
testParseExample(ContentExample.mathBlockKatexRaisebox); | ||
testParseExample(ContentExample.mathBlockKatexNegativeMargin); | ||
testParseExample(ContentExample.mathBlockKatexLogo); | ||
testParseExample(ContentExample.mathBlockNegativeMarginsOnVlistRow); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From the last two commits (the commits newly added in yesterday's revision, mentioned at #1698 (comment)):
f845c6d content test: Add test for negative margins on a vlist row in KaTeX content
0ec2cc5 content: Filter negative margin styles if present on a vlist row
+ testParseExample(ContentExample.mathBlockNegativeMarginsOnVlistRow,
+ // TODO fix parser to filter negative margins styles from
+ // vlist row span styles.
+ skip: true);
- testParseExample(ContentExample.mathBlockNegativeMarginsOnVlistRow,
- // TODO fix parser to filter negative margins styles from
- // vlist row span styles.
- skip: true);
+ testParseExample(ContentExample.mathBlockNegativeMarginsOnVlistRow);
This version doesn't really give any added information compared to just squashing the two commits together. The normal arrangement is to have the tests appear in the same commit as the changes they're testing, because then the tests can be read in the light of those changes and vice versa, which can help for understanding both of them.
There's a variation of this split which would be useful, though:
- The first commit adds the test, but doesn't skip it; instead, the expectation reflects the old wrong behavior, and a TODO comment points out where it's wrong.
- Then the second commit makes the fix, and updates the test to expect the right behavior.
If the updates to the test are short and readable — simpler to read than the whole test itself — then this can be a useful way of highlighting exactly which aspect of the test expectation is the thing getting fixed by the change.
If I'm understanding this change correctly, then this would be a good example of that: the bit that's wrong would be a single line with a marginLeftEm
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Relatedly:
content: Filter negative margin styles if present on a vlist row
This fixes a bug where if negative margin on a vlist row is present
the widget side code would hit an assert. Displaying the error
(red screen) in debug mode, but in release mode the negative padding
would be applied twice, once by `_KatexNegativeMargin` and another by
`Padding` widget.
Since one of the symptoms is that the widget code hits an assert, let's have a widget test that would exercise that assert. :-)
Stacked on top of #1698.
Related: #46