mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-04-02 10:19:17 +00:00
Compare commits
1 Commits
main
...
abort_asse
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
de0a04a58e |
@@ -235,10 +235,6 @@ fn _abort(self: *Client, comptime abort_all: bool, frame_id: u32) void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (comptime IS_DEBUG and abort_all) {
|
|
||||||
std.debug.assert(self.active == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
var q = &self.queue;
|
var q = &self.queue;
|
||||||
var n = q.first;
|
var n = q.first;
|
||||||
@@ -259,12 +255,16 @@ fn _abort(self: *Client, comptime abort_all: bool, frame_id: u32) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (comptime IS_DEBUG and abort_all) {
|
if (comptime IS_DEBUG and abort_all) {
|
||||||
std.debug.assert(self.in_use.first == null);
|
// Even after an abort_all, we could still have transfers, but, at the
|
||||||
|
// very least, they should all be flagged as aborted.
|
||||||
const running = self.handles.perform() catch |err| {
|
var it = self.in_use.first;
|
||||||
lp.assert(false, "multi perform in abort", .{ .err = err });
|
var leftover: usize = 0;
|
||||||
};
|
while (it) |node| : (it = node.next) {
|
||||||
std.debug.assert(running == 0);
|
const conn: *http.Connection = @fieldParentPtr("node", node);
|
||||||
|
std.debug.assert((Transfer.fromConnection(conn) catch unreachable).aborted);
|
||||||
|
leftover += 1;
|
||||||
|
}
|
||||||
|
std.debug.assert(self.active == leftover);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,9 @@ const Element = @import("webapi/Element.zig");
|
|||||||
const Node = @import("webapi/Node.zig");
|
const Node = @import("webapi/Node.zig");
|
||||||
const isAllWhitespace = @import("../string.zig").isAllWhitespace;
|
const isAllWhitespace = @import("../string.zig").isAllWhitespace;
|
||||||
|
|
||||||
pub const Opts = struct {};
|
pub const Opts = struct {
|
||||||
|
// Options for future customization (e.g., dialect)
|
||||||
|
};
|
||||||
|
|
||||||
const State = struct {
|
const State = struct {
|
||||||
const ListType = enum { ordered, unordered };
|
const ListType = enum { ordered, unordered };
|
||||||
@@ -37,6 +39,7 @@ const State = struct {
|
|||||||
list_depth: usize = 0,
|
list_depth: usize = 0,
|
||||||
list_stack: [32]ListState = undefined,
|
list_stack: [32]ListState = undefined,
|
||||||
pre_node: ?*Node = null,
|
pre_node: ?*Node = null,
|
||||||
|
in_code: 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,
|
||||||
@@ -97,35 +100,27 @@ fn getAnchorLabel(el: *Element) ?[]const u8 {
|
|||||||
return el.getAttributeSafe(comptime .wrap("aria-label")) orelse el.getAttributeSafe(comptime .wrap("title"));
|
return el.getAttributeSafe(comptime .wrap("aria-label")) orelse el.getAttributeSafe(comptime .wrap("title"));
|
||||||
}
|
}
|
||||||
|
|
||||||
const ContentInfo = struct {
|
fn hasBlockDescendant(root: *Node) bool {
|
||||||
has_visible: bool,
|
var tw = TreeWalker.FullExcludeSelf.Elements.init(root, .{});
|
||||||
has_block: bool,
|
while (tw.next()) |el| {
|
||||||
};
|
if (el.getTag().isBlock()) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
fn analyzeContent(root: *Node) ContentInfo {
|
fn hasVisibleContent(root: *Node) bool {
|
||||||
var result: ContentInfo = .{ .has_visible = false, .has_block = false };
|
|
||||||
var tw = TreeWalker.FullExcludeSelf.init(root, .{});
|
var tw = TreeWalker.FullExcludeSelf.init(root, .{});
|
||||||
while (tw.next()) |node| {
|
while (tw.next()) |node| {
|
||||||
if (isSignificantText(node)) {
|
if (isSignificantText(node)) return true;
|
||||||
result.has_visible = true;
|
if (node.is(Element)) |el| {
|
||||||
if (result.has_block) return result;
|
|
||||||
} else if (node.is(Element)) |el| {
|
|
||||||
if (!isVisibleElement(el)) {
|
if (!isVisibleElement(el)) {
|
||||||
tw.skipChildren();
|
tw.skipChildren();
|
||||||
} else {
|
} else if (el.getTag() == .img) {
|
||||||
const tag = el.getTag();
|
return true;
|
||||||
if (tag == .img) {
|
|
||||||
result.has_visible = true;
|
|
||||||
if (result.has_block) return result;
|
|
||||||
}
|
|
||||||
if (tag.isBlock()) {
|
|
||||||
result.has_block = true;
|
|
||||||
if (result.has_visible) return result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Context = struct {
|
const Context = struct {
|
||||||
@@ -175,7 +170,9 @@ const Context = struct {
|
|||||||
|
|
||||||
if (!isVisibleElement(el)) return;
|
if (!isVisibleElement(el)) return;
|
||||||
|
|
||||||
// Ensure block elements start on a new line
|
// --- Opening Tag Logic ---
|
||||||
|
|
||||||
|
// Ensure block elements start on a new line (double newline for paragraphs etc)
|
||||||
if (tag.isBlock() and !self.state.in_table) {
|
if (tag.isBlock() and !self.state.in_table) {
|
||||||
try self.ensureNewline();
|
try self.ensureNewline();
|
||||||
if (shouldAddSpacing(tag)) {
|
if (shouldAddSpacing(tag)) {
|
||||||
@@ -185,6 +182,7 @@ const Context = struct {
|
|||||||
try self.ensureNewline();
|
try self.ensureNewline();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prefixes
|
||||||
switch (tag) {
|
switch (tag) {
|
||||||
.h1 => try self.writer.writeAll("# "),
|
.h1 => try self.writer.writeAll("# "),
|
||||||
.h2 => try self.writer.writeAll("## "),
|
.h2 => try self.writer.writeAll("## "),
|
||||||
@@ -227,6 +225,7 @@ const Context = struct {
|
|||||||
try self.writer.writeByte('|');
|
try self.writer.writeByte('|');
|
||||||
},
|
},
|
||||||
.td, .th => {
|
.td, .th => {
|
||||||
|
// Note: leading pipe handled by previous cell closing or tr opening
|
||||||
self.state.last_char_was_newline = false;
|
self.state.last_char_was_newline = false;
|
||||||
try self.writer.writeByte(' ');
|
try self.writer.writeByte(' ');
|
||||||
},
|
},
|
||||||
@@ -242,6 +241,7 @@ const Context = struct {
|
|||||||
.code => {
|
.code => {
|
||||||
if (self.state.pre_node == null) {
|
if (self.state.pre_node == null) {
|
||||||
try self.writer.writeByte('`');
|
try self.writer.writeByte('`');
|
||||||
|
self.state.in_code = true;
|
||||||
self.state.last_char_was_newline = false;
|
self.state.last_char_was_newline = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -286,15 +286,16 @@ const Context = struct {
|
|||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
.anchor => {
|
.anchor => {
|
||||||
const info = analyzeContent(el.asNode());
|
const has_content = hasVisibleContent(el.asNode());
|
||||||
const label = getAnchorLabel(el);
|
const label = getAnchorLabel(el);
|
||||||
const href_raw = el.getAttributeSafe(comptime .wrap("href"));
|
const href_raw = el.getAttributeSafe(comptime .wrap("href"));
|
||||||
|
|
||||||
if (!info.has_visible and label == null and href_raw == null) return;
|
if (!has_content and label == null and href_raw == null) return;
|
||||||
|
|
||||||
|
const has_block = hasBlockDescendant(el.asNode());
|
||||||
const href = if (href_raw) |h| URL.resolve(self.page.call_arena, self.page.base(), h, .{ .encode = true }) catch h else null;
|
const href = if (href_raw) |h| URL.resolve(self.page.call_arena, self.page.base(), h, .{ .encode = true }) catch h else null;
|
||||||
|
|
||||||
if (info.has_block) {
|
if (has_block) {
|
||||||
try self.renderChildren(el.asNode());
|
try self.renderChildren(el.asNode());
|
||||||
if (href) |h| {
|
if (href) |h| {
|
||||||
if (!self.state.last_char_was_newline) try self.writer.writeByte('\n');
|
if (!self.state.last_char_was_newline) try self.writer.writeByte('\n');
|
||||||
@@ -306,12 +307,25 @@ const Context = struct {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const standalone = isStandaloneAnchor(el);
|
if (isStandaloneAnchor(el)) {
|
||||||
if (standalone) {
|
|
||||||
if (!self.state.last_char_was_newline) try self.writer.writeByte('\n');
|
if (!self.state.last_char_was_newline) try self.writer.writeByte('\n');
|
||||||
|
try self.writer.writeByte('[');
|
||||||
|
if (has_content) {
|
||||||
|
try self.renderChildren(el.asNode());
|
||||||
|
} else {
|
||||||
|
try self.writer.writeAll(label orelse "");
|
||||||
|
}
|
||||||
|
try self.writer.writeAll("](");
|
||||||
|
if (href) |h| {
|
||||||
|
try self.writer.writeAll(h);
|
||||||
|
}
|
||||||
|
try self.writer.writeAll(")\n");
|
||||||
|
self.state.last_char_was_newline = true;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try self.writer.writeByte('[');
|
try self.writer.writeByte('[');
|
||||||
if (info.has_visible) {
|
if (has_content) {
|
||||||
try self.renderChildren(el.asNode());
|
try self.renderChildren(el.asNode());
|
||||||
} else {
|
} else {
|
||||||
try self.writer.writeAll(label orelse "");
|
try self.writer.writeAll(label orelse "");
|
||||||
@@ -321,12 +335,7 @@ const Context = struct {
|
|||||||
try self.writer.writeAll(h);
|
try self.writer.writeAll(h);
|
||||||
}
|
}
|
||||||
try self.writer.writeByte(')');
|
try self.writer.writeByte(')');
|
||||||
if (standalone) {
|
self.state.last_char_was_newline = false;
|
||||||
try self.writer.writeByte('\n');
|
|
||||||
self.state.last_char_was_newline = true;
|
|
||||||
} else {
|
|
||||||
self.state.last_char_was_newline = false;
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
.input => {
|
.input => {
|
||||||
@@ -341,8 +350,12 @@ const Context = struct {
|
|||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Render Children ---
|
||||||
try self.renderChildren(el.asNode());
|
try self.renderChildren(el.asNode());
|
||||||
|
|
||||||
|
// --- Closing Tag Logic ---
|
||||||
|
|
||||||
|
// Suffixes
|
||||||
switch (tag) {
|
switch (tag) {
|
||||||
.pre => {
|
.pre => {
|
||||||
if (!self.state.last_char_was_newline) {
|
if (!self.state.last_char_was_newline) {
|
||||||
@@ -355,6 +368,7 @@ const Context = struct {
|
|||||||
.code => {
|
.code => {
|
||||||
if (self.state.pre_node == null) {
|
if (self.state.pre_node == null) {
|
||||||
try self.writer.writeByte('`');
|
try self.writer.writeByte('`');
|
||||||
|
self.state.in_code = false;
|
||||||
self.state.last_char_was_newline = false;
|
self.state.last_char_was_newline = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -397,6 +411,7 @@ const Context = struct {
|
|||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Post-block newlines
|
||||||
if (tag.isBlock() and !self.state.in_table) {
|
if (tag.isBlock() and !self.state.in_table) {
|
||||||
try self.ensureNewline();
|
try self.ensureNewline();
|
||||||
}
|
}
|
||||||
@@ -439,19 +454,15 @@ const Context = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn escape(self: *Context, text: []const u8) !void {
|
fn escape(self: *Context, text: []const u8) !void {
|
||||||
var start: usize = 0;
|
for (text) |c| {
|
||||||
for (text, 0..) |c, i| {
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
'\\', '`', '*', '_', '{', '}', '[', ']', '(', ')', '#', '+', '-', '!', '|' => {
|
'\\', '`', '*', '_', '{', '}', '[', ']', '(', ')', '#', '+', '-', '!', '|' => {
|
||||||
if (i > start) try self.writer.writeAll(text[start..i]);
|
|
||||||
try self.writer.writeByte('\\');
|
try self.writer.writeByte('\\');
|
||||||
try self.writer.writeByte(c);
|
try self.writer.writeByte(c);
|
||||||
start = i + 1;
|
|
||||||
},
|
},
|
||||||
else => {},
|
else => try self.writer.writeByte(c),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (start < text.len) try self.writer.writeAll(text[start..]);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user