Skip to content

Commit 83a0b6f

Browse files
committed
katex [nfc]: Split out _parseStrut, _parseVlist, _parseGenericSpan
Each of these swathes of logic has no interaction with the others. Splitting them into their own methods makes that structure easy for the reader to see.
1 parent 39fdded commit 83a0b6f

File tree

1 file changed

+141
-123
lines changed

1 file changed

+141
-123
lines changed

lib/model/katex.dart

Lines changed: 141 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -219,149 +219,167 @@ class _KatexParser {
219219
return resultSpans;
220220
}
221221

222-
static final _resetSizeClassRegExp = RegExp(r'^reset-size(\d\d?)$');
223-
static final _sizeClassRegExp = RegExp(r'^size(\d\d?)$');
224-
225222
KatexNode _parseSpan(dom.Element element) {
223+
assert(element.localName == 'span');
226224
// TODO maybe check if the sequence of ancestors matter for spans.
227225

228-
final debugHtmlNode = kDebugMode ? element : null;
229-
230226
if (element.className == 'strut') {
231-
if (element.nodes.isNotEmpty) throw _KatexHtmlParseError();
232-
233-
final styles = _parseInlineStyles(element);
234-
if (styles == null) throw _KatexHtmlParseError();
235-
final heightEm = _takeStyleEm(styles, 'height');
236-
if (heightEm == null) throw _KatexHtmlParseError();
237-
final verticalAlignEm = _takeStyleEm(styles, 'vertical-align');
238-
if (styles.isNotEmpty) throw _KatexHtmlParseError();
239-
240-
return KatexStrutNode(
241-
heightEm: heightEm,
242-
verticalAlignEm: verticalAlignEm,
243-
debugHtmlNode: debugHtmlNode);
227+
return _parseStrut(element);
244228
}
245229

246230
if (element.className == 'vlist-t'
247231
|| element.className == 'vlist-t vlist-t2') {
248-
final vlistT = element;
249-
if (vlistT.nodes.isEmpty) throw _KatexHtmlParseError();
250-
if (vlistT.attributes.containsKey('style')) throw _KatexHtmlParseError();
251-
252-
final hasTwoVlistR = vlistT.className == 'vlist-t vlist-t2';
253-
if (!hasTwoVlistR && vlistT.nodes.length != 1) throw _KatexHtmlParseError();
254-
255-
if (hasTwoVlistR) {
256-
if (vlistT.nodes case [
257-
_,
258-
dom.Element(localName: 'span', className: 'vlist-r', nodes: [
259-
dom.Element(localName: 'span', className: 'vlist', nodes: [
260-
dom.Element(localName: 'span', className: '', nodes: []),
261-
]) && final vlist,
262-
]),
263-
]) {
264-
// In the generated HTML the .vlist in second .vlist-r span will have
265-
// a "height" inline style which we ignore, because it doesn't seem
266-
// to have any effect in rendering on the web.
267-
// But also make sure there aren't any other inline styles present.
268-
final vlistStyles = _parseInlineStyles(vlist);
269-
if (vlistStyles != null && vlistStyles.keys.any((p) => p != 'height')) {
270-
throw _KatexHtmlParseError();
271-
}
272-
} else {
232+
return _parseVlist(element);
233+
}
234+
235+
return _parseGenericSpan(element);
236+
}
237+
238+
KatexNode _parseStrut(dom.Element element) {
239+
assert(element.localName == 'span');
240+
assert(element.className == 'strut');
241+
if (element.nodes.isNotEmpty) throw _KatexHtmlParseError();
242+
243+
final styles = _parseInlineStyles(element);
244+
if (styles == null) throw _KatexHtmlParseError();
245+
final heightEm = _takeStyleEm(styles, 'height');
246+
if (heightEm == null) throw _KatexHtmlParseError();
247+
final verticalAlignEm = _takeStyleEm(styles, 'vertical-align');
248+
if (styles.isNotEmpty) throw _KatexHtmlParseError();
249+
250+
return KatexStrutNode(
251+
heightEm: heightEm,
252+
verticalAlignEm: verticalAlignEm,
253+
debugHtmlNode: kDebugMode ? element : null);
254+
}
255+
256+
KatexNode _parseVlist(dom.Element element) {
257+
assert(element.localName == 'span');
258+
assert(element.className == 'vlist-t'
259+
|| element.className == 'vlist-t vlist-t2');
260+
final vlistT = element;
261+
if (vlistT.nodes.isEmpty) throw _KatexHtmlParseError();
262+
if (vlistT.attributes.containsKey('style')) throw _KatexHtmlParseError();
263+
264+
final hasTwoVlistR = vlistT.className == 'vlist-t vlist-t2';
265+
if (!hasTwoVlistR && vlistT.nodes.length != 1) throw _KatexHtmlParseError();
266+
267+
if (hasTwoVlistR) {
268+
if (vlistT.nodes case [
269+
_,
270+
dom.Element(localName: 'span', className: 'vlist-r', nodes: [
271+
dom.Element(localName: 'span', className: 'vlist', nodes: [
272+
dom.Element(localName: 'span', className: '', nodes: []),
273+
]) && final vlist,
274+
]),
275+
]) {
276+
// In the generated HTML the .vlist in second .vlist-r span will have
277+
// a "height" inline style which we ignore, because it doesn't seem
278+
// to have any effect in rendering on the web.
279+
// But also make sure there aren't any other inline styles present.
280+
final vlistStyles = _parseInlineStyles(vlist);
281+
if (vlistStyles != null && vlistStyles.keys.any((p) => p != 'height')) {
273282
throw _KatexHtmlParseError();
274283
}
284+
} else {
285+
throw _KatexHtmlParseError();
275286
}
287+
}
276288

277-
if (vlistT.nodes.first
278-
case dom.Element(localName: 'span', className: 'vlist-r') &&
279-
final vlistR) {
280-
if (vlistR.attributes.containsKey('style')) throw _KatexHtmlParseError();
281-
282-
if (vlistR.nodes.first
283-
case dom.Element(localName: 'span', className: 'vlist') &&
284-
final vlist) {
285-
// Same as above for the second .vlist-r span, .vlist span in first
286-
// .vlist-r span will have "height" inline style which we ignore,
287-
// because it doesn't seem to have any effect in rendering on
288-
// the web.
289-
// But also make sure there aren't any other inline styles present.
290-
final vlistStyles = _parseInlineStyles(vlist);
291-
if (vlistStyles != null && vlistStyles.keys.any((p) => p != 'height')) {
292-
throw _KatexHtmlParseError();
293-
}
289+
if (vlistT.nodes.first
290+
case dom.Element(localName: 'span', className: 'vlist-r') &&
291+
final vlistR) {
292+
if (vlistR.attributes.containsKey('style')) throw _KatexHtmlParseError();
293+
294+
if (vlistR.nodes.first
295+
case dom.Element(localName: 'span', className: 'vlist') &&
296+
final vlist) {
297+
// Same as above for the second .vlist-r span, .vlist span in first
298+
// .vlist-r span will have "height" inline style which we ignore,
299+
// because it doesn't seem to have any effect in rendering on
300+
// the web.
301+
// But also make sure there aren't any other inline styles present.
302+
final vlistStyles = _parseInlineStyles(vlist);
303+
if (vlistStyles != null && vlistStyles.keys.any((p) => p != 'height')) {
304+
throw _KatexHtmlParseError();
305+
}
306+
307+
final rows = <KatexVlistRowNode>[];
308+
309+
for (final innerSpan in vlist.nodes) {
310+
if (innerSpan case dom.Element(
311+
localName: 'span',
312+
nodes: [
313+
dom.Element(localName: 'span', className: 'pstrut') &&
314+
final pstrutSpan,
315+
...final otherSpans,
316+
],
317+
)) {
318+
if (innerSpan.className != '') {
319+
throw _KatexHtmlParseError('unexpected CSS class for '
320+
'vlist inner span: ${innerSpan.className}');
321+
}
294322

295-
final rows = <KatexVlistRowNode>[];
296-
297-
for (final innerSpan in vlist.nodes) {
298-
if (innerSpan case dom.Element(
299-
localName: 'span',
300-
nodes: [
301-
dom.Element(localName: 'span', className: 'pstrut') &&
302-
final pstrutSpan,
303-
...final otherSpans,
304-
],
305-
)) {
306-
if (innerSpan.className != '') {
307-
throw _KatexHtmlParseError('unexpected CSS class for '
308-
'vlist inner span: ${innerSpan.className}');
309-
}
310-
311-
final inlineStyles = _parseInlineStyles(innerSpan);
312-
if (inlineStyles == null) throw _KatexHtmlParseError();
313-
final marginLeftEm = _takeStyleEm(inlineStyles, 'margin-left');
314-
final marginLeftIsNegative = marginLeftEm?.isNegative ?? false;
315-
final marginRightEm = _takeStyleEm(inlineStyles, 'margin-right');
316-
if (marginRightEm?.isNegative ?? false) throw _KatexHtmlParseError();
317-
final styles = KatexSpanStyles(
318-
marginLeftEm: marginLeftIsNegative ? null : marginLeftEm,
319-
marginRightEm: marginRightEm,
320-
);
321-
final topEm = _takeStyleEm(inlineStyles, 'top');
322-
if (inlineStyles.isNotEmpty) throw _KatexHtmlParseError();
323-
324-
final pstrutStyles = _parseInlineStyles(pstrutSpan);
325-
if (pstrutStyles == null) throw _KatexHtmlParseError();
326-
final pstrutHeightEm = _takeStyleEm(pstrutStyles, 'height');
327-
if (pstrutHeightEm == null) throw _KatexHtmlParseError();
328-
if (pstrutStyles.isNotEmpty) throw _KatexHtmlParseError();
329-
330-
KatexSpanNode child = KatexSpanNode(
331-
styles: styles,
323+
final inlineStyles = _parseInlineStyles(innerSpan);
324+
if (inlineStyles == null) throw _KatexHtmlParseError();
325+
final marginLeftEm = _takeStyleEm(inlineStyles, 'margin-left');
326+
final marginLeftIsNegative = marginLeftEm?.isNegative ?? false;
327+
final marginRightEm = _takeStyleEm(inlineStyles, 'margin-right');
328+
if (marginRightEm?.isNegative ?? false) throw _KatexHtmlParseError();
329+
final styles = KatexSpanStyles(
330+
marginLeftEm: marginLeftIsNegative ? null : marginLeftEm,
331+
marginRightEm: marginRightEm,
332+
);
333+
final topEm = _takeStyleEm(inlineStyles, 'top');
334+
if (inlineStyles.isNotEmpty) throw _KatexHtmlParseError();
335+
336+
final pstrutStyles = _parseInlineStyles(pstrutSpan);
337+
if (pstrutStyles == null) throw _KatexHtmlParseError();
338+
final pstrutHeightEm = _takeStyleEm(pstrutStyles, 'height');
339+
if (pstrutHeightEm == null) throw _KatexHtmlParseError();
340+
if (pstrutStyles.isNotEmpty) throw _KatexHtmlParseError();
341+
342+
KatexSpanNode child = KatexSpanNode(
343+
styles: styles,
344+
text: null,
345+
nodes: _parseChildSpans(otherSpans));
346+
347+
if (marginLeftIsNegative) {
348+
child = KatexSpanNode(
349+
styles: KatexSpanStyles(),
332350
text: null,
333-
nodes: _parseChildSpans(otherSpans));
334-
335-
if (marginLeftIsNegative) {
336-
child = KatexSpanNode(
337-
styles: KatexSpanStyles(),
338-
text: null,
339-
nodes: [KatexNegativeMarginNode(
340-
leftOffsetEm: marginLeftEm!,
341-
nodes: [child])]);
342-
}
343-
344-
rows.add(KatexVlistRowNode(
345-
verticalOffsetEm: (topEm ?? 0) + pstrutHeightEm,
346-
debugHtmlNode: kDebugMode ? innerSpan : null,
347-
node: child));
348-
} else {
349-
throw _KatexHtmlParseError();
351+
nodes: [KatexNegativeMarginNode(
352+
leftOffsetEm: marginLeftEm!,
353+
nodes: [child])]);
350354
}
351-
}
352355

353-
// TODO(#1716) Handle styling for .vlist-t2 spans
354-
return KatexVlistNode(
355-
rows: rows,
356-
debugHtmlNode: debugHtmlNode,
357-
);
358-
} else {
359-
throw _KatexHtmlParseError();
356+
rows.add(KatexVlistRowNode(
357+
verticalOffsetEm: (topEm ?? 0) + pstrutHeightEm,
358+
debugHtmlNode: kDebugMode ? innerSpan : null,
359+
node: child));
360+
} else {
361+
throw _KatexHtmlParseError();
362+
}
360363
}
364+
365+
// TODO(#1716) Handle styling for .vlist-t2 spans
366+
return KatexVlistNode(
367+
rows: rows,
368+
debugHtmlNode: kDebugMode ? element : null,
369+
);
361370
} else {
362371
throw _KatexHtmlParseError();
363372
}
373+
} else {
374+
throw _KatexHtmlParseError();
364375
}
376+
}
377+
378+
static final _resetSizeClassRegExp = RegExp(r'^reset-size(\d\d?)$');
379+
static final _sizeClassRegExp = RegExp(r'^size(\d\d?)$');
380+
381+
KatexNode _parseGenericSpan(dom.Element element) {
382+
assert(element.localName == 'span');
365383

366384
// Aggregate the CSS styles that apply, in the same order as the CSS
367385
// classes specified for this span, mimicking the behaviour on web.
@@ -646,7 +664,7 @@ class _KatexParser {
646664
styles: styles,
647665
text: text,
648666
nodes: spans,
649-
debugHtmlNode: debugHtmlNode);
667+
debugHtmlNode: kDebugMode ? element : null);
650668
}
651669

652670
/// Parse the inline CSS styles from the given element.

0 commit comments

Comments
 (0)