Make --dump format optional and improve markdown rendering

This commit is contained in:
Adrià Arrufat
2026-02-18 19:33:32 +09:00
parent 0ec4522f9e
commit ce5dad722f
3 changed files with 33 additions and 37 deletions

View File

@@ -224,7 +224,7 @@ jobs:
- name: run hyperfine - name: run hyperfine
run: | run: |
hyperfine --export-json=hyperfine.json --warmup 3 --runs 20 --shell=none "./lightpanda --dump html http://127.0.0.1:1234/campfire-commerce/" hyperfine --export-json=hyperfine.json --warmup 3 --runs 20 --shell=none "./lightpanda --dump http://127.0.0.1:1234/campfire-commerce/"
- name: stop http - name: stop http
run: kill `cat WS.pid` run: kill `cat WS.pid`

View File

@@ -560,15 +560,17 @@ fn parseFetchArgs(
while (args.next()) |opt| { while (args.next()) |opt| {
if (std.mem.eql(u8, "--dump", opt)) { if (std.mem.eql(u8, "--dump", opt)) {
const str = args.next() orelse { var peek_args = args.*;
log.fatal(.app, "missing argument value", .{ .arg = "--dump" }); if (peek_args.next()) |next_arg| {
return error.InvalidArgument; if (std.meta.stringToEnum(DumpFormat, next_arg)) |mode| {
}; dump_mode = mode;
_ = args.next();
dump_mode = std.meta.stringToEnum(DumpFormat, str) orelse { } else {
log.fatal(.app, "invalid option choice", .{ .arg = "--dump", .value = str }); dump_mode = .html;
return error.InvalidArgument; }
}; } else {
dump_mode = .html;
}
continue; continue;
} }

View File

@@ -38,7 +38,6 @@ const State = struct {
in_pre: bool = false, in_pre: bool = false,
pre_node: ?*Node = null, pre_node: ?*Node = null,
in_code: bool = false, in_code: bool = false,
in_blockquote: bool = false,
in_table: bool = false, in_table: bool = false,
table_row_index: usize = 0, table_row_index: usize = 0,
table_col_count: usize = 0, table_col_count: usize = 0,
@@ -75,7 +74,7 @@ pub fn dump(node: *Node, opts: Opts, writer: *std.Io.Writer, page: *Page) !void
} }
} }
fn render(node: *Node, state: *State, writer: *std.Io.Writer, page: *Page) anyerror!void { fn render(node: *Node, state: *State, writer: *std.Io.Writer, page: *Page) error{WriteFailed}!void {
switch (node._type) { switch (node._type) {
.document, .document_fragment => { .document, .document_fragment => {
try renderChildren(node, state, writer, page); try renderChildren(node, state, writer, page);
@@ -100,14 +99,14 @@ fn render(node: *Node, state: *State, writer: *std.Io.Writer, page: *Page) anyer
} }
} }
fn renderChildren(parent: *Node, state: *State, writer: *std.Io.Writer, page: *Page) anyerror!void { fn renderChildren(parent: *Node, state: *State, writer: *std.Io.Writer, page: *Page) !void {
var it = parent.childrenIterator(); var it = parent.childrenIterator();
while (it.next()) |child| { while (it.next()) |child| {
try render(child, state, writer, page); try render(child, state, writer, page);
} }
} }
fn renderElement(el: *Element, state: *State, writer: *std.Io.Writer, page: *Page) anyerror!void { fn renderElement(el: *Element, state: *State, writer: *std.Io.Writer, page: *Page) !void {
const tag = el.getTag(); const tag = el.getTag();
// Skip hidden/metadata elements // Skip hidden/metadata elements
@@ -184,7 +183,6 @@ fn renderElement(el: *Element, state: *State, writer: *std.Io.Writer, page: *Pag
}, },
.blockquote => { .blockquote => {
try writer.writeAll("> "); try writer.writeAll("> ");
state.in_blockquote = true;
state.last_char_was_newline = false; state.last_char_was_newline = false;
}, },
.pre => { .pre => {
@@ -241,18 +239,24 @@ fn renderElement(el: *Element, state: *State, writer: *std.Io.Writer, page: *Pag
}, },
.anchor => { .anchor => {
try writer.writeByte('['); try writer.writeByte('[');
try renderChildren(el.asNode(), state, writer, page);
try writer.writeAll("](");
if (el.getAttributeSafe(comptime .wrap("href"))) |href| {
try writer.writeAll(href);
}
try writer.writeByte(')');
state.last_char_was_newline = false; state.last_char_was_newline = false;
return;
}, },
.input => { .input => {
if (el.getAttributeSafe(comptime .wrap("type"))) |t| { const input = el.as(Element.Html.Input);
if (std.mem.eql(u8, t, "checkbox")) { if (input._input_type == .checkbox) {
if (el.hasAttributeSafe(comptime .wrap("checked"))) { if (input._checked) {
try writer.writeAll("[x] "); try writer.writeAll("[x] ");
} else { } else {
try writer.writeAll("[ ] "); try writer.writeAll("[ ] ");
}
state.last_char_was_newline = false;
} }
state.last_char_was_newline = false;
} }
return; return;
}, },
@@ -266,14 +270,6 @@ fn renderElement(el: *Element, state: *State, writer: *std.Io.Writer, page: *Pag
// Suffixes // Suffixes
switch (tag) { switch (tag) {
.anchor => {
try writer.writeAll("](");
if (el.getAttributeSafe(comptime .wrap("href"))) |href| {
try writer.writeAll(href);
}
try writer.writeByte(')');
state.last_char_was_newline = false;
},
.pre => { .pre => {
if (!state.last_char_was_newline) { if (!state.last_char_was_newline) {
try writer.writeByte('\n'); try writer.writeByte('\n');
@@ -302,9 +298,7 @@ fn renderElement(el: *Element, state: *State, writer: *std.Io.Writer, page: *Pag
try writer.writeAll("~~"); try writer.writeAll("~~");
state.last_char_was_newline = false; state.last_char_was_newline = false;
}, },
.blockquote => { .blockquote => {},
state.in_blockquote = false;
},
.ul, .ol => { .ul, .ol => {
if (state.list_depth > 0) state.list_depth -= 1; if (state.list_depth > 0) state.list_depth -= 1;
}, },
@@ -340,7 +334,7 @@ fn renderElement(el: *Element, state: *State, writer: *std.Io.Writer, page: *Pag
} }
} }
fn renderText(text: []const u8, state: *State, writer: *std.Io.Writer) anyerror!void { fn renderText(text: []const u8, state: *State, writer: *std.Io.Writer) !void {
if (text.len == 0) return; if (text.len == 0) return;
if (state.in_pre) { if (state.in_pre) {
@@ -395,7 +389,7 @@ fn renderText(text: []const u8, state: *State, writer: *std.Io.Writer) anyerror!
fn escapeMarkdown(writer: *std.Io.Writer, text: []const u8) !void { fn escapeMarkdown(writer: *std.Io.Writer, text: []const u8) !void {
for (text) |c| { for (text) |c| {
switch (c) { switch (c) {
'\\', '`', '*', '_', '{', '}', '[', ']', '(', ')', '#', '+', '-', '!', '|', '<', '>' => { '\\', '`', '*', '_', '{', '}', '[', ']', '(', ')', '#', '+', '-', '!', '|' => {
try writer.writeByte('\\'); try writer.writeByte('\\');
try writer.writeByte(c); try writer.writeByte(c);
}, },
@@ -404,7 +398,7 @@ fn escapeMarkdown(writer: *std.Io.Writer, text: []const u8) !void {
} }
} }
fn writeIndentation(level: usize, writer: *std.Io.Writer) anyerror!void { fn writeIndentation(level: usize, writer: *std.Io.Writer) !void {
var i: usize = 0; var i: usize = 0;
while (i < level) : (i += 1) { while (i < level) : (i += 1) {
try writer.writeAll(" "); try writer.writeAll(" ");