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
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
run: kill `cat WS.pid`

View File

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

View File

@@ -38,7 +38,6 @@ const State = struct {
in_pre: bool = false,
pre_node: ?*Node = null,
in_code: bool = false,
in_blockquote: bool = false,
in_table: bool = false,
table_row_index: 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) {
.document, .document_fragment => {
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();
while (it.next()) |child| {
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();
// Skip hidden/metadata elements
@@ -184,7 +183,6 @@ fn renderElement(el: *Element, state: *State, writer: *std.Io.Writer, page: *Pag
},
.blockquote => {
try writer.writeAll("> ");
state.in_blockquote = true;
state.last_char_was_newline = false;
},
.pre => {
@@ -241,19 +239,25 @@ fn renderElement(el: *Element, state: *State, writer: *std.Io.Writer, page: *Pag
},
.anchor => {
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;
return;
},
.input => {
if (el.getAttributeSafe(comptime .wrap("type"))) |t| {
if (std.mem.eql(u8, t, "checkbox")) {
if (el.hasAttributeSafe(comptime .wrap("checked"))) {
const input = el.as(Element.Html.Input);
if (input._input_type == .checkbox) {
if (input._checked) {
try writer.writeAll("[x] ");
} else {
try writer.writeAll("[ ] ");
}
state.last_char_was_newline = false;
}
}
return;
},
else => {},
@@ -266,14 +270,6 @@ fn renderElement(el: *Element, state: *State, writer: *std.Io.Writer, page: *Pag
// Suffixes
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 => {
if (!state.last_char_was_newline) {
try writer.writeByte('\n');
@@ -302,9 +298,7 @@ fn renderElement(el: *Element, state: *State, writer: *std.Io.Writer, page: *Pag
try writer.writeAll("~~");
state.last_char_was_newline = false;
},
.blockquote => {
state.in_blockquote = false;
},
.blockquote => {},
.ul, .ol => {
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 (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 {
for (text) |c| {
switch (c) {
'\\', '`', '*', '_', '{', '}', '[', ']', '(', ')', '#', '+', '-', '!', '|', '<', '>' => {
'\\', '`', '*', '_', '{', '}', '[', ']', '(', ')', '#', '+', '-', '!', '|' => {
try writer.writeByte('\\');
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;
while (i < level) : (i += 1) {
try writer.writeAll(" ");