aboutsummaryrefslogtreecommitdiffstats
path: root/filters
diff options
context:
space:
mode:
authorJason A. Dönerfield <no-replay@sl0p.foo>2026-07-18 21:13:31 +0200
committerJason A. Dönerfield <no-replay@sl0p.foo>2026-07-18 21:31:00 +0200
commitb9b2876ba7790b0e92e2c66f516d374ce7d53905 (patch)
tree131f313f30f299388c6700817a961f1050bfc5ef /filters
parentmd2html: render linked .md via the about view, fix relative base (diff)
downloadcgit-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-xfilters/html-converters/md2html27
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