summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authort <t@tjp.lol>2026-06-16 12:02:33 -0600
committert <t@tjp.lol>2026-06-16 12:02:58 -0600
commite9708f910b74fa0f5412d0157cb2d43c9425a480 (patch)
treefc9b71bafd05787e77b785a1ae769f0d6ed0d442 /src
parent28cb3eacfcf1217b4d014dd864005deb2d7f0585 (diff)
fix user-text empty lines
Diffstat (limited to 'src')
-rw-r--r--src/markdown.zig33
1 files changed, 32 insertions, 1 deletions
diff --git a/src/markdown.zig b/src/markdown.zig
index fad1676..58f1b97 100644
--- a/src/markdown.zig
+++ b/src/markdown.zig
@@ -286,6 +286,7 @@ pub const Renderer = struct {
},
c.MD_BLOCK_P => {
self.flushParagraph() catch |e| return self.fail(e);
+ if (self.list_item_depth == 0) self.appendBlank() catch |e| return self.fail(e);
},
c.MD_BLOCK_LI => {
self.flushParagraph() catch |e| return self.fail(e);
@@ -337,7 +338,7 @@ pub const Renderer = struct {
const self: *Renderer = @ptrCast(@alignCast(userdata.?));
const s = p[0..@intCast(size)];
switch (t) {
- c.MD_TEXT_BR, c.MD_TEXT_SOFTBR => self.add(" ") catch |e| return self.fail(e),
+ c.MD_TEXT_BR, c.MD_TEXT_SOFTBR => self.add("\n") catch |e| return self.fail(e),
c.MD_TEXT_NULLCHAR => self.add("�") catch |e| return self.fail(e),
c.MD_TEXT_ENTITY => self.add(decodeEntity(s)) catch |e| return self.fail(e),
else => self.add(s) catch |e| return self.fail(e),
@@ -386,6 +387,36 @@ test "Renderer uses MD4C for common markdown" {
try testing.expect(found_code);
}
+test "Renderer preserves user-authored line breaks and blank paragraph lines" {
+ var out: std.ArrayList([]const u8) = .empty;
+ defer {
+ for (out.items) |l| testing.allocator.free(l);
+ out.deinit(testing.allocator);
+ }
+ var r: Renderer = .{ .alloc = testing.allocator, .width = 80, .out_lines = &out };
+ try r.render("first\nsecond\n\nthird");
+ try testing.expectEqual(@as(usize, 4), out.items.len);
+ try testing.expectEqualStrings("first", out.items[0]);
+ try testing.expectEqualStrings("second", out.items[1]);
+ try testing.expectEqualStrings("", out.items[2]);
+ try testing.expectEqualStrings("third", out.items[3]);
+}
+
+test "Renderer keeps soft breaks between inline-styled lines" {
+ var out: std.ArrayList([]const u8) = .empty;
+ defer {
+ for (out.items) |l| testing.allocator.free(l);
+ out.deinit(testing.allocator);
+ }
+ var r: Renderer = .{ .alloc = testing.allocator, .width = 80, .out_lines = &out };
+ try r.render("`code block`\n_underline_\n**bold**\n~strikethrough~");
+ try testing.expectEqual(@as(usize, 4), out.items.len);
+ try testing.expect(std.mem.indexOf(u8, out.items[0], "code block") != null);
+ try testing.expect(std.mem.indexOf(u8, out.items[1], "underline") != null);
+ try testing.expect(std.mem.indexOf(u8, out.items[2], "bold") != null);
+ try testing.expect(std.mem.indexOf(u8, out.items[3], "strikethrough") != null);
+}
+
test "Renderer preserves nested list indentation" {
var out: std.ArrayList([]const u8) = .empty;
defer {