diff --git a/packages/tui/src/components/markdown.ts b/packages/tui/src/components/markdown.ts index d5e3f477c..ed8ad780e 100644 --- a/packages/tui/src/components/markdown.ts +++ b/packages/tui/src/components/markdown.ts @@ -572,6 +572,7 @@ export class Markdown implements Component { for (let i = 0; i < token.items.length; i++) { const item = token.items[i]; + const isLastItem = i === token.items.length - 1; const bullet = token.ordered ? this.options.preserveOrderedListMarkers ? (this.getOrderedListMarker(item) ?? `${startNumber + i}. `) @@ -604,6 +605,10 @@ export class Markdown implements Component { if (!renderedAnyLine) { lines.push(firstPrefix); } + + if (token.loose && !isLastItem) { + lines.push(""); + } } return lines; diff --git a/packages/tui/test/markdown.test.ts b/packages/tui/test/markdown.test.ts index fd5345df6..9c0be05c4 100644 --- a/packages/tui/test/markdown.test.ts +++ b/packages/tui/test/markdown.test.ts @@ -149,6 +149,37 @@ describe("Markdown component", () => { assert.ok(plainLines.some((line) => line.includes("2. Second ordered"))); }); + it("should render blank lines between loose list items", () => { + const markdown = new Markdown( + `1. Lorem ipsum dolor sit amet. + + Ut enim ad minim veniam. + +2. Duis aute irure dolor. + + Excepteur sint occaecat cupidatat. + +3. Beep boop`, + 0, + 0, + defaultMarkdownTheme, + ); + + const lines = markdown.render(80).map((line) => stripAnsi(line).trimEnd()); + + assert.deepStrictEqual(lines, [ + "1. Lorem ipsum dolor sit amet.", + "", + " Ut enim ad minim veniam.", + "", + "2. Duis aute irure dolor.", + "", + " Excepteur sint occaecat cupidatat.", + "", + "3. Beep boop", + ]); + }); + it("should render task list markers", () => { const markdown = new Markdown("- [ ] beep\n- [x] boop", 0, 0, defaultMarkdownTheme);