From 9f13b14f6d64da1194714b46c7875751c57c2665 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A0=20Arrufat?= Date: Mon, 16 Feb 2026 20:55:51 +0900 Subject: [PATCH] Add support strikethrough and task lists in Markdown --- src/browser/markdown.zig | 64 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/src/browser/markdown.zig b/src/browser/markdown.zig index 095f6de5..72b859d9 100644 --- a/src/browser/markdown.zig +++ b/src/browser/markdown.zig @@ -141,6 +141,10 @@ fn renderElement(el: *Element, state: *State, writer: *std.Io.Writer, page: *Pag try writer.writeAll("*"); state.last_char_was_newline = false; }, + .s, .del => { + try writer.writeAll("~~"); + state.last_char_was_newline = false; + }, .hr => { try writer.writeAll("---\n"); state.last_char_was_newline = true; @@ -168,6 +172,19 @@ fn renderElement(el: *Element, state: *State, writer: *std.Io.Writer, page: *Pag try writer.writeByte('['); state.last_char_was_newline = false; }, + .input => { + if (el.getAttributeSafe(comptime .wrap("type"))) |t| { + if (std.mem.eql(u8, t, "checkbox")) { + if (el.hasAttributeSafe(comptime .wrap("checked"))) { + try writer.writeAll("[x] "); + } else { + try writer.writeAll("[ ] "); + } + state.last_char_was_newline = false; + } + } + return; // Void element + }, else => {}, } @@ -209,6 +226,10 @@ fn renderElement(el: *Element, state: *State, writer: *std.Io.Writer, page: *Pag try writer.writeAll("*"); state.last_char_was_newline = false; }, + .s, .del => { + try writer.writeAll("~~"); + state.last_char_was_newline = false; + }, .blockquote => { state.in_blockquote = false; }, @@ -384,3 +405,46 @@ test "markdown: escaping" { try testing.expectString("\n\\# Not a header\n", aw.written()); } + +test "markdown: strikethrough" { + const testing = @import("../testing.zig"); + const page = try testing.test_session.createPage(); + defer testing.test_session.removePage(); + const doc = page.window._document; + + const div = try doc.createElement("div", null, page); + + const s = try doc.createElement("s", null, page); + try s.asNode().setTextContent("deleted", page); + _ = try div.asNode().appendChild(s.asNode(), page); + + var aw = std.Io.Writer.Allocating.init(testing.allocator); + defer aw.deinit(); + try dump(div.asNode(), .{}, &aw.writer, page); + + try testing.expectString("~~deleted~~\n", aw.written()); +} + +test "markdown: task list" { + const testing = @import("../testing.zig"); + const page = try testing.test_session.createPage(); + defer testing.test_session.removePage(); + const doc = page.window._document; + + const div = try doc.createElement("div", null, page); + + const input1 = try doc.createElement("input", null, page); + try input1.setAttributeSafe(comptime .wrap("type"), .wrap("checkbox"), page); + try input1.setAttributeSafe(comptime .wrap("checked"), .wrap(""), page); + _ = try div.asNode().appendChild(input1.asNode(), page); + + const input2 = try doc.createElement("input", null, page); + try input2.setAttributeSafe(comptime .wrap("type"), .wrap("checkbox"), page); + _ = try div.asNode().appendChild(input2.asNode(), page); + + var aw = std.Io.Writer.Allocating.init(testing.allocator); + defer aw.deinit(); + try dump(div.asNode(), .{}, &aw.writer, page); + + try testing.expectString("[x] [ ] \n", aw.written()); +}