css: matcher draft

This commit is contained in:
Pierre Tachoire
2024-03-15 16:09:16 +01:00
parent a131e96ed5
commit b59fd9b1fb
4 changed files with 121 additions and 0 deletions

View File

@@ -11,6 +11,37 @@ pub fn parse(alloc: std.mem.Allocator, s: []const u8, opts: parser.ParseOptions)
return p.parse(alloc);
}
// matchFirst call m.match with the first node that matches the selector s, from the
// descendants of n and returns true. If none matches, it returns false.
pub fn matchFirst(s: Selector, node: anytype, m: anytype) !bool {
var c = try node.firstChild();
while (true) {
if (c == null) break;
if (try s.match(c.?)) {
try m.match(c.?);
return true;
}
if (try matchFirst(s, c.?, m)) return true;
c = try c.?.nextSibling();
}
return false;
}
// matchAll call m.match with the all the nodes that matches the selector s, from the
// descendants of n.
pub fn matchAll(s: Selector, node: anytype, m: anytype) !void {
var c = try node.firstChild();
while (true) {
if (c == null) break;
if (try s.match(c.?)) try m.match(c.?);
try matchFirst(s, c.?, m);
c = try c.?.nextSibling();
}
}
test "parse" {
const alloc = std.testing.allocator;

22
src/css/libdom.zig Normal file
View File

@@ -0,0 +1,22 @@
const std = @import("std");
const parser = @import("../netsurf.zig");
// Node implementation with Netsurf Libdom C lib.
pub const Node = struct {
node: *parser.Node,
pub fn firstChild(n: Node) !?Node {
const c = try parser.nodeFirstChild(n.node);
if (c) |cc| return .{ .node = cc };
return null;
}
pub fn nextSibling(n: Node) ?Node {
const c = try parser.nodeNextSibling(n.node);
if (c) |cc| return .{ .node = cc };
return null;
}
};

61
src/css/match_test.zig Normal file
View File

@@ -0,0 +1,61 @@
const std = @import("std");
const css = @import("css.zig");
// Node mock implementation for test only.
pub const Node = struct {
child: ?*const Node = null,
sibling: ?*const Node = null,
name: []const u8 = "",
pub fn firstChild(n: *const Node) !?*const Node {
return n.child;
}
pub fn nextSibling(n: *const Node) !?*const Node {
return n.sibling;
}
pub fn tag(n: *const Node) ![]const u8 {
return n.name;
}
};
const Matcher = struct {
const Nodes = std.ArrayList(*const Node);
nodes: Nodes,
fn init(alloc: std.mem.Allocator) Matcher {
return .{ .nodes = Nodes.init(alloc) };
}
fn deinit(m: *Matcher) void {
m.nodes.deinit();
}
fn reset(m: *Matcher) void {
m.nodes.clearRetainingCapacity();
}
pub fn match(m: *Matcher, n: *const Node) !void {
try m.nodes.append(n);
}
};
test "matchFirst" {
const alloc = std.testing.allocator;
const s = try css.parse(alloc, "address", .{});
defer s.deinit(alloc);
var matcher = Matcher.init(alloc);
defer matcher.deinit();
const node: Node = .{
.child = &.{ .name = "address" },
};
_ = try css.matchFirst(s, &node, &matcher);
try std.testing.expect(1 == matcher.nodes.items.len);
try std.testing.expect(matcher.nodes.items[0] == node.child);
}

View File

@@ -165,6 +165,13 @@ pub const Selector = union(enum) {
},
pseudo_element: PseudoClass,
pub fn match(s: Selector, n: anytype) !bool {
return switch (s) {
.tag => |v| std.ascii.eqlIgnoreCase(v, try n.tag()),
else => false,
};
}
pub fn deinit(sel: Selector, alloc: std.mem.Allocator) void {
switch (sel) {
.group => |v| {