Merge branch 'main' into cdp_struct

This commit is contained in:
Karl Seguin
2025-02-12 17:56:47 +08:00
5 changed files with 267 additions and 0 deletions

View File

@@ -18,13 +18,245 @@
const std = @import("std");
const cdp = @import("cdp.zig");
const css = @import("../dom/css.zig");
const parser = @import("netsurf");
pub fn processMessage(cmd: anytype) !void {
const action = std.meta.stringToEnum(enum {
enable,
getDocument,
performSearch,
getSearchResults,
discardSearchResults,
}, cmd.action) orelse return error.UnknownMethod;
switch (action) {
.enable => return cmd.sendResult(null, .{}),
.getDocument => return getDocument(cmd),
.performSearch => return performSearch(cmd),
.getSearchResults => return getSearchResults(cmd),
.discardSearchResults => return discardSearchResults(cmd),
}
}
// NodeList references tree nodes with an array id.
pub const NodeList = struct {
coll: List,
const List = std.ArrayList(*parser.Node);
pub fn init(alloc: std.mem.Allocator) NodeList {
return .{
.coll = List.init(alloc),
};
}
pub fn deinit(self: *NodeList) void {
self.coll.deinit();
}
pub fn reset(self: *NodeList) void {
self.coll.clearAndFree();
}
pub fn set(self: *NodeList, node: *parser.Node) !NodeId {
const coll = &self.coll;
for (coll.items, 0..) |n, i| {
if (n == node) {
return @intCast(i);
}
}
try coll.append(node);
return @intCast(coll.items.len);
}
};
const NodeId = u32;
const Node = struct {
nodeId: NodeId,
parentId: ?NodeId = null,
backendNodeId: NodeId,
nodeType: u32,
nodeName: []const u8 = "",
localName: []const u8 = "",
nodeValue: []const u8 = "",
childNodeCount: ?u32 = null,
children: ?[]const Node = null,
documentURL: ?[]const u8 = null,
baseURL: ?[]const u8 = null,
xmlVersion: []const u8 = "",
compatibilityMode: []const u8 = "NoQuirksMode",
isScrollable: bool = false,
fn init(n: *parser.Node, nlist: *NodeList) !Node {
const id = try nlist.set(n);
return .{
.nodeId = id,
.backendNodeId = id,
.nodeType = @intFromEnum(try parser.nodeType(n)),
.nodeName = try parser.nodeName(n),
.localName = try parser.nodeLocalName(n),
.nodeValue = try parser.nodeValue(n) orelse "",
};
}
fn initChildren(
self: *Node,
alloc: std.mem.Allocator,
n: *parser.Node,
nlist: *NodeList,
) !std.ArrayList(Node) {
const children = try parser.nodeGetChildNodes(n);
const ln = try parser.nodeListLength(children);
self.childNodeCount = ln;
var list = try std.ArrayList(Node).initCapacity(alloc, ln);
for (0..ln) |i| {
const child = try parser.nodeListItem(children, @intCast(i)) orelse continue;
list.appendAssumeCapacity(try Node.init(child, nlist));
}
self.children = list.items;
return list;
}
};
// https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-getDocument
fn getDocument(cmd: anytype) !void {
// const params = (try cmd.params(struct {
// depth: ?u32 = null,
// pierce: ?bool = null,
// })) orelse return error.InvalidParams;
// retrieve the root node
const page = cmd.session.page orelse return error.NoPage;
const doc = page.doc orelse return error.NoDocument;
const state = cmd.cdp;
const node = parser.documentToNode(doc);
var n = try Node.init(node, &state.node_list);
_ = try n.initChildren(cmd.arena, node, &state.node_list);
return cmd.sendResult(.{
.root = n,
}, .{});
}
pub const NodeSearch = struct {
coll: List,
name: []u8,
alloc: std.mem.Allocator,
var count: u8 = 0;
const List = std.ArrayListUnmanaged(NodeId);
pub fn initCapacity(alloc: std.mem.Allocator, ln: usize) !NodeSearch {
count += 1;
return .{
.alloc = alloc,
.coll = try List.initCapacity(alloc, ln),
.name = try std.fmt.allocPrint(alloc, "{d}", .{count}),
};
}
pub fn deinit(self: *NodeSearch) void {
self.coll.deinit(self.alloc);
self.alloc.free(self.name);
}
pub fn append(self: *NodeSearch, id: NodeId) !void {
try self.coll.append(self.alloc, id);
}
};
pub const NodeSearchList = std.ArrayList(NodeSearch);
// https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-performSearch
fn performSearch(cmd: anytype) !void {
const params = (try cmd.params(struct {
query: []const u8,
includeUserAgentShadowDOM: ?bool = null,
})) orelse return error.InvalidParams;
// retrieve the root node
const page = cmd.session.page orelse return error.NoPage;
const doc = page.doc orelse return error.NoDocument;
const list = try css.querySelectorAll(cmd.cdp.allocator, parser.documentToNode(doc), params.query);
const ln = list.nodes.items.len;
var ns = try NodeSearch.initCapacity(cmd.cdp.allocator, ln);
var state = cmd.cdp;
for (list.nodes.items) |n| {
const id = try state.node_list.set(n);
try ns.append(id);
}
try state.node_search_list.append(ns);
return cmd.sendResult(.{
.searchId = ns.name,
.resultCount = @as(u32, @intCast(ln)),
}, .{});
}
// https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-discardSearchResults
fn discardSearchResults(cmd: anytype) !void {
const params = (try cmd.params(struct {
searchId: []const u8,
})) orelse return error.InvalidParams;
var state = cmd.cdp;
// retrieve the search from context
for (state.node_search_list.items, 0..) |*s, i| {
if (!std.mem.eql(u8, s.name, params.searchId)) continue;
s.deinit();
_ = state.node_search_list.swapRemove(i);
break;
}
return cmd.sendResult(null, .{});
}
// https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-getSearchResults
fn getSearchResults(cmd: anytype) !void {
const params = (try cmd.params(struct {
searchId: []const u8,
fromIndex: u32,
toIndex: u32,
})) orelse return error.InvalidParams;
if (params.fromIndex >= params.toIndex) {
return error.BadIndices;
}
const state = cmd.cdp;
// retrieve the search from context
var ns: ?*const NodeSearch = undefined;
for (state.node_search_list.items) |s| {
if (!std.mem.eql(u8, s.name, params.searchId)) continue;
ns = &s;
break;
}
if (ns == null) {
return error.searchResultNotFound;
}
const items = ns.?.coll.items;
if (params.fromIndex >= items.len) return error.BadFromIndex;
if (params.toIndex > items.len) return error.BadToIndex;
return cmd.sendResult(.{
.nodeIds = ns.?.coll.items[params.fromIndex..params.toIndex]
}, .{});
}