md2star.linebreak module
Semantic line breaking: md2star chooses where a slide’s lines end.
A renderer wraps greedily, so a line ends wherever the next word stops fitting: on « de », on « the », before a lone « : », between « 500 » and « 000 ». The usual cure, a no-break space, does not work on every template: Satoshi, the course’s face, has no glyph for U+00A0 or U+202F at all.
So when md2star writes a title or a paragraph into a box whose width and font
size it knows, it breaks the lines itself, with the face’s real advance widths
(read from the font file’s cmap and hmtx tables, 0.55 em per character
when the file cannot be found), and writes explicit line breaks the renderer
keeps. The break points are chosen by dynamic programming over a cost model:
a line does not end on a function word (article, preposition, conjunction, pronoun, auxiliary — French and English) whenever any other break fits;
a line never starts with
: ; ? ! » %and a number is never separated from the number or the unit after it (500 000, 2 min, 30 %);no single orphan word on the last line;
breaking after punctuation, or before a word that opens a clause (qui, que, pour, quand, mais, which, when, because), is preferred;
among the permitted breaks, balanced lines win, and each extra line costs.
The cost model is the one the course’s figures already use (figkit.wrap).
- md2star.linebreak.BREAK_BEFORE = frozenset({'alors', 'après', 'avant', 'because', 'but', 'car', 'comme', 'donc', 'if', 'mais', 'où', 'parce', 'pour', 'puis', 'quand', 'que', 'qui', 'si', 'so', 'that', 'then', 'when', 'where', 'which', 'while'})
breaking just before one reads naturally.
- Type:
Words that open a clause
- md2star.linebreak.FALLBACK_EM = 0.55
Advance of one character when the face’s own metrics cannot be read.
- md2star.linebreak.GLUE_AFTER = frozenset({'a', 'an', 'and', 'are', 'as', 'at', 'au', 'aux', 'avec', 'be', 'by', "c'", 'ce', 'ces', 'cet', 'cette', 'chez', 'c’', "d'", 'dans', 'de', 'des', 'du', 'd’', 'elle', 'elles', 'en', 'entre', 'est', 'et', 'for', 'from', 'her', 'his', 'il', 'ils', 'in', 'into', 'is', 'its', "j'", 'je', 'j’', "l'", 'la', 'le', 'les', 'leur', 'leurs', 'l’', 'ma', 'mes', 'mon', 'my', "n'", 'ne', 'ni', 'no', 'nor', 'nos', 'not', 'notre', 'nous', 'n’', 'of', 'on', 'or', 'ou', 'our', 'par', 'pas', 'per', 'plus', 'pour', "qu'", 'que', 'qui', 'qu’', "s'", 'sa', 'sans', 'se', 'ses', 'son', 'sont', 'sous', 'sur', 's’', 'ta', 'tes', 'than', 'that', 'the', 'their', 'these', 'this', 'those', 'to', 'ton', 'très', 'un', 'une', 'vers', 'via', 'vos', 'votre', 'vous', 'was', 'with', 'y', 'your', 'à', 'être'})
a line ending on one reads as cut.
- Type:
Words that announce what follows
- md2star.linebreak.NO_LINE_START = frozenset({'!', '%', ')', ':', ';', '?', '»', '…'})
Characters a line must never start with.
- md2star.linebreak.UNITS = frozenset({'$', '%', 'an', 'ans', 'cm', 'fois', 'g', 'h', 'j', 'jours', 'kg', 'km', 'k€', 'm', 'md', 'mds', 'min', 'mm', 'mois', 'ms', 'm€', 'pt', 's', 'x', '€'})
Units that stay with the number before them.
- md2star.linebreak.WIDTH_MARGIN = 1.03
a renderer’s kerning, hinting or a slightly different inset must never make it re-wrap a line we broke.
- Type:
Safety factor on measured widths
- md2star.linebreak.break_lines(text, size, box_width_pt, *, family=None, bold=False)[source]
text with its line breaks chosen (
\vbetween lines), ready to write.A no-break space the face has no glyph for is written as a plain space: the break it protected is now ours to choose, and the cost model already keeps a number with its unit and a « : » off the start of a line.
- md2star.linebreak.cost_break(left, right)[source]
Cost of ending a line on word left and starting the next on right.
- md2star.linebreak.face(family, bold=False)[source]
The metrics of family (
None: the 0.55 em fallback is used).
- md2star.linebreak.has_glyph(metrics, ch)[source]
Whether the face draws ch (always
Falsewithout metrics).
- md2star.linebreak.width(text, size, metrics=None)[source]
Printed width of text at size pt, in points.