diff options
| author | Jason A. Dönerfield <no-replay@sl0p.foo> | 2026-07-18 21:13:31 +0200 |
|---|---|---|
| committer | Jason A. Dönerfield <no-replay@sl0p.foo> | 2026-07-18 21:31:00 +0200 |
| commit | b9b2876ba7790b0e92e2c66f516d374ce7d53905 (patch) | |
| tree | 131f313f30f299388c6700817a961f1050bfc5ef /filters | |
| parent | md2html: render linked .md via the about view, fix relative base (diff) | |
| download | cgit-b9b2876ba7790b0e92e2c66f516d374ce7d53905.tar.gz cgit-b9b2876ba7790b0e92e2c66f516d374ce7d53905.tar.xz cgit-b9b2876ba7790b0e92e2c66f516d374ce7d53905.zip | |
md2html: do not loosen tight lists with multi-line items
The list-interrupt preprocessor inserted a blank line before any bullet
that followed a non-item, non-4-space-indented line. When a list item
wrapped onto a 2-space-indented continuation line, the *next* item looked
like a paragraph->list transition, so a blank got injected between items
— turning a tight list into a loose one (every <li> wrapped in <p>), as
seen in docs/internals.md "Writing programs in C".
Track list state and only interrupt an actual paragraph: a bullet that
continues an already-open list (or its indented continuation lines) no
longer triggers a blank-line insert. The original paragraph->list
interrupt and the "1985." ordered-list guard are unchanged.
Diffstat (limited to 'filters')
| -rwxr-xr-x | filters/html-converters/md2html | 27 |
1 files changed, 25 insertions, 2 deletions
diff --git a/filters/html-converters/md2html b/filters/html-converters/md2html index 79d4a17..d2906ec 100755 --- a/filters/html-converters/md2html +++ b/filters/html-converters/md2html @@ -31,6 +31,13 @@ _MD_ANYITEM = re.compile(r'^ {0,3}(?:[-*+]|\d{1,9}[.)])[ \t]') class _ListInterruptPreprocessor(Preprocessor): def run(self, lines): out, in_fence, fence = [], False, None + # Track whether we're already inside a list. A bullet that merely + # continues an existing list must NOT get a blank line inserted before + # it: that would turn a tight list into a loose one (every item wrapped + # in <p>), which is exactly what happens when a preceding item wraps onto + # an indented continuation line and we mistake the next bullet for a + # paragraph->list transition. We only want to interrupt a real paragraph. + in_list = False for line in lines: m = _MD_FENCE.match(line) if m: @@ -41,12 +48,28 @@ class _ListInterruptPreprocessor(Preprocessor): in_fence, fence = False, None out.append(line) continue - if not in_fence and out: + if in_fence: + out.append(line) + continue + if not line.strip(): + # a blank line doesn't end a list (loose lists / lazy + # continuation), so leave in_list untouched + out.append(line) + continue + is_item = bool(_MD_ANYITEM.match(line)) + indented = line[:1] in (' ', '\t') + # a non-indented, non-item line after a list closes that list + if in_list and not is_item and not indented: + in_list = False + if out: prev = out[-1] - if (prev.strip() and not _MD_ANYITEM.match(prev) + if (prev.strip() and not in_list + and not _MD_ANYITEM.match(prev) and not prev.startswith((' ', '\t')) and (_MD_BULLET.match(line) or _MD_ORDERED1.match(line))): out.append('') + if is_item: + in_list = True out.append(line) return out |
