mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-10-08 04:11:45 -04:00
Upgrade to Zig 0.17
Dependencies: - v8: zig-v8-fork 0.17 branch (lightpanda-io/zig-v8-fork#218). - sqlite3: build the amalgamation directly; the allyourcodebase wrapper has no 0.17 support yet. - pcre2: master commit with 0.17 support (no release yet). - translate_c package (2.0.0) replaces the deprecated addTranslateC. default_init is set to keep 0.16's zero-initialized struct fields. Build: - b.pathFromRoot/build_root/args/sysroot are gone: resolve paths from b.root, use addPassthruArgs, declare configure-time file and directory dependencies, and poison the configure cache for the git version. - Drop curl config values the template never used (now an error). - Drop the 0.16 zip-fetch workaround from the Makefile and CI. - -Doptimize=ReleaseFast -> -Doptimize=fast. Language and std: - @intFromEnum/@enumFromInt -> @backingInt/@fromBackingInt. - Struct-of-arrays @typeInfo (field_names, field_types, decl_names, param_types, error_names). - `a ** n` removed: @splat for arrays, string.repeat for strings. - errdefer captures removed: split WebDriver.run and fulfillRedirect. - @hasDecl only sees pub decls: make StyleManager's Spec.finish pub, otherwise it silently stops running. - SafeAllocator replaces DebugAllocator; the test runner now has to initialize std.testing.allocator_instance itself. - std.fmt.allocPrint/bufPrint -> Allocator.print/std.mem.print, dupeZ -> dupeSentinel, std.builtin -> std.lang, builtin.os -> builtin.target.os, zon.parse arena API, BufferFirstAllocator, and the remaining renames (getLastOrNull, bit_set, ascii.find*, meta.Int).
This commit is contained in:
1 parent
e020e9d350
commit
10609b025a
192 files changed
+1124
-1141
No files matched your search
@@ -41,14 +41,6 @@ runs:
|
||||
# Zig version used from the `minimum_zig_version` field in build.zig.zon
|
||||
- uses: mlugg/setup-zig@d1434d08867e3ee9daa34448df10607b98908d29 # v2.2.1
|
||||
|
||||
# Zig 0.16 writes fetched .zip archives to <global cache>/tmp but no longer
|
||||
# creates that directory, so zip dependencies (sqlite amalgamation) fail
|
||||
# with "failed to create temporary zip file: FileNotFound" on the fresh
|
||||
# cache dir setup-zig points ZIG_GLOBAL_CACHE_DIR at.
|
||||
- name: Zig 0.16 zip-fetch workaround
|
||||
shell: bash
|
||||
run: mkdir -p "${ZIG_GLOBAL_CACHE_DIR:-$HOME/.cache/zig}/tmp"
|
||||
|
||||
# Rust Toolchain for src/rust (html5ever bridge, renderer)
|
||||
- uses: dtolnay/rust-toolchain@2c7215f132e9ebf062739d9130488b56d53c060c # master
|
||||
with:
|
||||
|
||||
@@ -44,4 +44,4 @@ runs:
|
||||
- name: v8 snapshot
|
||||
shell: bash
|
||||
if: hashFiles('src/snapshot.bin') == ''
|
||||
run: zig build -Dprebuilt_v8_path=v8/libc_v8.a -Doptimize=ReleaseFast snapshot_creator -- src/snapshot.bin
|
||||
run: zig build -Dprebuilt_v8_path=v8/libc_v8.a -Doptimize=fast snapshot_creator -- src/snapshot.bin
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
- uses: ./.github/actions/v8-snapshot
|
||||
|
||||
- name: zig build release
|
||||
run: zig build -Dsnapshot_path=../../snapshot.bin -Dprebuilt_v8_path=v8/libc_v8.a -Doptimize=ReleaseFast -Dcpu=x86_64
|
||||
run: zig build -Dsnapshot_path=../../snapshot.bin -Dprebuilt_v8_path=v8/libc_v8.a -Doptimize=fast -Dcpu=x86_64
|
||||
|
||||
- name: upload artifact
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
|
||||
@@ -27,7 +27,7 @@ jobs:
|
||||
- uses: ./.github/actions/install
|
||||
|
||||
- name: zig build release
|
||||
run: zig build -Dprebuilt_v8_path=v8/libc_v8.a -Doptimize=ReleaseFast -Dcpu=x86_64
|
||||
run: zig build -Dprebuilt_v8_path=v8/libc_v8.a -Doptimize=fast -Dcpu=x86_64
|
||||
|
||||
- name: upload artifact
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
|
||||
@@ -53,7 +53,7 @@ jobs:
|
||||
- uses: ./.github/actions/v8-snapshot
|
||||
|
||||
- name: zig build release
|
||||
run: zig build -Dsnapshot_path=../../snapshot.bin -Dprebuilt_v8_path=v8/libc_v8.a -Doptimize=ReleaseFast -Dorderfile=orderfile/lightpanda.ld -Dcpu=x86_64
|
||||
run: zig build -Dsnapshot_path=../../snapshot.bin -Dprebuilt_v8_path=v8/libc_v8.a -Doptimize=fast -Dorderfile=orderfile/lightpanda.ld -Dcpu=x86_64
|
||||
|
||||
- name: upload artifact
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
|
||||
@@ -56,7 +56,7 @@ jobs:
|
||||
- uses: ./.github/actions/orderfile
|
||||
id: orderfile
|
||||
with:
|
||||
build-args: -Dsnapshot_path=../../snapshot.bin -Dprebuilt_v8_path=v8/libc_v8.a -Doptimize=ReleaseFast -Dcpu=x86_64
|
||||
build-args: -Dsnapshot_path=../../snapshot.bin -Dprebuilt_v8_path=v8/libc_v8.a -Doptimize=fast -Dcpu=x86_64
|
||||
|
||||
- name: open a pull request
|
||||
env:
|
||||
|
||||
@@ -58,10 +58,10 @@ jobs:
|
||||
arch: ${{env.ARCH}}
|
||||
|
||||
- name: v8 snapshot
|
||||
run: zig build -Dprebuilt_v8_path=v8/libc_v8.a -Doptimize=ReleaseFast snapshot_creator -- src/snapshot.bin
|
||||
run: zig build -Dprebuilt_v8_path=v8/libc_v8.a -Doptimize=fast snapshot_creator -- src/snapshot.bin
|
||||
|
||||
- name: zig build
|
||||
run: zig build -Dsnapshot_path=../../snapshot.bin -Dprebuilt_v8_path=v8/libc_v8.a -Doptimize=ReleaseFast -Dorderfile=orderfile/lightpanda.ld ${{ matrix.cpu_flag }} ${{ env.VERSION_FLAG }}
|
||||
run: zig build -Dsnapshot_path=../../snapshot.bin -Dprebuilt_v8_path=v8/libc_v8.a -Doptimize=fast -Dorderfile=orderfile/lightpanda.ld ${{ matrix.cpu_flag }} ${{ env.VERSION_FLAG }}
|
||||
|
||||
- name: Rename binary
|
||||
run: mv zig-out/bin/lightpanda lightpanda-${{ env.ARCH }}-${{ env.OS }}
|
||||
@@ -118,10 +118,10 @@ jobs:
|
||||
arch: ${{env.ARCH}}
|
||||
|
||||
- name: v8 snapshot
|
||||
run: zig build -Dprebuilt_v8_path=v8/libc_v8.a -Doptimize=ReleaseFast snapshot_creator -- src/snapshot.bin
|
||||
run: zig build -Dprebuilt_v8_path=v8/libc_v8.a -Doptimize=fast snapshot_creator -- src/snapshot.bin
|
||||
|
||||
- name: zig build
|
||||
run: zig build -Dsnapshot_path=../../snapshot.bin -Dprebuilt_v8_path=v8/libc_v8.a -Doptimize=ReleaseFast ${{ env.VERSION_FLAG }}
|
||||
run: zig build -Dsnapshot_path=../../snapshot.bin -Dprebuilt_v8_path=v8/libc_v8.a -Doptimize=fast ${{ env.VERSION_FLAG }}
|
||||
|
||||
- name: Rename binary
|
||||
run: mv zig-out/bin/lightpanda lightpanda-${{ env.ARCH }}-${{ env.OS }}
|
||||
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
arch: ${{env.ARCH}}
|
||||
|
||||
- name: zig build release
|
||||
run: zig build -Dwpt_extensions -Dprebuilt_v8_path=v8/libc_v8.a -Doptimize=ReleaseFast -Dcpu=generic
|
||||
run: zig build -Dwpt_extensions -Dprebuilt_v8_path=v8/libc_v8.a -Doptimize=fast -Dcpu=generic
|
||||
|
||||
- name: upload artifact
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
|
||||
@@ -6,7 +6,7 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for how to open a pull request (CLA, dev
|
||||
|
||||
Run `make download-v8` once first: it fetches the prebuilt V8 archive into `.lp-cache/`, which `build.zig` picks up automatically. Without it every build compiles V8 from source (10+ minutes).
|
||||
|
||||
The C and Rust dependencies are built in ReleaseFast whatever `-Doptimize` is, so debug and release builds share them. Pass `ZIGFLAGS=-Ddebug_deps` to step into a dependency with a debugger.
|
||||
The C and Rust dependencies are built with `-Doptimize=fast` whatever `-Doptimize` is, so debug and release builds share them. Pass `ZIGFLAGS=-Ddebug_deps` to step into a dependency with a debugger.
|
||||
|
||||
```bash
|
||||
make test # Run all tests
|
||||
|
||||
+2
-2
@@ -52,12 +52,12 @@ RUN case $TARGETPLATFORM in \
|
||||
mv libc_v8.a v8/libc_v8.a
|
||||
|
||||
# build v8 snapshot
|
||||
RUN zig build -Doptimize=ReleaseFast \
|
||||
RUN zig build -Doptimize=fast \
|
||||
-Dprebuilt_v8_path=v8/libc_v8.a \
|
||||
snapshot_creator -- src/snapshot.bin
|
||||
|
||||
# build release
|
||||
RUN zig build -Doptimize=ReleaseFast \
|
||||
RUN zig build -Doptimize=fast \
|
||||
-Dsnapshot_path=../../snapshot.bin \
|
||||
-Dprebuilt_v8_path=v8/libc_v8.a \
|
||||
-Dorderfile=orderfile/lightpanda.ld
|
||||
|
||||
@@ -77,14 +77,7 @@ help:
|
||||
|
||||
# $(ZIG) commands
|
||||
# ------------
|
||||
.PHONY: build build-v8-snapshot build-dev download-v8 run run-release test bench data end2end clean zig-cache-tmp
|
||||
|
||||
# Zig 0.16.0 doesn't create <global cache>/tmp before fetching .zip deps.
|
||||
# https://codeberg.org/ziglang/zig/issues/31964
|
||||
zig-cache-tmp:
|
||||
@dir=$$($(ZIG) env | sed -n 's/^ *\.global_cache_dir = "\(.*\)",$$/\1/p'); \
|
||||
test -n "$$dir" || { printf "\033[31mCould not read global_cache_dir from '$(ZIG) env'\033[0m\n"; exit 1; }; \
|
||||
mkdir -p "$$dir/tmp"
|
||||
.PHONY: build build-v8-snapshot build-dev download-v8 run run-release test bench data end2end clean
|
||||
|
||||
## Download the prebuilt V8 libraries (skips the 10+ min source build)
|
||||
download-v8:
|
||||
@@ -105,19 +98,19 @@ ifeq ($(OS)_$(ARCH),linux_x86_64)
|
||||
endif
|
||||
|
||||
## Build v8 snapshot
|
||||
build-v8-snapshot: zig-cache-tmp
|
||||
build-v8-snapshot:
|
||||
@printf "\033[36mBuilding v8 snapshot (release safe)...\033[0m\n"
|
||||
@$(ZIG) build $(ZIGFLAGS) -Doptimize=ReleaseFast snapshot_creator -- src/snapshot.bin || (printf "\033[31mBuild ERROR\033[0m\n"; exit 1;)
|
||||
@$(ZIG) build $(ZIGFLAGS) -Doptimize=fast snapshot_creator -- src/snapshot.bin || (printf "\033[31mBuild ERROR\033[0m\n"; exit 1;)
|
||||
@printf "\033[32mBuild OK\033[0m\n"
|
||||
|
||||
## Build in release-fast mode
|
||||
build: build-v8-snapshot
|
||||
@printf "\033[36mBuilding (release fast)...\033[0m\n"
|
||||
@$(ZIG) build $(ZIGFLAGS) -Doptimize=ReleaseFast -Dsnapshot_path=../../snapshot.bin || (printf "\033[31mBuild ERROR\033[0m\n"; exit 1;)
|
||||
@$(ZIG) build $(ZIGFLAGS) -Doptimize=fast -Dsnapshot_path=../../snapshot.bin || (printf "\033[31mBuild ERROR\033[0m\n"; exit 1;)
|
||||
@printf "\033[32mBuild OK\033[0m\n"
|
||||
|
||||
## Build in debug mode
|
||||
build-dev: zig-cache-tmp
|
||||
build-dev:
|
||||
@printf "\033[36mBuilding (debug)...\033[0m\n"
|
||||
@$(ZIG) build $(ZIGFLAGS) || (printf "\033[31mBuild ERROR\033[0m\n"; exit 1;)
|
||||
@printf "\033[32mBuild OK\033[0m\n"
|
||||
@@ -132,7 +125,7 @@ run-debug: build-dev
|
||||
@printf "\033[36mRunning...\033[0m\n"
|
||||
@./zig-out/bin/lightpanda || (printf "\033[31mRun ERROR\033[0m\n"; exit 1;)
|
||||
|
||||
test: zig-cache-tmp
|
||||
test:
|
||||
TEST_FILTER="$(or $(F),$(TEST_FILTER))" $(ZIG) build $(ZIGFLAGS) test -freference-trace
|
||||
|
||||
## Run demo/runner end to end tests
|
||||
|
||||
@@ -458,7 +458,7 @@ zig build -Dwpt_extensions run -- fetch \
|
||||
it's useful to build in `releaseFast` mode to make tests faster.
|
||||
|
||||
```
|
||||
zig build -Dwpt_extensions -Doptimize=ReleaseFast run -- serve ...
|
||||
zig build -Dwpt_extensions -Doptimize=fast run -- serve ...
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const Translator = @import("translate_c").Translator;
|
||||
|
||||
const lightpanda_version = std.SemanticVersion.parse(@import("build.zig.zon").version) catch unreachable;
|
||||
const min_zig_version = std.SemanticVersion.parse(@import("build.zig.zon").minimum_zig_version) catch unreachable;
|
||||
@@ -44,18 +45,18 @@ pub fn build(b: *Build) !void {
|
||||
const prebuilt_v8_path_option = b.option([]const u8, "prebuilt_v8_path", "Path to a prebuilt libc_v8.a or libc_v8.so");
|
||||
|
||||
const dev_fast = b.option(bool, "dev_fast", "Linux debug builds: shared V8 + self-hosted backend. Implies -Dshared_v8, -Duse_llvm=false and a bundled-CRT target") orelse
|
||||
(builtin.os.tag == .linux and builtin.cpu.arch == .x86_64 and
|
||||
optimize == .Debug and requested_target.query.isNative() and
|
||||
(builtin.target.os.tag == .linux and builtin.target.cpu.arch == .x86_64 and
|
||||
optimize == .debug and requested_target.query.isNative() and
|
||||
!enable_tsan and !enable_asan and
|
||||
(prebuilt_v8_path_option == null or std.mem.endsWith(u8, prebuilt_v8_path_option.?, ".so")));
|
||||
|
||||
if (dev_fast) {
|
||||
if (builtin.os.tag != .linux) {
|
||||
std.debug.print("-Ddev_fast is Linux-only (host is {s})\n", .{@tagName(builtin.os.tag)});
|
||||
if (builtin.target.os.tag != .linux) {
|
||||
std.debug.print("-Ddev_fast is Linux-only (host is {s})\n", .{@tagName(builtin.target.os.tag)});
|
||||
return error.DevFastUnsupportedHost;
|
||||
}
|
||||
if (optimize != .Debug) {
|
||||
std.debug.print("-Ddev_fast is Debug-only (optimize is {s})\n", .{@tagName(optimize)});
|
||||
if (optimize != .debug) {
|
||||
std.debug.print("-Ddev_fast is debug-only (optimize is {s})\n", .{@tagName(optimize)});
|
||||
return error.DevFastRequiresDebug;
|
||||
}
|
||||
if (!requested_target.query.isNative()) {
|
||||
@@ -75,10 +76,10 @@ pub fn build(b: *Build) !void {
|
||||
// Dependencies never follow -Doptimize, and they build for the requested
|
||||
// target rather than the dev_fast bundled-CRT query, so debug and release
|
||||
// builds share one set of dependency objects in the cache.
|
||||
const debug_deps = b.option(bool, "debug_deps", "Build the C and Rust dependencies in Debug instead of ReleaseFast") orelse false;
|
||||
const debug_deps = b.option(bool, "debug_deps", "Build the C and Rust dependencies in debug instead of fast") orelse false;
|
||||
const deps: Deps = .{
|
||||
.target = requested_target,
|
||||
.optimize = if (debug_deps) .Debug else .ReleaseFast,
|
||||
.optimize = if (debug_deps) .debug else .fast,
|
||||
};
|
||||
|
||||
// Without an explicit -Dprebuilt_v8_path, pick up whatever `make
|
||||
@@ -118,7 +119,7 @@ pub fn build(b: *Build) !void {
|
||||
|
||||
const fmt_step = b.step("fmt", "Check code formatting");
|
||||
const fmt = b.addFmt(.{
|
||||
.paths = &.{ "src", "build.zig", "build.zig.zon" },
|
||||
.paths = b.pathList(&.{ "src", "build.zig", "build.zig.zon" }),
|
||||
.check = true,
|
||||
});
|
||||
fmt_step.dependOn(&fmt.step);
|
||||
@@ -167,9 +168,7 @@ pub fn build(b: *Build) !void {
|
||||
b.installArtifact(exe);
|
||||
|
||||
const run_cmd = b.addRunArtifact(exe);
|
||||
if (b.args) |args| {
|
||||
run_cmd.addArgs(args);
|
||||
}
|
||||
run_cmd.addPassthruArgs();
|
||||
const run_step = b.step("run", "Run the app");
|
||||
run_step.dependOn(&run_cmd.step);
|
||||
|
||||
@@ -185,9 +184,7 @@ pub fn build(b: *Build) !void {
|
||||
extras_step.dependOn(&b.addInstallArtifact(exe, .{}).step);
|
||||
|
||||
const run_cmd = b.addRunArtifact(exe);
|
||||
if (b.args) |args| {
|
||||
run_cmd.addArgs(args);
|
||||
}
|
||||
run_cmd.addPassthruArgs();
|
||||
const run_step = b.step("snapshot_creator", "Generate a v8 snapshot");
|
||||
run_step.dependOn(&run_cmd.step);
|
||||
}
|
||||
@@ -197,7 +194,7 @@ pub fn build(b: *Build) !void {
|
||||
const exe = addExe(b, exe_config, "lightpanda-skills", "skills_check", "src/main_skills.zig");
|
||||
|
||||
const run_cmd = b.addRunArtifact(exe);
|
||||
const out_dir = run_cmd.addOutputDirectoryArg("skills");
|
||||
const out_dir = run_cmd.addOutputDirectoryArg2("skills", .{});
|
||||
const install = b.addInstallDirectory(.{
|
||||
.source_dir = out_dir,
|
||||
.install_dir = .prefix,
|
||||
@@ -222,14 +219,14 @@ pub fn build(b: *Build) !void {
|
||||
|
||||
const Deps = struct {
|
||||
target: Build.ResolvedTarget,
|
||||
optimize: std.builtin.OptimizeMode,
|
||||
optimize: std.lang.Optimize,
|
||||
};
|
||||
|
||||
const ExeConfig = struct {
|
||||
check: *Build.Step,
|
||||
lightpanda_module: *Build.Module,
|
||||
target: Build.ResolvedTarget,
|
||||
optimize: std.builtin.OptimizeMode,
|
||||
optimize: std.lang.Optimize,
|
||||
use_llvm: bool,
|
||||
orderfile: ?[]const u8,
|
||||
sanitize_c: ?std.zig.SanitizeC,
|
||||
@@ -255,7 +252,7 @@ fn addExe(b: *Build, config: ExeConfig, name: []const u8, check_name: []const u8
|
||||
if (config.orderfile) |path| {
|
||||
// Per-function/per-datum sections exist only so the orderfile script
|
||||
// can place individual hot functions; the self-hosted backend used by
|
||||
// Debug builds does not support them on the C libraries, so they are
|
||||
// debug builds does not support them on the C libraries, so they are
|
||||
// gated on the orderfile being set (release/LLVM only).
|
||||
exe.link_function_sections = true;
|
||||
exe.link_data_sections = true;
|
||||
@@ -282,9 +279,11 @@ fn devFastGlibcVersion(b: *Build) std.SemanticVersion {
|
||||
/// it cannot drift from CI (the Makefile reads the same source of truth).
|
||||
fn findPrebuiltV8(b: *Build, target: Build.ResolvedTarget, dev_fast: bool) ?[]const u8 {
|
||||
const io = b.graph.io;
|
||||
const action_path = ".github/actions/install/action.yml";
|
||||
b.dependOnFileContents(b.path(action_path));
|
||||
const action = std.Io.Dir.cwd().readFileAlloc(
|
||||
io,
|
||||
b.pathFromRoot(".github/actions/install/action.yml"),
|
||||
rootPath(b, action_path),
|
||||
b.allocator,
|
||||
.limited(64 * 1024),
|
||||
) catch return null;
|
||||
@@ -294,7 +293,7 @@ fn findPrebuiltV8(b: *Build, target: Build.ResolvedTarget, dev_fast: bool) ?[]co
|
||||
return null;
|
||||
}
|
||||
|
||||
const cache_dir = b.pathFromRoot(".lp-cache");
|
||||
const cache_dir = ".lp-cache";
|
||||
// The .so must keep the name the exe's DT_NEEDED records; the archive
|
||||
// name encodes V8 version, os and arch.
|
||||
const path = if (dev_fast)
|
||||
@@ -307,7 +306,8 @@ fn findPrebuiltV8(b: *Build, target: Build.ResolvedTarget, dev_fast: bool) ?[]co
|
||||
@tagName(target.result.cpu.arch),
|
||||
}) });
|
||||
};
|
||||
std.Io.Dir.cwd().access(io, path, .{}) catch {
|
||||
b.dependOnFileMetadata(b.path(path));
|
||||
std.Io.Dir.cwd().access(io, rootPath(b, path), .{}) catch {
|
||||
std.debug.print("No prebuilt V8 at {s}; using the V8 source-build path. `make download-v8` fetches the prebuilt.\n", .{path});
|
||||
return null;
|
||||
};
|
||||
@@ -315,6 +315,10 @@ fn findPrebuiltV8(b: *Build, target: Build.ResolvedTarget, dev_fast: bool) ?[]co
|
||||
return path;
|
||||
}
|
||||
|
||||
fn rootPath(b: *Build, sub_path: []const u8) []const u8 {
|
||||
return b.root.joinString(b.allocator, sub_path) catch @panic("OOM");
|
||||
}
|
||||
|
||||
/// Returns the quoted `default:` value of a top-level `key` in the install
|
||||
/// action's yaml.
|
||||
fn actionDefault(action: []const u8, key: []const u8) ?[]const u8 {
|
||||
@@ -346,18 +350,18 @@ fn markHotSections(b: *Build, archive: Build.LazyPath) Build.LazyPath {
|
||||
.root_module = b.createModule(.{
|
||||
.root_source_file = b.path("orderfile/mark_hot_sections.zig"),
|
||||
.target = b.graph.host,
|
||||
.optimize = .ReleaseSafe,
|
||||
.optimize = .safe,
|
||||
}),
|
||||
});
|
||||
const run = b.addRunArtifact(tool);
|
||||
run.addFileArg(archive);
|
||||
run.addFileArg(b.path("orderfile/v8.txt"));
|
||||
return run.addOutputFileArg("libc_v8.a");
|
||||
return run.addOutputFileArg2("libc_v8.a", .{});
|
||||
}
|
||||
|
||||
/// Per-function/per-datum sections let the -Dorderfile linker script place
|
||||
/// individual hot functions. Only enabled for orderfile (release/LLVM) builds:
|
||||
/// the self-hosted backend used by Debug builds fails to link the C libraries
|
||||
/// the self-hosted backend used by debug builds fails to link the C libraries
|
||||
/// with them.
|
||||
fn sectionize(lib: *Build.Step.Compile, enabled: bool) *Build.Step.Compile {
|
||||
if (enabled) {
|
||||
@@ -384,7 +388,7 @@ fn linkV8(
|
||||
.is_tsan = is_tsan,
|
||||
.inspector_subtype = false,
|
||||
.v8_enable_sandbox = is_tsan,
|
||||
.cache_root = b.pathFromRoot(".lp-cache"),
|
||||
.cache_root = rootPath(b, ".lp-cache"),
|
||||
.prebuilt_v8_path = prebuilt_v8_path,
|
||||
.shared_v8 = shared_v8,
|
||||
});
|
||||
@@ -393,7 +397,7 @@ fn linkV8(
|
||||
|
||||
fn linkRust(b: *Build, mod: *Build.Module, deps: Deps) void {
|
||||
// Cargo's "dev" profile writes to target/debug.
|
||||
const profile, const out_subdir = if (deps.optimize == .Debug) .{ "dev", "debug" } else .{ "release", "release" };
|
||||
const profile, const out_subdir = if (deps.optimize == .debug) .{ "dev", "debug" } else .{ "release", "release" };
|
||||
|
||||
// One cargo workspace, one staticlib (src/rust/Cargo.toml explains why).
|
||||
const exec_cargo = b.addSystemCommand(&.{
|
||||
@@ -412,7 +416,7 @@ fn linkRust(b: *Build, mod: *Build.Module, deps: Deps) void {
|
||||
_ = exec_cargo.captureStdErr(.{});
|
||||
|
||||
// TODO: We can prefer `--artifact-dir` once it become stable.
|
||||
const out_dir = exec_cargo.addPrefixedOutputDirectoryArg("--target-dir=", "rust");
|
||||
const out_dir = exec_cargo.addOutputDirectoryArg2("rust", .{ .prefix = "--target-dir=" });
|
||||
|
||||
const rust_step = b.step("rust", "Build the Rust staticlib (requires cargo)");
|
||||
rust_step.dependOn(&exec_cargo.step);
|
||||
@@ -425,14 +429,18 @@ fn linkRust(b: *Build, mod: *Build.Module, deps: Deps) void {
|
||||
/// input of `run`, skipping the `skip_dir` subtree at any depth.
|
||||
fn addDirInputs(b: *Build, run: *Build.Step.Run, root: []const u8, skip_dir: []const u8) !void {
|
||||
const io = b.graph.io;
|
||||
var dir = try b.build_root.handle.openDir(io, root, .{ .iterate = true });
|
||||
var dir = try std.Io.Dir.cwd().openDir(io, rootPath(b, root), .{ .iterate = true });
|
||||
defer dir.close(io);
|
||||
|
||||
b.dependOnDirectoryContents(b.path(root));
|
||||
var walker = try dir.walk(b.allocator);
|
||||
defer walker.deinit();
|
||||
while (try walker.next(io)) |entry| {
|
||||
switch (entry.kind) {
|
||||
.directory => if (std.mem.eql(u8, entry.basename, skip_dir)) walker.leave(io),
|
||||
.directory => if (std.mem.eql(u8, entry.basename, skip_dir))
|
||||
walker.leave(io)
|
||||
else
|
||||
b.dependOnDirectoryContents(b.path(b.pathJoin(&.{ root, entry.path }))),
|
||||
.file => run.addFileInput(b.path(b.pathJoin(&.{ root, entry.path }))),
|
||||
else => {},
|
||||
}
|
||||
@@ -440,14 +448,12 @@ fn addDirInputs(b: *Build, run: *Build.Step.Run, root: []const u8, skip_dir: []c
|
||||
}
|
||||
|
||||
fn linkSqlite(b: *Build, mod: *Build.Module, deps: Deps, enable_csan: ?std.zig.SanitizeC, is_tsan: bool, section: bool) void {
|
||||
const dep = b.dependency("sqlite3", .{
|
||||
.target = deps.target,
|
||||
.optimize = deps.optimize,
|
||||
});
|
||||
const dep = b.dependency("sqlite3", .{});
|
||||
|
||||
const lib = sectionize(dep.artifact("sqlite3"), section);
|
||||
lib.root_module.sanitize_c = enable_csan;
|
||||
lib.root_module.sanitize_thread = is_tsan;
|
||||
const lib_mod = cLibModule(b, deps.target, deps.optimize, is_tsan);
|
||||
lib_mod.sanitize_c = enable_csan;
|
||||
lib_mod.addCSourceFile(.{ .file = dep.path("sqlite3.c") });
|
||||
const lib = sectionize(b.addLibrary(.{ .name = "sqlite3", .root_module = lib_mod }), section);
|
||||
|
||||
const macros = [_]struct { []const u8, []const u8 }{
|
||||
.{ "SQLITE_DEFAULT_FILE_PERMISSIONS", "0600" },
|
||||
@@ -489,12 +495,7 @@ fn linkSqlite(b: *Build, mod: *Build.Module, deps: Deps, enable_csan: ?std.zig.S
|
||||
|
||||
mod.linkLibrary(lib);
|
||||
|
||||
const translate_c = b.addTranslateC(.{
|
||||
.root_source_file = lib.getEmittedIncludeTree().path(b, "sqlite3.h"),
|
||||
.target = mod.resolved_target.?,
|
||||
.optimize = mod.optimize.?,
|
||||
});
|
||||
mod.addImport("sqlite3", translate_c.createModule());
|
||||
mod.addImport("sqlite3", translateC(b, mod, dep.path("sqlite3.h")).mod);
|
||||
}
|
||||
|
||||
fn linkPcre2(b: *Build, mod: *Build.Module, deps: Deps, enable_csan: ?std.zig.SanitizeC, is_tsan: bool, section: bool) void {
|
||||
@@ -509,13 +510,9 @@ fn linkPcre2(b: *Build, mod: *Build.Module, deps: Deps, enable_csan: ?std.zig.Sa
|
||||
lib.root_module.sanitize_thread = is_tsan;
|
||||
mod.linkLibrary(lib);
|
||||
|
||||
const translate_c = b.addTranslateC(.{
|
||||
.root_source_file = lib.getEmittedIncludeTree().path(b, "pcre2.h"),
|
||||
.target = mod.resolved_target.?,
|
||||
.optimize = mod.optimize.?,
|
||||
});
|
||||
translate_c.defineCMacro("PCRE2_CODE_UNIT_WIDTH", "8");
|
||||
mod.addImport("pcre2", translate_c.createModule());
|
||||
const translator = translateC(b, mod, lib.getEmittedIncludeTree().path(b, "pcre2.h"));
|
||||
translator.defineCMacro("PCRE2_CODE_UNIT_WIDTH", "8");
|
||||
mod.addImport("pcre2", translator.mod);
|
||||
}
|
||||
|
||||
fn linkCurl(b: *Build, mod: *Build.Module, deps: Deps, is_tsan: bool, section: bool) void {
|
||||
@@ -523,13 +520,9 @@ fn linkCurl(b: *Build, mod: *Build.Module, deps: Deps, is_tsan: bool, section: b
|
||||
mod.linkLibrary(curl);
|
||||
|
||||
const dep = b.dependency("curl", .{});
|
||||
const translate_c = b.addTranslateC(.{
|
||||
.root_source_file = dep.path("include/curl/curl.h"),
|
||||
.target = mod.resolved_target.?,
|
||||
.optimize = mod.optimize.?,
|
||||
});
|
||||
translate_c.addIncludePath(dep.path("include"));
|
||||
mod.addImport("curl", translate_c.createModule());
|
||||
const translator = translateC(b, mod, dep.path("include/curl/curl.h"));
|
||||
translator.addIncludePath(dep.path("include"));
|
||||
mod.addImport("curl", translator.mod);
|
||||
|
||||
const zlib = buildZlib(b, deps.target, deps.optimize, is_tsan, section);
|
||||
curl.root_module.linkLibrary(zlib);
|
||||
@@ -545,9 +538,7 @@ fn linkCurl(b: *Build, mod: *Build.Module, deps: Deps, is_tsan: bool, section: b
|
||||
|
||||
if (deps.target.result.os.tag == .macos) {
|
||||
// needed for proxying on mac
|
||||
const framework_path = if (b.sysroot) |sysroot|
|
||||
b.pathJoin(&.{ sysroot, "System/Library/Frameworks" })
|
||||
else if (b.graph.environ_map.get("SDKROOT")) |sdk_root|
|
||||
const framework_path = if (b.graph.environ_map.get("SDKROOT")) |sdk_root|
|
||||
b.pathJoin(&.{ sdk_root, "System/Library/Frameworks" })
|
||||
else
|
||||
"/System/Library/Frameworks";
|
||||
@@ -557,7 +548,7 @@ fn linkCurl(b: *Build, mod: *Build.Module, deps: Deps, is_tsan: bool, section: b
|
||||
}
|
||||
}
|
||||
|
||||
fn cLibModule(b: *Build, target: Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, is_tsan: bool) *Build.Module {
|
||||
fn cLibModule(b: *Build, target: Build.ResolvedTarget, optimize: std.lang.Optimize, is_tsan: bool) *Build.Module {
|
||||
return b.createModule(.{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
@@ -566,7 +557,7 @@ fn cLibModule(b: *Build, target: Build.ResolvedTarget, optimize: std.builtin.Opt
|
||||
});
|
||||
}
|
||||
|
||||
fn buildZlib(b: *Build, target: Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, is_tsan: bool, section: bool) *Build.Step.Compile {
|
||||
fn buildZlib(b: *Build, target: Build.ResolvedTarget, optimize: std.lang.Optimize, is_tsan: bool, section: bool) *Build.Step.Compile {
|
||||
const dep = b.dependency("zlib", .{});
|
||||
|
||||
const mod = cLibModule(b, target, optimize, is_tsan);
|
||||
@@ -592,7 +583,7 @@ fn buildZlib(b: *Build, target: Build.ResolvedTarget, optimize: std.builtin.Opti
|
||||
return lib;
|
||||
}
|
||||
|
||||
fn buildBrotli(b: *Build, target: Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, is_tsan: bool, section: bool) [3]*Build.Step.Compile {
|
||||
fn buildBrotli(b: *Build, target: Build.ResolvedTarget, optimize: std.lang.Optimize, is_tsan: bool, section: bool) [3]*Build.Step.Compile {
|
||||
const dep = b.dependency("brotli", .{});
|
||||
|
||||
const mod = cLibModule(b, target, optimize, is_tsan);
|
||||
@@ -634,7 +625,7 @@ fn buildBrotli(b: *Build, target: Build.ResolvedTarget, optimize: std.builtin.Op
|
||||
return .{ brotlicmn, brotlidec, brotlienc };
|
||||
}
|
||||
|
||||
fn buildBoringSsl(b: *Build, target: Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, section: bool) [2]*Build.Step.Compile {
|
||||
fn buildBoringSsl(b: *Build, target: Build.ResolvedTarget, optimize: std.lang.Optimize, section: bool) [2]*Build.Step.Compile {
|
||||
const dep = b.dependency("boringssl-zig", .{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
@@ -650,7 +641,7 @@ fn buildBoringSsl(b: *Build, target: Build.ResolvedTarget, optimize: std.builtin
|
||||
return .{ ssl, crypto };
|
||||
}
|
||||
|
||||
fn buildNghttp2(b: *Build, target: Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, is_tsan: bool, section: bool) *Build.Step.Compile {
|
||||
fn buildNghttp2(b: *Build, target: Build.ResolvedTarget, optimize: std.lang.Optimize, is_tsan: bool, section: bool) *Build.Step.Compile {
|
||||
const dep = b.dependency("nghttp2", .{});
|
||||
|
||||
const mod = cLibModule(b, target, optimize, is_tsan);
|
||||
@@ -696,7 +687,7 @@ fn buildNghttp2(b: *Build, target: Build.ResolvedTarget, optimize: std.builtin.O
|
||||
fn buildCurl(
|
||||
b: *Build,
|
||||
target: Build.ResolvedTarget,
|
||||
optimize: std.builtin.OptimizeMode,
|
||||
optimize: std.lang.Optimize,
|
||||
is_tsan: bool,
|
||||
section: bool,
|
||||
) *Build.Step.Compile {
|
||||
@@ -721,7 +712,7 @@ fn buildCurl(
|
||||
|
||||
const byte_size = struct {
|
||||
fn it(b2: *std.Build, target2: Build.ResolvedTarget, name: []const u8, comptime ctype: std.Target.CType) []const u8 {
|
||||
return b2.fmt("#define SIZEOF_{s} {d}", .{ name, target2.result.cTypeByteSize(ctype) });
|
||||
return b2.fmt("#define SIZEOF_{s} {d}", .{ name, target2.result.cTypeByteSize(ctype).? });
|
||||
}
|
||||
}.it;
|
||||
|
||||
@@ -731,7 +722,6 @@ fn buildCurl(
|
||||
.USE_NGHTTP2 = true,
|
||||
|
||||
.USE_OPENSSL = true,
|
||||
.OPENSSL_IS_BORINGSSL = true,
|
||||
.CURL_BORINGSSL_VERSION = null,
|
||||
.CURL_CA_PATH = null,
|
||||
.CURL_CA_BUNDLE = null,
|
||||
@@ -751,11 +741,9 @@ fn buildCurl(
|
||||
.CURL_DISABLE_LDAP = true,
|
||||
.CURL_DISABLE_LDAPS = true,
|
||||
.CURL_DISABLE_MQTT = true,
|
||||
.CURL_DISABLE_NTLM = true,
|
||||
.CURL_DISABLE_PROGRESS_METER = true,
|
||||
.CURL_DISABLE_POP3 = true,
|
||||
.CURL_DISABLE_RTSP = true,
|
||||
.CURL_DISABLE_SMB = true,
|
||||
.CURL_DISABLE_SMTP = true,
|
||||
.CURL_DISABLE_TELNET = true,
|
||||
.CURL_DISABLE_TFTP = true,
|
||||
@@ -777,7 +765,6 @@ fn buildCurl(
|
||||
|
||||
.SIZEOF_INT_CODE = byte_size(b, target, "INT", .int),
|
||||
.SIZEOF_LONG_CODE = byte_size(b, target, "LONG", .long),
|
||||
.SIZEOF_LONG_LONG_CODE = byte_size(b, target, "LONG_LONG", .longlong),
|
||||
|
||||
.SIZEOF_OFF_T_CODE = byte_size(b, target, "OFF_T", .longlong),
|
||||
.SIZEOF_CURL_OFF_T_CODE = byte_size(b, target, "CURL_OFF_T", .longlong),
|
||||
@@ -805,8 +792,6 @@ fn buildCurl(
|
||||
.HAVE_PWD_H = !is_windows,
|
||||
.HAVE_STDATOMIC_H = true,
|
||||
.HAVE_STDBOOL_H = true,
|
||||
.HAVE_STDDEF_H = true,
|
||||
.HAVE_STDINT_H = true,
|
||||
.HAVE_STRINGS_H = true,
|
||||
.HAVE_STROPTS_H = false,
|
||||
.HAVE_SYS_EVENTFD_H = is_linux or is_freebsd or is_netbsd,
|
||||
@@ -835,18 +820,15 @@ fn buildCurl(
|
||||
.HAVE_BUILTIN_AVAILABLE = true,
|
||||
.HAVE_CLOCK_GETTIME_MONOTONIC = !is_darwin and !is_windows,
|
||||
.HAVE_CLOCK_GETTIME_MONOTONIC_RAW = is_linux,
|
||||
.HAVE_FILE_OFFSET_BITS = true,
|
||||
.HAVE_GETEUID = !is_windows,
|
||||
.HAVE_GETPPID = !is_windows,
|
||||
.HAVE_GETTIMEOFDAY = true,
|
||||
.HAVE_GLIBC_STRERROR_R = is_gnu,
|
||||
.HAVE_GMTIME_R = !is_windows,
|
||||
.HAVE_LOCALTIME_R = !is_windows,
|
||||
.HAVE_LONGLONG = !is_windows,
|
||||
.HAVE_MACH_ABSOLUTE_TIME = is_darwin,
|
||||
.HAVE_MEMRCHR = !is_darwin and !is_windows,
|
||||
.HAVE_POSIX_STRERROR_R = !is_gnu and !is_windows,
|
||||
.HAVE_PTHREAD_H = !is_windows,
|
||||
.HAVE_THREADS_POSIX = !is_windows,
|
||||
.HAVE_SETLOCALE = true,
|
||||
.HAVE_SETRLIMIT = !is_windows,
|
||||
@@ -854,12 +836,8 @@ fn buildCurl(
|
||||
.HAVE_SIGINTERRUPT = !is_windows,
|
||||
.HAVE_SIGNAL = true,
|
||||
.HAVE_SIGSETJMP = !is_windows,
|
||||
.HAVE_SIZEOF_SA_FAMILY_T = false,
|
||||
.HAVE_SIZEOF_SUSECONDS_T = false,
|
||||
.HAVE_SNPRINTF = true,
|
||||
.HAVE_STRCASECMP = !is_windows,
|
||||
.HAVE_STRCMPI = false,
|
||||
.HAVE_STRDUP = true,
|
||||
.HAVE_STRERROR_R = !is_windows,
|
||||
.HAVE_STRICMP = false,
|
||||
.HAVE_STRUCT_TIMEVAL = true,
|
||||
@@ -867,8 +845,6 @@ fn buildCurl(
|
||||
.HAVE_UTIME = true,
|
||||
.HAVE_UTIMES = !is_windows,
|
||||
.HAVE_WRITABLE_ARGV = !is_windows,
|
||||
.HAVE__SETMODE = is_windows,
|
||||
.USE_THREADS_POSIX = !is_windows,
|
||||
.USE_RESOLV_THREADED = !is_windows,
|
||||
|
||||
// filesystem, network
|
||||
@@ -885,16 +861,12 @@ fn buildCurl(
|
||||
.HAVE_FSETXATTR = is_darwin or is_linux or is_netbsd,
|
||||
.HAVE_FSETXATTR_5 = is_linux or is_netbsd,
|
||||
.HAVE_FSETXATTR_6 = is_darwin,
|
||||
.HAVE_FTRUNCATE = true,
|
||||
.HAVE_GETADDRINFO = true,
|
||||
.HAVE_GETADDRINFO_THREADSAFE = is_linux or is_freebsd or is_netbsd,
|
||||
.HAVE_GETHOSTBYNAME_R = is_linux or is_freebsd,
|
||||
.HAVE_GETHOSTBYNAME_R_3 = false,
|
||||
.HAVE_GETHOSTBYNAME_R_3_REENTRANT = false,
|
||||
.HAVE_GETHOSTBYNAME_R_5 = false,
|
||||
.HAVE_GETHOSTBYNAME_R_5_REENTRANT = false,
|
||||
.HAVE_GETHOSTBYNAME_R_6 = is_linux,
|
||||
.HAVE_GETHOSTBYNAME_R_6_REENTRANT = is_linux,
|
||||
.HAVE_GETHOSTNAME = true,
|
||||
.HAVE_GETIFADDRS = if (is_windows) false else !is_android or target.result.os.versionRange().linux.android >= 24,
|
||||
.HAVE_GETPASS_R = is_netbsd,
|
||||
@@ -910,7 +882,6 @@ fn buildCurl(
|
||||
.HAVE_IOCTLSOCKET_FIONBIO = is_windows,
|
||||
.HAVE_IOCTL_FIONBIO = !is_windows,
|
||||
.HAVE_IOCTL_SIOCGIFADDR = !is_windows,
|
||||
.HAVE_MSG_NOSIGNAL = !is_windows,
|
||||
.HAVE_OPENDIR = true,
|
||||
.HAVE_PIPE = !is_windows,
|
||||
.HAVE_PIPE2 = is_linux or is_freebsd or is_netbsd or is_openbsd,
|
||||
@@ -922,9 +893,7 @@ fn buildCurl(
|
||||
.HAVE_SEND = true,
|
||||
.HAVE_SENDMMSG = !is_darwin and !is_windows,
|
||||
.HAVE_SENDMSG = !is_windows,
|
||||
.HAVE_SETMODE = !is_linux,
|
||||
.HAVE_SETSOCKOPT_SO_NONBLOCK = false,
|
||||
.HAVE_SOCKADDR_IN6_SIN6_ADDR = !is_windows,
|
||||
.HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID = true,
|
||||
.HAVE_SOCKET = true,
|
||||
.HAVE_SOCKETPAIR = !is_windows,
|
||||
@@ -1022,12 +991,17 @@ fn linkIsocline(b: *Build, mod: *Build.Module) void {
|
||||
.file = dep.path("src/isocline.c"),
|
||||
});
|
||||
|
||||
const translate_c = b.addTranslateC(.{
|
||||
.root_source_file = dep.path("include/isocline.h"),
|
||||
mod.addImport("isocline", translateC(b, mod, dep.path("include/isocline.h")).mod);
|
||||
}
|
||||
|
||||
fn translateC(b: *Build, mod: *Build.Module, header: Build.LazyPath) Translator {
|
||||
return .init(b.dependency("translate_c", .{}), .{
|
||||
.c_source_file = header,
|
||||
.target = mod.resolved_target.?,
|
||||
.optimize = mod.optimize.?,
|
||||
// Zig 0.16's built-in translate-c defaulted to this.
|
||||
.default_init = true,
|
||||
});
|
||||
mod.addImport("isocline", translate_c.createModule());
|
||||
}
|
||||
|
||||
/// Resolves the semantic version of the build.
|
||||
@@ -1072,10 +1046,14 @@ fn resolveVersion(b: *std.Build) std.SemanticVersion {
|
||||
}
|
||||
|
||||
fn runGit(b: *std.Build, args: []const []const u8) ![]const u8 {
|
||||
var code: u8 = undefined;
|
||||
// HEAD moves without touching any file the cache could track cheaply.
|
||||
b.graph.poisonCache();
|
||||
const command = try std.mem.concat(b.allocator, []const u8, &.{
|
||||
&.{ "git", "-C", b.pathFromRoot(".") },
|
||||
&.{ "git", "-C", rootPath(b, ".") },
|
||||
args,
|
||||
});
|
||||
return b.runAllowFail(command, &code, .ignore);
|
||||
return switch (b.runFallible(command, .{ .stderr_behavior = .ignore })) {
|
||||
.success => |stdout| stdout,
|
||||
else => error.GitFailed,
|
||||
};
|
||||
}
|
||||
+13
-9
@@ -2,11 +2,11 @@
|
||||
.name = .browser,
|
||||
.version = "1.1.0-dev",
|
||||
.fingerprint = 0xda130f3af836cea0, // Changing this has security and trust implications.
|
||||
.minimum_zig_version = "0.16.0",
|
||||
.minimum_zig_version = "0.17.0",
|
||||
.dependencies = .{
|
||||
.v8 = .{
|
||||
.url = "https://github.com/lightpanda-io/zig-v8-fork/archive/200123d4a5eee5136aa96a3933c651cc3d2c069f.tar.gz",
|
||||
.hash = "v8-0.0.0-xddH67dJAwAdG6Puk7KzLsWsEzP8kqxLDfS-6tpkKS5B",
|
||||
.url = "https://github.com/lightpanda-io/zig-v8-fork/archive/10f6a11e81fd4809988a24e3f5b3d5d4fd3a73fe.tar.gz",
|
||||
.hash = "v8-0.0.0-xddH6w1QAwDcuJPtc73VXElNBsgPgrRBqQR__jWhy_C4",
|
||||
},
|
||||
// .v8 = .{ .path = "../zig-v8-fork" },
|
||||
.brotli = .{
|
||||
@@ -32,20 +32,24 @@
|
||||
.hash = "N-V-__8AALJXUwHr71AwttzhEqqYTvFb_jz0EQ5Ou3OWpHBM",
|
||||
},
|
||||
.sqlite3 = .{
|
||||
.url = "https://github.com/allyourcodebase/sqlite3/archive/7a615f5af79009cd733e3480658586d9b0d28b35.tar.gz",
|
||||
.hash = "sqlite3-3.53.2-DMxLWuAOAAA_Px0arJOIOaP4AKEu5prbsQgPMA35W1zz",
|
||||
.url = "https://sqlite.org/2026/sqlite-amalgamation-3530200.zip",
|
||||
.hash = "N-V-__8AALc_rgC04POe18O0LKFRm4ouQpLtL3riscEmWp-Q",
|
||||
},
|
||||
.zenai = .{
|
||||
.url = "git+https://github.com/lightpanda-io/zenai.git#b3386fde741d3d9f76674e4706ac1db27923c855",
|
||||
.hash = "zenai-0.0.0-iOY_VJEhBwBj9qGuHOtw1TdQw0aiIbOZhXlybkSqhXKs",
|
||||
.url = "git+https://github.com/lightpanda-io/zenai.git#63df800afc438c0e90603270a4696689eb339ccc",
|
||||
.hash = "zenai-0.0.0-iOY_VEuBBwAanO_h2hbjC9Up37-a4pjYlViKeOYJLQjS",
|
||||
},
|
||||
.isocline = .{
|
||||
.url = "git+https://github.com/arrufat/isocline#4a99434bee4a5ed04c1639514224d48cd55e1405",
|
||||
.hash = "N-V-__8AAHxtEwB16xj2Xz-zx_uklGdTP5C2-GHXDoSzah-8",
|
||||
},
|
||||
.pcre2 = .{
|
||||
.url = "https://github.com/PCRE2Project/pcre2/releases/download/pcre2-10.49/pcre2-10.49.tar.gz",
|
||||
.hash = "pcre2-10.49.0-IZ6r68cregBKN199ndY6AaKNyKJpNmnQVSm8-h0gp4sj",
|
||||
.url = "git+https://github.com/PCRE2Project/pcre2#9ad4a2e956876747a5022bf04614c7e39e71d4ec",
|
||||
.hash = "pcre2-10.50.0-DEV-IZ6r6yDTrgCmI3jcBntPIdZLWLhNORGZZSi8hxQkc11x",
|
||||
},
|
||||
.translate_c = .{
|
||||
.url = "git+https://codeberg.org/ziglang/translate-c?ref=2.0.0#0da7a16c3235b935b82421646076e0657cda21f6",
|
||||
.hash = "translate_c-2.0.0-Q_BUWltOBwA0229IE8wwSxxGzOxyRso3hvcb1nN8oJX_",
|
||||
},
|
||||
},
|
||||
.paths = .{""},
|
||||
|
||||
+1
-1
@@ -59,7 +59,7 @@ below), with no change in run duration.
|
||||
```bash
|
||||
# root for /sys/kernel/debug/fault_around_bytes; ../demo checked out with
|
||||
# `npm install` done; node, go, python3 and binutils on the PATH.
|
||||
orderfile/tools/regen.sh -Doptimize=ReleaseFast -Dsnapshot_path=../../snapshot.bin -Dcpu=x86_64
|
||||
orderfile/tools/regen.sh -Doptimize=fast -Dsnapshot_path=../../snapshot.bin -Dcpu=x86_64
|
||||
```
|
||||
|
||||
The script
|
||||
|
||||
@@ -123,7 +123,7 @@ fn rewriteArchive(gpa: Allocator, archive: []const u8, hot: *const HotSet, out:
|
||||
out.appendSliceAssumeCapacity("!<arch>\n");
|
||||
for (members.items) |m| {
|
||||
var header = m.header.*;
|
||||
_ = try std.fmt.bufPrint(header[48..58], "{d:<10}", .{m.body.len});
|
||||
_ = try std.mem.print(header[48..58], "{d:<10}", .{m.body.len});
|
||||
out.appendSliceAssumeCapacity(&header);
|
||||
const start = out.items.len;
|
||||
out.appendSliceAssumeCapacity(m.body);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#
|
||||
# usage: orderfile/tools/regen.sh [zig build args...]
|
||||
# The build args are those of the release build minus -Dorderfile, e.g.
|
||||
# -Doptimize=ReleaseFast -Dsnapshot_path=../../snapshot.bin -Dcpu=x86_64
|
||||
# -Doptimize=fast -Dsnapshot_path=../../snapshot.bin -Dcpu=x86_64
|
||||
#
|
||||
# Needs root (sudo) for /sys/kernel/debug/fault_around_bytes, a checkout of
|
||||
# lightpanda-io/demo (DEMO_DIR, npm install done), node, go, python3 and
|
||||
|
||||
+2
-2
@@ -109,8 +109,8 @@ pub fn dupe(self: *Arena, comptime T: type, m: []const T) ![]T {
|
||||
return self.allocator().dupe(T, m);
|
||||
}
|
||||
|
||||
pub fn dupeZ(self: *Arena, comptime T: type, m: []const T) ![:0]T {
|
||||
return self.allocator().dupeZ(T, m);
|
||||
pub fn dupeSentinel(self: *Arena, comptime T: type, m: []const T, comptime sentinel: T) ![:sentinel]T {
|
||||
return self.allocator().dupeSentinel(T, m, sentinel);
|
||||
}
|
||||
|
||||
// Arena is being released. Account goes back to 0 (everything is being released)
|
||||
|
||||
+19
-19
@@ -358,7 +358,7 @@ pub const AgentVerbosity = enum {
|
||||
high,
|
||||
|
||||
pub fn atLeast(self: AgentVerbosity, min: AgentVerbosity) bool {
|
||||
return @intFromEnum(self) >= @intFromEnum(min);
|
||||
return @backingInt(self) >= @backingInt(min);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1038,7 +1038,7 @@ pub const HttpHeaders = struct {
|
||||
languages: []const []const u8,
|
||||
|
||||
pub fn init(allocator: Allocator, value: []const u8) !AcceptLanguage {
|
||||
const header = try allocator.dupeZ(u8, value);
|
||||
const header = try allocator.dupeSentinel(u8, value, 0);
|
||||
errdefer allocator.free(header);
|
||||
|
||||
var languages: std.ArrayList([]const u8) = .empty;
|
||||
@@ -1067,15 +1067,15 @@ pub const HttpHeaders = struct {
|
||||
|
||||
pub fn init(allocator: Allocator, config: *const Config) !HttpHeaders {
|
||||
const user_agent: [:0]const u8 = if (config.userAgent()) |ua|
|
||||
try allocator.dupeZ(u8, ua)
|
||||
try allocator.dupeSentinel(u8, ua, 0)
|
||||
else if (config.userAgentSuffix()) |suffix|
|
||||
try std.fmt.allocPrintSentinel(allocator, "{s} {s}", .{ user_agent_base, suffix }, 0)
|
||||
try allocator.printSentinel("{s} {s}", .{ user_agent_base, suffix }, 0)
|
||||
else
|
||||
user_agent_base;
|
||||
errdefer if (config.userAgent() != null or config.userAgentSuffix() != null) allocator.free(user_agent);
|
||||
|
||||
const proxy_bearer_header: ?[:0]const u8 = if (config.proxyBearerToken()) |token|
|
||||
try std.fmt.allocPrintSentinel(allocator, "Proxy-Authorization: Bearer {s}", .{token}, 0)
|
||||
try allocator.printSentinel("Proxy-Authorization: Bearer {s}", .{token}, 0)
|
||||
else
|
||||
null;
|
||||
errdefer if (proxy_bearer_header) |hdr| allocator.free(hdr);
|
||||
@@ -1133,7 +1133,7 @@ pub fn printUsageAndExit(self: *const Config, allocator: Allocator, help_for: Ru
|
||||
\\{s}
|
||||
\\
|
||||
, .{Help.general});
|
||||
break :text try std.fmt.allocPrint(allocator, template, .{exec_name});
|
||||
break :text try allocator.print(template, .{exec_name});
|
||||
},
|
||||
inline .fetch, .serve, .mcp, .agent, .run => |tag| text: {
|
||||
const template = comptimePrint(
|
||||
@@ -1142,11 +1142,11 @@ pub fn printUsageAndExit(self: *const Config, allocator: Allocator, help_for: Ru
|
||||
\\{s}
|
||||
\\
|
||||
, .{ @field(Help, @tagName(tag)), Help.common_options });
|
||||
break :text try std.fmt.allocPrint(allocator, template, .{ exec_name, info_or_warn, pretty_or_logfmt });
|
||||
break :text try allocator.print(template, .{ exec_name, info_or_warn, pretty_or_logfmt });
|
||||
},
|
||||
.version => text: {
|
||||
const template = Help.version ++ "\n";
|
||||
break :text try std.fmt.allocPrint(allocator, template, .{exec_name});
|
||||
break :text try allocator.print(template, .{exec_name});
|
||||
},
|
||||
};
|
||||
defer allocator.free(text);
|
||||
@@ -1228,8 +1228,8 @@ pub fn parseArgs(allocator: Allocator, proc_args: std.process.Args) !Config {
|
||||
}
|
||||
// run's fields are a strict subset of Agent's (compile error otherwise).
|
||||
var agent_opts: Agent = .{};
|
||||
inline for (@typeInfo(@TypeOf(run)).@"struct".fields) |f| {
|
||||
@field(agent_opts, f.name) = @field(run, f.name);
|
||||
inline for (@typeInfo(@TypeOf(run)).@"struct".field_names) |field_name| {
|
||||
@field(agent_opts, field_name) = @field(run, field_name);
|
||||
}
|
||||
command = .{ .agent = agent_opts };
|
||||
}
|
||||
@@ -1428,7 +1428,7 @@ test "Config: validateLocale" {
|
||||
try std.testing.expectError(error.InvalidSubtag, validateLocale("en-U"));
|
||||
try std.testing.expectError(error.InvalidSubtag, validateLocale("en-US-x-toolongsub"));
|
||||
try std.testing.expectError(error.InvalidSubtag, validateLocale("en-U$"));
|
||||
try std.testing.expectError(error.TooLong, validateLocale("en-" ++ "a" ** 40));
|
||||
try std.testing.expectError(error.TooLong, validateLocale("en-" ++ string.repeat("a", 40)));
|
||||
}
|
||||
|
||||
test "Config: validateTimezone" {
|
||||
@@ -1438,7 +1438,7 @@ test "Config: validateTimezone" {
|
||||
try std.testing.expectError(error.Empty, validateTimezone(""));
|
||||
try std.testing.expectError(error.InvalidCharacter, validateTimezone("Europe/ Paris"));
|
||||
try std.testing.expectError(error.InvalidCharacter, validateTimezone("UTC\n"));
|
||||
try std.testing.expectError(error.TooLong, validateTimezone("a" ** 65));
|
||||
try std.testing.expectError(error.TooLong, validateTimezone(string.repeat("a", 65)));
|
||||
}
|
||||
|
||||
test "Config: HttpHeaders.acceptLanguageFor" {
|
||||
@@ -1634,7 +1634,7 @@ pub fn validateUserAgent(ua: []const u8) !void {
|
||||
}
|
||||
}
|
||||
|
||||
if (std.ascii.indexOfIgnoreCase(ua, "mozilla") != null) {
|
||||
if (std.ascii.findIgnoreCase(ua, "mozilla") != null) {
|
||||
return error.Reserved;
|
||||
}
|
||||
}
|
||||
@@ -1645,7 +1645,7 @@ fn localeValidator(allocator: Allocator, args: *std.process.Args.Iterator, field
|
||||
log.fatal(.app, "invalid option value", .{ .arg = "--locale", .value = str, .err = err, .hint = "must be a BCP 47 tag such as en-US, de or zh-Hant-TW" });
|
||||
return error.InvalidArgument;
|
||||
};
|
||||
field.* = try allocator.dupeZ(u8, str);
|
||||
field.* = try allocator.dupeSentinel(u8, str, 0);
|
||||
}
|
||||
|
||||
fn timezoneValidator(allocator: Allocator, args: *std.process.Args.Iterator, field: *?[:0]const u8) !void {
|
||||
@@ -1654,7 +1654,7 @@ fn timezoneValidator(allocator: Allocator, args: *std.process.Args.Iterator, fie
|
||||
log.fatal(.app, "invalid option value", .{ .arg = "--timezone", .value = str, .err = err, .hint = "must be an IANA time zone such as Europe/Paris or UTC" });
|
||||
return error.InvalidArgument;
|
||||
};
|
||||
field.* = try allocator.dupeZ(u8, str);
|
||||
field.* = try allocator.dupeSentinel(u8, str, 0);
|
||||
}
|
||||
|
||||
/// A BCP 47 tag restricted to what ICU and the Accept-Language derivation
|
||||
@@ -1708,8 +1708,8 @@ pub const tagNames = cli.tagNames;
|
||||
/// `<a|b|c>` ghost-text hint built from the same enum's tag names.
|
||||
pub fn tagHint(comptime E: type) []const u8 {
|
||||
var s: []const u8 = "<";
|
||||
for (@typeInfo(E).@"enum".fields, 0..) |f, i| {
|
||||
s = s ++ (if (i == 0) f.name else "|" ++ f.name);
|
||||
for (@typeInfo(E).@"enum".field_names, 0..) |field_name, i| {
|
||||
s = s ++ (if (i == 0) field_name else "|" ++ field_name);
|
||||
}
|
||||
return s ++ ">";
|
||||
}
|
||||
@@ -1717,8 +1717,8 @@ pub fn tagHint(comptime E: type) []const u8 {
|
||||
/// JSON array `["a","b","c"]` representation of the enum tag names.
|
||||
pub fn tagJsonArray(comptime E: type) []const u8 {
|
||||
var s: []const u8 = "[";
|
||||
for (@typeInfo(E).@"enum".fields, 0..) |f, i| {
|
||||
s = s ++ (if (i == 0) "\"" else ",\"") ++ f.name ++ "\"";
|
||||
for (@typeInfo(E).@"enum".field_names, 0..) |field_name, i| {
|
||||
s = s ++ (if (i == 0) "\"" else ",\"") ++ field_name ++ "\"";
|
||||
}
|
||||
return s ++ "]";
|
||||
}
|
||||
+2
-2
@@ -151,8 +151,8 @@ fn _write(self: *const Metrics, writer: *std.Io.Writer) !void {
|
||||
"# TYPE build_info gauge\nbuild_info{{version=\"{s}\"}} 1\n",
|
||||
.{lp.build_config.version},
|
||||
);
|
||||
inline for (@typeInfo(Metrics).@"struct".fields) |f| {
|
||||
try @field(self, f.name).write(f.name, @field(help, f.name), writer);
|
||||
inline for (@typeInfo(Metrics).@"struct".field_names) |field_name| {
|
||||
try @field(self, field_name).write(field_name, @field(help, field_name), writer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -484,12 +484,7 @@ pub fn dispatch(self: *Notification, comptime event: EventType, data: ArgType(ev
|
||||
|
||||
// Given an event type enum, returns the type of arg the event emits
|
||||
pub fn ArgType(comptime event: Notification.EventType) type {
|
||||
inline for (std.meta.fields(Notification.Events)) |f| {
|
||||
if (std.mem.eql(u8, f.name, @tagName(event))) {
|
||||
return f.type;
|
||||
}
|
||||
}
|
||||
unreachable;
|
||||
return @FieldType(Notification.Events, @tagName(event));
|
||||
}
|
||||
|
||||
// Given an event type enum, returns the listening function type
|
||||
|
||||
@@ -43,7 +43,7 @@ free_lists: std.array_hash_map.Custom(Class, ?[*]u8, Class.Context, false) = .em
|
||||
// class, e.g. a 34-byte string and a 40-byte node recycle each other.
|
||||
const Class = packed struct(u64) {
|
||||
alignment: Alignment,
|
||||
size: std.meta.Int(.unsigned, 64 - @bitSizeOf(Alignment)),
|
||||
size: @Int(.unsigned, 64 - @bitSizeOf(Alignment)),
|
||||
|
||||
fn of(len: usize, alignment: Alignment) Class {
|
||||
const class_alignment = Alignment.max(alignment, .of(usize));
|
||||
|
||||
+6
-4
@@ -25,6 +25,7 @@
|
||||
|
||||
const std = @import("std");
|
||||
const pcre2 = @import("pcre2");
|
||||
const repeat = @import("string.zig").repeat;
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
@@ -171,8 +172,9 @@ const MATCH_SCRATCH = 24 * 1024;
|
||||
/// Whether the pattern matches anywhere in `text`, as `RegExp.test` would
|
||||
/// answer. A match that hits the backtracking limits counts as no match.
|
||||
pub fn matches(self: Regex, text: []const u8) bool {
|
||||
var scratch = std.heap.stackFallback(MATCH_SCRATCH, self.context.allocator);
|
||||
var allocator = scratch.get();
|
||||
var scratch_buf: [MATCH_SCRATCH]u8 = undefined;
|
||||
var scratch: std.heap.BufferFirstAllocator = .init(&scratch_buf, self.context.allocator);
|
||||
var allocator = scratch.allocator();
|
||||
const general = pcre2.pcre2_general_context_create_8(Context.cMalloc, Context.cFree, &allocator) orelse return false;
|
||||
defer pcre2.pcre2_general_context_free_8(general);
|
||||
|
||||
@@ -236,9 +238,9 @@ test "Regex: invalid patterns are errors, runaway ones no match" {
|
||||
// the caller.
|
||||
const runaway = try context.compile("^(a+)+$", .{ .case_insensitive = true }, null);
|
||||
defer runaway.deinit();
|
||||
const subject = "a" ** 64 ++ "b";
|
||||
const subject = repeat("a", 64) ++ "b";
|
||||
try testing.expect(!runaway.matches(subject));
|
||||
try testing.expect(runaway.matches("a" ** 64));
|
||||
try testing.expect(runaway.matches(repeat("a", 64)));
|
||||
}
|
||||
|
||||
test "Regex: dot_all and multiline follow the JavaScript flags" {
|
||||
|
||||
@@ -385,7 +385,7 @@ const JsonVisitor = struct {
|
||||
try self.jw.beginObject();
|
||||
|
||||
try self.jw.objectField("nodeId");
|
||||
try self.jw.write(try std.fmt.allocPrint(self.tree.arena, "{d}", .{data.id}));
|
||||
try self.jw.write(try self.tree.arena.print("{d}", .{data.id}));
|
||||
|
||||
try self.jw.objectField("backendDOMNodeId");
|
||||
try self.jw.write(data.id);
|
||||
|
||||
+1
-1
@@ -129,7 +129,7 @@ fn sighandle(self: *SigHandler) noreturn {
|
||||
std.process.exit(1);
|
||||
}
|
||||
|
||||
switch (@as(std.posix.SIG, @enumFromInt(sig))) {
|
||||
switch (@as(std.posix.SIG, @fromBackingInt(@intCast(sig)))) {
|
||||
.INT, .TERM => {
|
||||
self.mutex.lockUncancelable(lp.io);
|
||||
if (self.attempt > 1 and !self.no_hard_exit) {
|
||||
|
||||
@@ -145,7 +145,7 @@ fn handleClient(client: posix.socket_t) void {
|
||||
|
||||
// Send upgrade response
|
||||
var resp_buf: [256]u8 = undefined;
|
||||
const resp = std.fmt.bufPrint(&resp_buf, "HTTP/1.1 101 Switching Protocols\r\n" ++
|
||||
const resp = std.mem.print(&resp_buf, "HTTP/1.1 101 Switching Protocols\r\n" ++
|
||||
"Upgrade: websocket\r\n" ++
|
||||
"Connection: Upgrade\r\n" ++
|
||||
"Sec-WebSocket-Accept: {s}\r\n\r\n", .{accept_key}) catch return;
|
||||
|
||||
+16
-15
@@ -55,8 +55,8 @@ const UserError = error{
|
||||
};
|
||||
|
||||
pub fn isUserError(err: anyerror) bool {
|
||||
inline for (@typeInfo(UserError).error_set.?) |e| {
|
||||
if (err == @field(anyerror, e.name)) return true;
|
||||
inline for (@typeInfo(UserError).error_set.error_names.?) |name| {
|
||||
if (err == @field(anyerror, name)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -194,7 +194,7 @@ api_error_buf: [512]u8 = undefined,
|
||||
api_error_detail: ?[]const u8 = null,
|
||||
|
||||
pub fn init(allocator: std.mem.Allocator, app: *App, opts: Config.Agent) !*Agent {
|
||||
var providers_buf: [@typeInfo(Config.AiProvider).@"enum".fields.len]Candidate = undefined;
|
||||
var providers_buf: [@typeInfo(Config.AiProvider).@"enum".field_names.len]Candidate = undefined;
|
||||
const found_providers = settings.availableProviders(&providers_buf);
|
||||
const available_providers = try allocator.alloc([]const u8, found_providers.len);
|
||||
for (found_providers, 0..) |f, i| {
|
||||
@@ -233,8 +233,9 @@ pub fn init(allocator: std.mem.Allocator, app: *App, opts: Config.Agent) !*Agent
|
||||
|
||||
// Load remembered selection up front so a saved null provider can flip the
|
||||
// REPL into basic mode before resolution. Pure script runs need nothing.
|
||||
const remembered: ?settings.Remembered = if (will_repl or is_one_shot) settings.loadRemembered(allocator) else null;
|
||||
defer if (remembered) |r| std.zon.parse.free(allocator, r);
|
||||
var remembered_arena: std.heap.ArenaAllocator = .init(allocator);
|
||||
defer remembered_arena.deinit();
|
||||
const remembered: ?settings.Remembered = if (will_repl or is_one_shot) settings.loadRemembered(allocator, remembered_arena.allocator()) else null;
|
||||
|
||||
// A remembered null provider means the user disabled the LLM via
|
||||
// `/provider null`; honor it for the REPL only (one-shot --task and script
|
||||
@@ -645,7 +646,7 @@ fn runRepl(self: *Agent) void {
|
||||
self.terminal.printError("{s}", .{switch (err) {
|
||||
error.OutOfMemory => "out of memory",
|
||||
error.FrameNotLoaded => "no page loaded — run /goto <url> first (Esc exits JS mode)",
|
||||
else => std.fmt.allocPrint(aa, "evaluate failed: {s}", .{@errorName(err)}) catch "evaluate failed",
|
||||
else => aa.print("evaluate failed: {s}", .{@errorName(err)}) catch "evaluate failed",
|
||||
}});
|
||||
continue :repl;
|
||||
};
|
||||
@@ -699,7 +700,7 @@ fn runRepl(self: *Agent) void {
|
||||
.comment => continue :repl,
|
||||
.llm => |lc| {
|
||||
var label_buf: [32]u8 = undefined;
|
||||
const label = std.fmt.bufPrint(&label_buf, "/{s}", .{@tagName(lc)}) catch "/?";
|
||||
const label = std.mem.print(&label_buf, "/{s}", .{@tagName(lc)}) catch "/?";
|
||||
if (!self.requireLlm(label)) continue :repl;
|
||||
_ = self.runTurn(.{ .prompt = lc.prompt(), .record_comment = line, .capture_for_save = true, .label = label });
|
||||
},
|
||||
@@ -1008,7 +1009,7 @@ fn subscriptionLogin(self: *Agent, desc: *const auth.Descriptor) ?auth.Session {
|
||||
fn promptStoredSubscription(self: *Agent, desc: *const auth.Descriptor, stored: auth.Session) ?auth.Session {
|
||||
var session = stored;
|
||||
var header_buf: [128]u8 = undefined;
|
||||
const header = std.fmt.bufPrint(&header_buf, "Already logged in with your {s}. Pick:", .{desc.label}) catch
|
||||
const header = std.mem.print(&header_buf, "Already logged in with your {s}. Pick:", .{desc.label}) catch
|
||||
"Already logged in. Pick:";
|
||||
const idx = picker.promptNumberedChoice(header, &.{
|
||||
"keep — use the stored login",
|
||||
@@ -1167,7 +1168,7 @@ fn handleSave(self: *Agent, arena: std.mem.Allocator, rest: []const u8) void {
|
||||
|
||||
fn promptSaveMode(self: *Agent, path: []const u8) ?save.Mode {
|
||||
var header_buf: [256]u8 = undefined;
|
||||
const header = std.fmt.bufPrint(&header_buf, "{s} already exists. Pick save mode:", .{path}) catch
|
||||
const header = std.mem.print(&header_buf, "{s} already exists. Pick save mode:", .{path}) catch
|
||||
"File already exists. Pick save mode:";
|
||||
const with_llm = self.ai_client != null;
|
||||
const modes: []const save.Mode = if (with_llm)
|
||||
@@ -1507,7 +1508,7 @@ fn runCommand(self: *Agent, arena: std.mem.Allocator, tc: Command.ToolCall) brow
|
||||
.text = switch (err) {
|
||||
error.OutOfMemory => "out of memory",
|
||||
error.FrameNotLoaded => "no page loaded — run /goto <url> first",
|
||||
else => std.fmt.allocPrint(arena, "{s} failed: {s}", .{ tc.name(), browser_tools.errorMessage(err) }) catch "tool failed",
|
||||
else => arena.print("{s} failed: {s}", .{ tc.name(), browser_tools.errorMessage(err) }) catch "tool failed",
|
||||
},
|
||||
.is_error = true,
|
||||
};
|
||||
@@ -1634,7 +1635,7 @@ fn recordSlashToolCall(
|
||||
|
||||
const tool_calls = try ma.alloc(zenai.provider.ToolCall, 1);
|
||||
tool_calls[0] = .{
|
||||
.id = try std.fmt.allocPrint(ma, "lp-slash-{d}", .{self.synthetic_tool_call_id}),
|
||||
.id = try ma.print("lp-slash-{d}", .{self.synthetic_tool_call_id}),
|
||||
.name = try ma.dupe(u8, tool_name),
|
||||
.arguments = if (args) |v| try zenai.json.dupeValue(ma, v) else null,
|
||||
};
|
||||
@@ -1685,9 +1686,9 @@ fn formatApiError(self: *Agent, client: zenai.provider.Client, err: anyerror) []
|
||||
else
|
||||
"";
|
||||
if (e.message) |m| {
|
||||
if (std.fmt.bufPrint(&self.api_error_buf, "HTTP {d} — {s}{s}", .{ status, m, hint })) |s| return s else |_| {}
|
||||
if (std.mem.print(&self.api_error_buf, "HTTP {d} — {s}{s}", .{ status, m, hint })) |s| return s else |_| {}
|
||||
}
|
||||
return std.fmt.bufPrint(&self.api_error_buf, "HTTP {d}{s}", .{ status, hint }) catch @errorName(err);
|
||||
return std.mem.print(&self.api_error_buf, "HTTP {d}{s}", .{ status, hint }) catch @errorName(err);
|
||||
}
|
||||
|
||||
/// Returned text lives in `conversation.arena`, valid only until the next prune.
|
||||
@@ -1932,7 +1933,7 @@ fn capToolOutput(allocator: std.mem.Allocator, tool_name: []const u8, output: []
|
||||
if (output.len <= cap) return output;
|
||||
const prefix = string.truncateUtf8(output, cap);
|
||||
var suffix_buf: [128]u8 = undefined;
|
||||
const suffix = std.fmt.bufPrint(&suffix_buf, "\n...[truncated, original {d} bytes — re-read scoped (selector/backendNodeId)]", .{output.len}) catch return prefix;
|
||||
const suffix = std.mem.print(&suffix_buf, "\n...[truncated, original {d} bytes — re-read scoped (selector/backendNodeId)]", .{output.len}) catch return prefix;
|
||||
return std.mem.concat(allocator, u8, &.{ prefix, suffix }) catch prefix;
|
||||
}
|
||||
|
||||
@@ -1954,7 +1955,7 @@ fn handleToolCall(ctx: *anyopaque, allocator: std.mem.Allocator, tool_name: []co
|
||||
|
||||
var selector: ?[]const u8 = null;
|
||||
const outcome = self.toolOutcome(allocator, tool_name, arguments, &selector) catch |err| zenai.provider.Client.ToolHandler.Result{
|
||||
.content = std.fmt.allocPrint(allocator, "Error: {s}", .{browser_tools.errorMessage(err)}) catch "Error: tool execution failed",
|
||||
.content = allocator.print("Error: {s}", .{browser_tools.errorMessage(err)}) catch "Error: tool execution failed",
|
||||
.is_error = true,
|
||||
};
|
||||
if (self.capturing_for_save) {
|
||||
|
||||
@@ -151,7 +151,7 @@ test "expireImages keeps the newest images and annotates the rest" {
|
||||
const image = [_]zenai.provider.ContentPart{.{ .image = .{ .data = "AAAA", .mime_type = "image/png" } }};
|
||||
for (0..4) |n| {
|
||||
const results = try a.alloc(zenai.provider.ToolResult, 1);
|
||||
results[0] = .{ .id = "c", .name = "screenshot", .content = try std.fmt.allocPrint(a, "shot {d}", .{n}), .parts = &image };
|
||||
results[0] = .{ .id = "c", .name = "screenshot", .content = try a.print("shot {d}", .{n}), .parts = &image };
|
||||
try conv.messages.append(std.testing.allocator, .{ .role = .tool, .tool_results = results });
|
||||
}
|
||||
|
||||
|
||||
@@ -140,7 +140,7 @@ pub fn stop(self: *Spinner) void {
|
||||
const elapsed_s = @as(f64, @floatFromInt(elapsed_ms)) / @as(f64, std.time.ms_per_s);
|
||||
|
||||
var buf: [frame_buf_bytes]u8 = undefined;
|
||||
const summary = std.fmt.bufPrint(
|
||||
const summary = std.mem.print(
|
||||
&buf,
|
||||
"\r" ++ clear_eol ++ ansi.dim ++ "[agent: worked for {d:.1}s · {d} tool call{s}]" ++ ansi.reset ++ "\n",
|
||||
.{ elapsed_s, self.tool_calls, if (self.tool_calls == 1) "" else "s" },
|
||||
@@ -275,7 +275,7 @@ fn renderLocked(self: *Spinner) void {
|
||||
const glyph = braille[self.frame % braille.len];
|
||||
const written = switch (self.state) {
|
||||
.idle => return,
|
||||
.thinking => std.fmt.bufPrint(
|
||||
.thinking => std.mem.print(
|
||||
&buf,
|
||||
"\r" ++ ansi.yellow ++ "{s}" ++ ansi.reset ++ " " ++ ansi.dim ++ "[agent: thinking]" ++ ansi.reset ++ clear_eol,
|
||||
.{glyph},
|
||||
@@ -297,7 +297,7 @@ fn renderLocked(self: *Spinner) void {
|
||||
const cap = @min(max_args_cells, room);
|
||||
const cut = truncToCells(all_args, cap);
|
||||
const suffix: []const u8 = if (cut < all_args.len) ellipsis else "";
|
||||
break :blk std.fmt.bufPrint(
|
||||
break :blk std.mem.print(
|
||||
&buf,
|
||||
"\r" ++ ansi.yellow ++ "{s}" ++ ansi.reset ++ " " ++ ansi.dim ++ "[{s}{s} {s}{s}]" ++ ansi.reset ++ clear_eol,
|
||||
.{ glyph, prefix, name, all_args[0..cut], suffix },
|
||||
|
||||
@@ -141,7 +141,7 @@ fn emitStderr(self: *Terminal, bytes: []const u8) void {
|
||||
|
||||
fn formatBulletLine(arena: std.mem.Allocator, name: []const u8, args: []const u8, ok: bool) ![]const u8 {
|
||||
const bullet_color = if (ok) ansi.green else ansi.red;
|
||||
return std.fmt.allocPrint(arena, bullet_line_fmt, .{ bullet_color, ansi.reset, ansi.dim, name, ansi.reset, args });
|
||||
return arena.print(bullet_line_fmt, .{ bullet_color, ansi.reset, ansi.dim, name, ansi.reset, args });
|
||||
}
|
||||
|
||||
pub fn setIdleCallback(fun: ?*const c.ic_idle_fun_t, arg: ?*anyopaque) void {
|
||||
@@ -307,7 +307,7 @@ pub fn printToolOutcome(self: *Terminal, name: []const u8, text: []const u8, is_
|
||||
pub fn printScriptDone(self: *Terminal, name: []const u8, args: []const u8) void {
|
||||
if (!self.spinner.isEnabled()) return;
|
||||
var buf: [256]u8 = undefined;
|
||||
const line = std.fmt.bufPrint(
|
||||
const line = std.mem.print(
|
||||
&buf,
|
||||
ansi.green ++ "●" ++ ansi.reset ++ " " ++ ansi.dim ++ "[{s} {s}]" ++ ansi.reset ++ "\n",
|
||||
.{ name, args },
|
||||
@@ -354,7 +354,7 @@ pub fn printWarning(self: *Terminal, comptime fmt: []const u8, args: anytype) vo
|
||||
fn printSeverity(self: *Terminal, color: []const u8, label: []const u8, comptime fmt: []const u8, args: anytype) void {
|
||||
if (self.repl_arena) |*a| {
|
||||
defer _ = a.reset(.retain_capacity);
|
||||
const bytes = std.fmt.allocPrint(a.allocator(), "{s}●{s} " ++ fmt ++ "\n", .{ color, ansi.reset } ++ args) catch return;
|
||||
const bytes = a.allocator().print("{s}●{s} " ++ fmt ++ "\n", .{ color, ansi.reset } ++ args) catch return;
|
||||
return self.emitStderr(bytes);
|
||||
}
|
||||
std.debug.print("{s}{s}{s}: " ++ fmt ++ "{s}\n", .{ ansi.bold, color, label } ++ args ++ .{ansi.reset});
|
||||
|
||||
@@ -50,7 +50,7 @@ pub const TokenSet = struct {
|
||||
account_id: ?[]const u8 = null,
|
||||
|
||||
pub fn dup(allocator: std.mem.Allocator, access: []const u8, refresh: []const u8, expires_at_ms: i64, account_id: ?[]const u8) !TokenSet {
|
||||
const a = try allocator.dupeZ(u8, access);
|
||||
const a = try allocator.dupeSentinel(u8, access, 0);
|
||||
errdefer allocator.free(a);
|
||||
const r = try allocator.dupe(u8, refresh);
|
||||
errdefer allocator.free(r);
|
||||
|
||||
@@ -108,13 +108,13 @@ fn parseTokenResponse(allocator: std.mem.Allocator, body: []const u8) !auth.Toke
|
||||
}
|
||||
|
||||
fn refreshBody(arena: std.mem.Allocator, refresh_token: []const u8) ![]u8 {
|
||||
return std.fmt.allocPrint(arena, "grant_type=refresh_token&client_id=" ++ client_id ++ "&refresh_token={s}", .{
|
||||
return arena.print("grant_type=refresh_token&client_id=" ++ client_id ++ "&refresh_token={s}", .{
|
||||
try lp.URL.percentEncodeSegment(arena, refresh_token, .component),
|
||||
});
|
||||
}
|
||||
|
||||
fn exchangeBody(arena: std.mem.Allocator, code: []const u8, code_verifier: []const u8) ![]u8 {
|
||||
return std.fmt.allocPrint(arena, "grant_type=authorization_code&client_id=" ++ client_id ++
|
||||
return arena.print("grant_type=authorization_code&client_id=" ++ client_id ++
|
||||
"&redirect_uri=" ++ device_redirect_uri ++ "&code={s}&code_verifier={s}", .{
|
||||
try lp.URL.percentEncodeSegment(arena, code, .component),
|
||||
try lp.URL.percentEncodeSegment(arena, code_verifier, .component),
|
||||
@@ -155,7 +155,7 @@ fn deviceLogin(allocator: std.mem.Allocator, interrupt: ?*zenai.http.Interrupt)
|
||||
|
||||
const code_res = try post(a, interrupt, device_code_url, "application/json", "{\"client_id\":\"" ++ client_id ++ "\"}");
|
||||
if (code_res.status != .ok) {
|
||||
log.warn(.app, "codex device-code failed", .{ .status = @intFromEnum(code_res.status), .body = code_res.body });
|
||||
log.warn(.app, "codex device-code failed", .{ .status = @backingInt(code_res.status), .body = code_res.body });
|
||||
return error.DeviceCodeRequestFailed;
|
||||
}
|
||||
const dc = try std.json.parseFromSliceLeaky(DeviceCode, a, code_res.body, .{ .ignore_unknown_fields = true });
|
||||
@@ -166,7 +166,7 @@ fn deviceLogin(allocator: std.mem.Allocator, interrupt: ?*zenai.http.Interrupt)
|
||||
.{ verify_url, dc.user_code },
|
||||
);
|
||||
|
||||
const poll_body = try std.fmt.allocPrint(a, "{f}", .{std.json.fmt(
|
||||
const poll_body = try a.print("{f}", .{std.json.fmt(
|
||||
.{ .device_auth_id = dc.device_auth_id, .user_code = dc.user_code },
|
||||
.{},
|
||||
)});
|
||||
@@ -178,7 +178,7 @@ fn deviceLogin(allocator: std.mem.Allocator, interrupt: ?*zenai.http.Interrupt)
|
||||
// Still pending — the user hasn't finished authorizing.
|
||||
.forbidden, .not_found => continue,
|
||||
else => {
|
||||
log.warn(.app, "codex device-auth poll failed", .{ .status = @intFromEnum(res.status), .body = res.body });
|
||||
log.warn(.app, "codex device-auth poll failed", .{ .status = @backingInt(res.status), .body = res.body });
|
||||
return error.DeviceAuthFailed;
|
||||
},
|
||||
}
|
||||
@@ -187,7 +187,7 @@ fn deviceLogin(allocator: std.mem.Allocator, interrupt: ?*zenai.http.Interrupt)
|
||||
const exchange = try exchangeBody(a, dt.authorization_code, dt.code_verifier);
|
||||
const tok_res = try post(a, interrupt, token_url, "application/x-www-form-urlencoded", exchange);
|
||||
if (tok_res.status != .ok) {
|
||||
log.warn(.app, "codex token exchange failed", .{ .status = @intFromEnum(tok_res.status), .body = tok_res.body });
|
||||
log.warn(.app, "codex token exchange failed", .{ .status = @backingInt(tok_res.status), .body = tok_res.body });
|
||||
return error.TokenExchangeFailed;
|
||||
}
|
||||
return parseTokenResponse(allocator, tok_res.body);
|
||||
@@ -200,7 +200,7 @@ fn refreshGrant(allocator: std.mem.Allocator, refresh_token: []const u8) !auth.T
|
||||
const body = try refreshBody(a, refresh_token);
|
||||
const res = try post(a, null, token_url, "application/x-www-form-urlencoded", body);
|
||||
if (res.status != .ok) {
|
||||
log.warn(.app, "codex token refresh failed", .{ .status = @intFromEnum(res.status), .body = res.body });
|
||||
log.warn(.app, "codex token refresh failed", .{ .status = @backingInt(res.status), .body = res.body });
|
||||
return error.RefreshFailed;
|
||||
}
|
||||
return parseTokenResponse(allocator, res.body);
|
||||
@@ -233,7 +233,7 @@ fn makeJwt(arena: std.mem.Allocator, payload_json: []const u8) ![]const u8 {
|
||||
const enc = std.base64.url_safe_no_pad.Encoder;
|
||||
const p = try arena.alloc(u8, enc.calcSize(payload_json.len));
|
||||
_ = enc.encode(p, payload_json);
|
||||
return std.fmt.allocPrint(arena, "aGVhZGVy.{s}.c2ln", .{p});
|
||||
return arena.print("aGVhZGVy.{s}.c2ln", .{p});
|
||||
}
|
||||
|
||||
test "accountIdFromJwt: top-level chatgpt_account_id" {
|
||||
@@ -281,7 +281,7 @@ test "parseTokenResponse derives account id and absolute expiry" {
|
||||
defer arena.deinit();
|
||||
const a = arena.allocator();
|
||||
const jwt = try makeJwt(a, "{\"chatgpt_account_id\":\"acct-x\"}");
|
||||
const body = try std.fmt.allocPrint(a, "{{\"access_token\":\"acc\",\"refresh_token\":\"ref\",\"id_token\":\"{s}\",\"expires_in\":3600}}", .{jwt});
|
||||
const body = try a.print("{{\"access_token\":\"acc\",\"refresh_token\":\"ref\",\"id_token\":\"{s}\",\"expires_in\":3600}}", .{jwt});
|
||||
const tokens = try parseTokenResponse(std.testing.allocator, body);
|
||||
defer tokens.deinit(std.testing.allocator);
|
||||
try std.testing.expectEqualStrings("acc", tokens.access_token);
|
||||
|
||||
@@ -51,7 +51,7 @@ const Cache = struct {
|
||||
};
|
||||
|
||||
fn cachePath(arena: std.mem.Allocator, app_dir: []const u8, provider_id: []const u8) ![]const u8 {
|
||||
const name = try std.fmt.allocPrint(arena, "models-dev-{s}.json", .{provider_id});
|
||||
const name = try arena.print("models-dev-{s}.json", .{provider_id});
|
||||
return std.fs.path.join(arena, &.{ app_dir, name });
|
||||
}
|
||||
|
||||
|
||||
+13
-12
@@ -19,6 +19,7 @@
|
||||
const std = @import("std");
|
||||
const ansi = @import("ansi.zig");
|
||||
const js_highlight = @import("js_highlight.zig");
|
||||
const repeat = @import("../string.zig").repeat;
|
||||
|
||||
/// Render markdown `src` as ANSI-styled terminal output to `w`. Tables are
|
||||
/// aligned straight from `src`, so unlike `Stream` there is no size limit.
|
||||
@@ -470,7 +471,7 @@ fn renderLine(w: *std.Io.Writer, line: []const u8, js: ?*js_highlight.State) !vo
|
||||
|
||||
// Dashed, unlike the solid fence rules, so adjacent ones read differently.
|
||||
if (isHorizontalRule(trimmed)) {
|
||||
try styled(w, "┄" ** rule_width, ansi.dim);
|
||||
try styled(w, repeat("┄", rule_width), ansi.dim);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -729,8 +730,8 @@ test "md_term: nested inline styles" {
|
||||
);
|
||||
}
|
||||
|
||||
const open_rule = "\x1b[2m╭" ++ "─" ** 23 ++ "\x1b[0m";
|
||||
const close_rule = "\x1b[2m╰" ++ "─" ** 23 ++ "\x1b[0m";
|
||||
const open_rule = "\x1b[2m╭" ++ repeat("─", 23) ++ "\x1b[0m";
|
||||
const close_rule = "\x1b[2m╰" ++ repeat("─", 23) ++ "\x1b[0m";
|
||||
|
||||
test "md_term: fenced code block is highlighted as JavaScript" {
|
||||
try expectRender(
|
||||
@@ -743,13 +744,13 @@ test "md_term: fenced code block is highlighted as JavaScript" {
|
||||
|
||||
test "md_term: fence rules carry the language tag" {
|
||||
try expectRender(
|
||||
"\x1b[2m╭─ js " ++ "─" ** 18 ++ "\x1b[0m\n\nx\n\n" ++ close_rule,
|
||||
"\x1b[2m╭─ js " ++ repeat("─", 18) ++ "\x1b[0m\n\nx\n\n" ++ close_rule,
|
||||
"```js\nx\n```",
|
||||
);
|
||||
// An overlong info string doesn't fit the rule and is dropped.
|
||||
try expectRender(
|
||||
open_rule ++ "\n\nx\n\n" ++ close_rule,
|
||||
"```" ++ "x" ** 20 ++ "\nx\n```",
|
||||
"```" ++ repeat("x", 20) ++ "\nx\n```",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -791,8 +792,8 @@ test "md_term: blockquote" {
|
||||
}
|
||||
|
||||
test "md_term: horizontal rule" {
|
||||
try expectRender("\x1b[2m" ++ "┄" ** 24 ++ "\x1b[0m", "---");
|
||||
try expectRender("\x1b[2m" ++ "┄" ** 24 ++ "\x1b[0m", "***");
|
||||
try expectRender("\x1b[2m" ++ repeat("┄", 24) ++ "\x1b[0m", "---");
|
||||
try expectRender("\x1b[2m" ++ repeat("┄", 24) ++ "\x1b[0m", "***");
|
||||
try expectRender("---x", "---x");
|
||||
}
|
||||
|
||||
@@ -828,7 +829,7 @@ test "md_term: pipe rows without a separator pass through" {
|
||||
try expectRender("| a |\n", "| a |\n");
|
||||
}
|
||||
|
||||
const big_table = "| A | B |\n|-|-|\n" ++ ("| " ++ "a" ** 16 ++ " | " ++ "b" ** 16 ++ " |\n") ** 500;
|
||||
const big_table = "| A | B |\n|-|-|\n" ++ repeat("| " ++ repeat("a", 16) ++ " | " ++ repeat("b", 16) ++ " |\n", 500);
|
||||
|
||||
test "md_term: batch aligns tables beyond the stream table buffer" {
|
||||
try testing.expect(big_table.len > table_buf_len);
|
||||
@@ -839,8 +840,8 @@ test "md_term: batch aligns tables beyond the stream table buffer" {
|
||||
|
||||
const pipe = "\x1b[2m│\x1b[0m";
|
||||
try testing.expectEqual(0, std.mem.count(u8, out, "| a"));
|
||||
try testing.expectEqual(500, std.mem.count(u8, out, pipe ++ " " ++ "a" ** 16 ++ " " ++ pipe));
|
||||
try testing.expect(std.mem.indexOf(u8, out, "\x1b[2m├" ++ "─" ** 18 ++ "┼" ++ "─" ** 18 ++ "┤\x1b[0m\n") != null);
|
||||
try testing.expectEqual(500, std.mem.count(u8, out, pipe ++ " " ++ repeat("a", 16) ++ " " ++ pipe));
|
||||
try testing.expect(std.mem.indexOf(u8, out, "\x1b[2m├" ++ repeat("─", 18) ++ "┼" ++ repeat("─", 18) ++ "┤\x1b[0m\n") != null);
|
||||
}
|
||||
|
||||
test "md_term: stream falls back to raw rows past its table buffer" {
|
||||
@@ -853,8 +854,8 @@ test "md_term: stream falls back to raw rows past its table buffer" {
|
||||
}
|
||||
|
||||
test "md_term: overwide table falls back to verbatim rows" {
|
||||
const header = "|a" ** 17 ++ "|";
|
||||
const sep = "|-" ** 17 ++ "|";
|
||||
const header = repeat("|a", 17) ++ "|";
|
||||
const sep = repeat("|-", 17) ++ "|";
|
||||
try expectRender(
|
||||
"\x1b[1m" ++ header ++ "\x1b[0m\n\x1b[2m" ++ sep ++ "\x1b[0m\n",
|
||||
header ++ "\n" ++ sep,
|
||||
|
||||
@@ -118,8 +118,8 @@ const RawTerminal = struct {
|
||||
raw.lflag.ICANON = false;
|
||||
raw.lflag.IEXTEN = false;
|
||||
raw.lflag.ISIG = false;
|
||||
raw.cc[@intFromEnum(std.c.V.MIN)] = 0;
|
||||
raw.cc[@intFromEnum(std.c.V.TIME)] = 1;
|
||||
raw.cc[@backingInt(std.c.V.MIN)] = 0;
|
||||
raw.cc[@backingInt(std.c.V.TIME)] = 1;
|
||||
std.posix.tcsetattr(std.posix.STDIN_FILENO, .FLUSH, raw) catch return error.NotInteractive;
|
||||
// Under `ansi.kitty_disambiguate` (pushed by `Terminal.readLine`),
|
||||
// cursor keys arrive as CSI-u the byte reader can't parse; push the
|
||||
|
||||
@@ -72,13 +72,13 @@ const kind_styles = blk: {
|
||||
const n = std.enums.values(js_highlight.Kind).len;
|
||||
var arr: [n]?[:0]const u8 = @splat(null);
|
||||
for (styles) |s| for (s.kinds) |kind| {
|
||||
if (arr[@intFromEnum(kind)] != null) @compileError("kind styled twice: " ++ @tagName(kind));
|
||||
arr[@intFromEnum(kind)] = s.name;
|
||||
if (arr[@backingInt(kind)] != null) @compileError("kind styled twice: " ++ @tagName(kind));
|
||||
arr[@backingInt(kind)] = s.name;
|
||||
};
|
||||
var out: [n][:0]const u8 = undefined;
|
||||
for (arr, 0..) |name, i| {
|
||||
out[i] = name orelse @compileError("js_highlight.Kind with no ps-* style: " ++
|
||||
@tagName(@as(js_highlight.Kind, @enumFromInt(i))));
|
||||
@tagName(@as(js_highlight.Kind, @fromBackingInt(@intCast(i)))));
|
||||
}
|
||||
break :blk out;
|
||||
};
|
||||
@@ -169,7 +169,7 @@ fn addPrefixedCompletion(
|
||||
partial: []const u8,
|
||||
) void {
|
||||
if (!std.ascii.startsWithIgnoreCase(name, partial)) return;
|
||||
const text = std.fmt.bufPrintZ(buf, "{s}{s}{s}", .{ prefix, name, suffix }) catch return;
|
||||
const text = std.mem.printSentinel(buf, "{s}{s}{s}", .{ prefix, name, suffix }, 0) catch return;
|
||||
_ = c.ic_add_completion_prim(cenv, text.ptr, null, null, @intCast(input.len), 0);
|
||||
}
|
||||
|
||||
@@ -408,7 +408,7 @@ fn addPathCompletions(
|
||||
var name_buf: [completion_buf_len]u8 = undefined;
|
||||
while (matches.next()) |m| {
|
||||
const suffix: []const u8 = if (m.is_dir) "/" else "";
|
||||
const full = std.fmt.bufPrint(&name_buf, "{s}{s}", .{ matches.dir_part, m.name }) catch continue;
|
||||
const full = std.mem.print(&name_buf, "{s}{s}", .{ matches.dir_part, m.name }) catch continue;
|
||||
addPrefixedCompletion(cenv, buf, input, prefix, full, suffix, body);
|
||||
}
|
||||
}
|
||||
@@ -580,7 +580,7 @@ fn ghostPathFirstMatch(body: []const u8) [*c]const u8 {
|
||||
defer matches.deinit();
|
||||
const m = matches.next() orelse return null;
|
||||
const suffix: []const u8 = if (m.is_dir) "/" else "";
|
||||
const text = std.fmt.bufPrintZ(&hint_buf, "{s}{s}", .{ m.name[matches.base.len..], suffix }) catch return null;
|
||||
const text = std.mem.printSentinel(&hint_buf, "{s}{s}", .{ m.name[matches.base.len..], suffix }, 0) catch return null;
|
||||
return text.ptr;
|
||||
}
|
||||
|
||||
@@ -589,7 +589,7 @@ fn ghostPathFirstMatch(body: []const u8) [*c]const u8 {
|
||||
fn ghostFirstMatch(names: []const []const u8, body: []const u8, lead: []const u8) [*c]const u8 {
|
||||
for (names) |v| {
|
||||
if (!std.ascii.startsWithIgnoreCase(v, body)) continue;
|
||||
const text = std.fmt.bufPrintZ(&hint_buf, "{s}{s}", .{ lead, v[body.len..] }) catch return null;
|
||||
const text = std.mem.printSentinel(&hint_buf, "{s}{s}", .{ lead, v[body.len..] }, 0) catch return null;
|
||||
return text.ptr;
|
||||
}
|
||||
return null;
|
||||
@@ -621,7 +621,7 @@ fn renderSchemaHint(schema: *const Schema, body: []const u8, ends_ws: bool) [*c]
|
||||
for (schema.hints) |slot| {
|
||||
if (a.isUsed(slot.name)) continue;
|
||||
if (!std.ascii.startsWithIgnoreCase(slot.name, pk)) continue;
|
||||
const text = std.fmt.bufPrintZ(&hint_buf, "{s}=…", .{slot.name[pk.len..]}) catch return null;
|
||||
const text = std.mem.printSentinel(&hint_buf, "{s}=…", .{slot.name[pk.len..]}, 0) catch return null;
|
||||
return text.ptr;
|
||||
}
|
||||
return null;
|
||||
@@ -725,7 +725,7 @@ const IcSink = struct {
|
||||
henv: ?*c.ic_highlight_env_t,
|
||||
|
||||
pub fn emit(self: IcSink, start: usize, len: usize, kind: js_highlight.Kind) void {
|
||||
c.ic_highlight(self.henv, @intCast(start), @intCast(len), kind_styles[@intFromEnum(kind)].ptr);
|
||||
c.ic_highlight(self.henv, @intCast(start), @intCast(len), kind_styles[@backingInt(kind)].ptr);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+1
-1
@@ -72,7 +72,7 @@ pub fn randomFilename(arena: std.mem.Allocator) ![]const u8 {
|
||||
var n_bytes: [8]u8 = undefined;
|
||||
lp.io.random(&n_bytes);
|
||||
const n = std.mem.readInt(u64, &n_bytes, .little);
|
||||
const path = try std.fmt.allocPrint(arena, "session-{x}.js", .{n});
|
||||
const path = try arena.print("session-{x}.js", .{n});
|
||||
if (!(try fileExists(path))) return path;
|
||||
}
|
||||
return error.NameCollision;
|
||||
|
||||
+28
-25
@@ -126,7 +126,7 @@ pub fn gcloudAccessToken(allocator: std.mem.Allocator) ![:0]const u8 {
|
||||
std.debug.print("`gcloud auth print-access-token` failed:\n{s}", .{result.stderr});
|
||||
return error.GcloudTokenFailed;
|
||||
}
|
||||
return allocator.dupeZ(u8, token);
|
||||
return allocator.dupeSentinel(u8, token, 0);
|
||||
}
|
||||
|
||||
/// True when a non-Ollama provider key is available (flag, remembered, or
|
||||
@@ -271,24 +271,24 @@ pub const Remembered = struct {
|
||||
search_engine: ?lp.tools.SearchEngine = null,
|
||||
};
|
||||
|
||||
pub fn loadRemembered(allocator: std.mem.Allocator) ?Remembered {
|
||||
const data = std.Io.Dir.cwd().readFileAllocOptions(lp.io, remembered_path, allocator, .limited(1024), .of(u8), 0) catch return null;
|
||||
defer allocator.free(data);
|
||||
return parseRemembered(allocator, data);
|
||||
/// The result's strings live in `arena`.
|
||||
pub fn loadRemembered(gpa: std.mem.Allocator, arena: std.mem.Allocator) ?Remembered {
|
||||
const data = std.Io.Dir.cwd().readFileAllocOptions(lp.io, remembered_path, gpa, .limited(1024), .of(u8), 0) catch return null;
|
||||
defer gpa.free(data);
|
||||
return parseRemembered(gpa, arena, data);
|
||||
}
|
||||
|
||||
fn parseRemembered(allocator: std.mem.Allocator, data: [:0]const u8) ?Remembered {
|
||||
// A real Diagnostics, not null: a type-check failure allocates an owned
|
||||
// error note that leaks unless a Diagnostics owns it to free on deinit.
|
||||
var diag: std.zon.parse.Diagnostics = .{};
|
||||
defer diag.deinit(allocator);
|
||||
const remembered = std.zon.parse.fromSliceAlloc(Remembered, allocator, data, &diag, .{}) catch return null;
|
||||
fn parseRemembered(gpa: std.mem.Allocator, arena: std.mem.Allocator, data: [:0]const u8) ?Remembered {
|
||||
var diag: std.zon.parse.Diagnostics = undefined;
|
||||
const remembered = std.zon.parse.fromSlice(Remembered, .{
|
||||
.gpa = gpa,
|
||||
.arena = arena,
|
||||
.source = data,
|
||||
.diagnostics = &diag,
|
||||
}) catch return null;
|
||||
// An empty model is corrupt only when a provider is set; a null provider
|
||||
// (LLM disabled) legitimately has no model to remember.
|
||||
if (remembered.provider != null and remembered.model.len == 0) {
|
||||
std.zon.parse.free(allocator, remembered);
|
||||
return null;
|
||||
}
|
||||
if (remembered.provider != null and remembered.model.len == 0) return null;
|
||||
return remembered;
|
||||
}
|
||||
|
||||
@@ -423,15 +423,16 @@ pub fn reconcileModel(
|
||||
|
||||
const testing = @import("../testing.zig");
|
||||
|
||||
test "parseRemembered: invalid enum is rejected without leaking" {
|
||||
// A bad enum builds an owned error note; the leak detector fails here if
|
||||
// the Diagnostics doesn't free it.
|
||||
try testing.expect(parseRemembered(testing.allocator, ".{ .provider = .not_a_provider, .model = \"x\" }") == null);
|
||||
test "parseRemembered: invalid enum is rejected" {
|
||||
var arena: std.heap.ArenaAllocator = .init(testing.allocator);
|
||||
defer arena.deinit();
|
||||
try testing.expect(parseRemembered(testing.allocator, arena.allocator(), ".{ .provider = .not_a_provider, .model = \"x\" }") == null);
|
||||
}
|
||||
|
||||
test "parseRemembered: valid file round-trips" {
|
||||
const remembered = parseRemembered(testing.allocator, ".{ .provider = null, .model = \"some-model\" }").?;
|
||||
defer std.zon.parse.free(testing.allocator, remembered);
|
||||
var arena: std.heap.ArenaAllocator = .init(testing.allocator);
|
||||
defer arena.deinit();
|
||||
const remembered = parseRemembered(testing.allocator, arena.allocator(), ".{ .provider = null, .model = \"some-model\" }").?;
|
||||
try testing.expect(remembered.provider == null);
|
||||
try testing.expectString("some-model", remembered.model);
|
||||
// Absent `stream` is null so pre-streaming files still fall back to the default.
|
||||
@@ -439,14 +440,16 @@ test "parseRemembered: valid file round-trips" {
|
||||
}
|
||||
|
||||
test "parseRemembered: stream field round-trips" {
|
||||
const remembered = parseRemembered(testing.allocator, ".{ .model = \"m\", .stream = false }").?;
|
||||
defer std.zon.parse.free(testing.allocator, remembered);
|
||||
var arena: std.heap.ArenaAllocator = .init(testing.allocator);
|
||||
defer arena.deinit();
|
||||
const remembered = parseRemembered(testing.allocator, arena.allocator(), ".{ .model = \"m\", .stream = false }").?;
|
||||
try testing.expect(remembered.stream == false);
|
||||
}
|
||||
|
||||
test "parseRemembered: search_engine field round-trips" {
|
||||
const remembered = parseRemembered(testing.allocator, ".{ .model = \"m\", .search_engine = .brave }").?;
|
||||
defer std.zon.parse.free(testing.allocator, remembered);
|
||||
var arena: std.heap.ArenaAllocator = .init(testing.allocator);
|
||||
defer arena.deinit();
|
||||
const remembered = parseRemembered(testing.allocator, arena.allocator(), ".{ .model = \"m\", .search_engine = .brave }").?;
|
||||
try testing.expect(remembered.search_engine == .brave);
|
||||
}
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ comptime {
|
||||
/// hints beside it, vertically centered. `llm_active` picks the tagline.
|
||||
pub fn print(llm_active: bool) void {
|
||||
var version_buf: [192]u8 = undefined;
|
||||
const version: []const u8 = std.fmt.bufPrint(&version_buf, ansi.dim ++ "{s}" ++ ansi.reset, .{lp.build_config.version}) catch "";
|
||||
const version: []const u8 = std.mem.print(&version_buf, ansi.dim ++ "{s}" ++ ansi.reset, .{lp.build_config.version}) catch "";
|
||||
|
||||
var lines: [9][]const u8 = undefined;
|
||||
var n: usize = 0;
|
||||
|
||||
@@ -476,7 +476,7 @@ pub const Listener = struct {
|
||||
};
|
||||
},
|
||||
.string => |string| {
|
||||
const str = try arena.dupeZ(u8, string.str());
|
||||
const str = try arena.dupeSentinel(u8, string.str(), 0);
|
||||
local.eval(str, null) catch |err| {
|
||||
if (err == error.ExecutionTerminated) {
|
||||
return error.ExecutionTerminated;
|
||||
|
||||
+9
-16
@@ -479,21 +479,14 @@ pub fn chained(self: *Factory, values: anytype) !*ChainedLeaf(@TypeOf(values)) {
|
||||
}
|
||||
|
||||
pub fn chainedWithAllocator(allocator: Allocator, values: anytype) !*ChainedLeaf(@TypeOf(values)) {
|
||||
const fields = @typeInfo(@TypeOf(values)).@"struct".fields;
|
||||
const types = comptime blk: {
|
||||
var types: [fields.len]type = undefined;
|
||||
for (fields, 0..) |f, i| {
|
||||
types[i] = f.type;
|
||||
}
|
||||
break :blk types;
|
||||
};
|
||||
const types = @typeInfo(@TypeOf(values)).@"struct".field_types;
|
||||
comptime {
|
||||
for (types[1..], 0..) |T, i| {
|
||||
assert(reflect.Proto(T).? == types[i]);
|
||||
}
|
||||
}
|
||||
|
||||
const chain = try PrototypeChain(&types).allocate(allocator);
|
||||
const chain = try PrototypeChain(types).allocate(allocator);
|
||||
inline for (0..types.len) |i| {
|
||||
const ptr = chain.get(i);
|
||||
ptr.* = values[i];
|
||||
@@ -505,8 +498,8 @@ pub fn chainedWithAllocator(allocator: Allocator, values: anytype) !*ChainedLeaf
|
||||
}
|
||||
|
||||
fn ChainedLeaf(comptime Values: type) type {
|
||||
const fields = @typeInfo(Values).@"struct".fields;
|
||||
return fields[fields.len - 1].type;
|
||||
const field_types = @typeInfo(Values).@"struct".field_types;
|
||||
return field_types[field_types.len - 1];
|
||||
}
|
||||
|
||||
pub fn document(self: *Factory, child: anytype) !*@TypeOf(child) {
|
||||
@@ -684,8 +677,8 @@ fn typeInit(comptime Parent: type, value: anytype) Parent.Type {
|
||||
}
|
||||
|
||||
fn subtypeTag(comptime Parent: type, comptime V: type) Parent.Type {
|
||||
for (@typeInfo(Parent.Type).@"enum".fields) |f| {
|
||||
const tag: Parent.Type = @enumFromInt(f.value);
|
||||
for (@typeInfo(Parent.Type).@"enum".field_values) |field_value| {
|
||||
const tag: Parent.Type = @fromBackingInt(field_value);
|
||||
if (Parent.Subtype(tag) == V) return tag;
|
||||
}
|
||||
@compileError(@typeName(V) ++ " is not a subtype of " ++ @typeName(Parent));
|
||||
@@ -699,9 +692,9 @@ fn subtypeTag(comptime Parent: type, comptime V: type) Parent.Type {
|
||||
// This only works because we never have a union with a field S and another
|
||||
// field *S.
|
||||
fn unionFieldName(comptime T: type, comptime V: type) []const u8 {
|
||||
inline for (@typeInfo(T).@"union".fields) |field| {
|
||||
if (reflect.Struct(field.type) == reflect.Struct(V)) {
|
||||
return field.name;
|
||||
inline for (@typeInfo(T).@"union".field_names, @typeInfo(T).@"union".field_types) |field_name, field_type| {
|
||||
if (reflect.Struct(field_type) == reflect.Struct(V)) {
|
||||
return field_name;
|
||||
}
|
||||
}
|
||||
@compileError(@typeName(V) ++ " is not a valid type for " ++ @typeName(T) ++ ".type");
|
||||
|
||||
@@ -696,7 +696,7 @@ pub fn navigate(self: *Frame, request_url: [:0]const u8, opts: NavigateOpts) !vo
|
||||
else if (is_srcdoc)
|
||||
"about:srcdoc"
|
||||
else
|
||||
try self.arena.dupeZ(u8, request_url);
|
||||
try self.arena.dupeSentinel(u8, request_url, 0);
|
||||
|
||||
// even though about:blank navigations may share the same _data_, we
|
||||
// have to do this to make sure window.location is at a unique _address_.
|
||||
@@ -825,7 +825,7 @@ pub fn navigate(self: *Frame, request_url: [:0]const u8, opts: NavigateOpts) !vo
|
||||
|
||||
self.url = blk: {
|
||||
if (URL.isCompleteHTTPUrl(request_url)) {
|
||||
break :blk try self.arena.dupeZ(u8, request_url);
|
||||
break :blk try self.arena.dupeSentinel(u8, request_url, 0);
|
||||
}
|
||||
break :blk try std.mem.concatWithSentinel(self.arena, u8, &.{ "http://", request_url }, 0);
|
||||
};
|
||||
@@ -836,7 +836,7 @@ pub fn navigate(self: *Frame, request_url: [:0]const u8, opts: NavigateOpts) !vo
|
||||
.reason = opts.reason,
|
||||
.method = opts.method,
|
||||
.body = if (opts.body) |b| try self.arena.dupe(u8, b) else null,
|
||||
.header = if (opts.header) |h| try self.arena.dupeZ(u8, h) else null,
|
||||
.header = if (opts.header) |h| try self.arena.dupeSentinel(u8, h, 0) else null,
|
||||
};
|
||||
|
||||
const transfer = try http_client.newRequest(.{
|
||||
@@ -947,7 +947,7 @@ pub fn scheduleNavigation(self: *Frame, request_url: []const u8, opts: NavigateO
|
||||
fn scheduleNavigationWithArena(originator: *Frame, arena: *lp.Arena, request_url: []const u8, opts: NavigateOpts, nt: Navigation) !void {
|
||||
const resolved_url, const is_about_something = blk: {
|
||||
if (URL.isCompleteHTTPUrl(request_url)) {
|
||||
break :blk .{ try arena.dupeZ(u8, request_url), false };
|
||||
break :blk .{ try arena.dupeSentinel(u8, request_url, 0), false };
|
||||
}
|
||||
|
||||
if (std.mem.eql(u8, request_url, "about:blank")) {
|
||||
@@ -1012,7 +1012,7 @@ fn scheduleNavigationWithArena(originator: *Frame, arena: *lp.Arena, request_url
|
||||
const is_fragment_navigation = !std.mem.eql(u8, target.url, resolved_url) and URL.eqlDocument(target.url, resolved_url);
|
||||
if (!opts.force and is_fragment_navigation) {
|
||||
const old_url = target.url;
|
||||
target.url = try target.arena.dupeZ(u8, resolved_url);
|
||||
target.url = try target.arena.dupeSentinel(u8, resolved_url, 0);
|
||||
|
||||
const location = try Location.init(target.url, target);
|
||||
location.acquireRef();
|
||||
@@ -1061,7 +1061,7 @@ fn scheduleNavigationWithArena(originator: *Frame, arena: *lp.Arena, request_url
|
||||
// that from its owner. Only a top-level navigation's initiator is another
|
||||
// document.
|
||||
if (nav_opts.initiator_url == null and target.parent == null and std.mem.startsWith(u8, referrer_source, "http")) {
|
||||
nav_opts.initiator_url = .{ .url = try arena.dupeZ(u8, referrer_source) };
|
||||
nav_opts.initiator_url = .{ .url = try arena.dupeSentinel(u8, referrer_source, 0) };
|
||||
}
|
||||
if (nav_opts.initiator_origin == null) {
|
||||
if (originator.origin) |o| {
|
||||
@@ -1468,7 +1468,7 @@ fn frameHeaderDoneCallback(transfer: *HttpClient.Transfer) !HttpClient.Transfer.
|
||||
const response_url = transfer.req.url;
|
||||
if (std.mem.eql(u8, response_url, self.url) == false) {
|
||||
// would be different than self.url in the case of a redirect
|
||||
self.url = try self.arena.dupeZ(u8, response_url);
|
||||
self.url = try self.arena.dupeSentinel(u8, response_url, 0);
|
||||
self.origin = try URL.getOrigin(self.arena, self.url);
|
||||
}
|
||||
|
||||
@@ -3868,10 +3868,10 @@ pub fn submitForm(self: *Frame, submitter_: ?*Element, form_: ?*Element.Html.For
|
||||
opts.body = buf.written();
|
||||
opts.header = switch (encoding) {
|
||||
.urlencode => "Content-Type: application/x-www-form-urlencoded",
|
||||
.formdata => |b| try std.fmt.allocPrintSentinel(arena.allocator(), "Content-Type: multipart/form-data; boundary={s}", .{b}, 0),
|
||||
.formdata => |b| try arena.allocator().printSentinel("Content-Type: multipart/form-data; boundary={s}", .{b}, 0),
|
||||
// Per WHATWG HTML §4.10.21.6, text/plain submissions include the form's
|
||||
// resolved encoding (accept-charset or document charset).
|
||||
.plaintext => try std.fmt.allocPrintSentinel(arena.allocator(), "Content-Type: text/plain; charset={s}", .{charset}, 0),
|
||||
.plaintext => try arena.allocator().printSentinel("Content-Type: text/plain; charset={s}", .{charset}, 0),
|
||||
};
|
||||
} else {
|
||||
action = try URL.concatQueryString(arena.allocator(), action, buf.written());
|
||||
|
||||
+11
-4
@@ -17,6 +17,7 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
const std = @import("std");
|
||||
const repeat = @import("../string.zig").repeat;
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
const Mime = @This();
|
||||
@@ -28,9 +29,15 @@ charset_len: usize = default_charset_len,
|
||||
is_default_charset: bool = true,
|
||||
|
||||
/// String "UTF-8" continued by null characters.
|
||||
const default_charset = .{ 'U', 'T', 'F', '-', '8' } ++ .{0} ** 36;
|
||||
const default_charset = charsetBuf("UTF-8");
|
||||
const default_charset_len = 5;
|
||||
|
||||
fn charsetBuf(comptime name: []const u8) [41]u8 {
|
||||
var buf: [41]u8 = @splat(0);
|
||||
@memcpy(buf[0..name.len], name);
|
||||
return buf;
|
||||
}
|
||||
|
||||
/// Mime with unknown Content-Type, empty params and empty charset.
|
||||
pub const unknown = Mime{ .content_type = .{ .unknown = {} } };
|
||||
|
||||
@@ -376,7 +383,7 @@ pub fn sniff(body: []const u8) ?Mime {
|
||||
// UTF-16 big-endian BOM
|
||||
return .{
|
||||
.content_type = .{ .text_plain = {} },
|
||||
.charset = .{ 'U', 'T', 'F', '-', '1', '6', 'B', 'E' } ++ .{0} ** 33,
|
||||
.charset = comptime charsetBuf("UTF-16BE"),
|
||||
.charset_len = 8,
|
||||
.is_default_charset = false,
|
||||
};
|
||||
@@ -385,7 +392,7 @@ pub fn sniff(body: []const u8) ?Mime {
|
||||
// UTF-16 little-endian BOM
|
||||
return .{
|
||||
.content_type = .{ .text_plain = {} },
|
||||
.charset = .{ 'U', 'T', 'F', '-', '1', '6', 'L', 'E' } ++ .{0} ** 33,
|
||||
.charset = comptime charsetBuf("UTF-16LE"),
|
||||
.charset_len = 8,
|
||||
.is_default_charset = false,
|
||||
};
|
||||
@@ -1017,7 +1024,7 @@ test "Mime: parse charset (WHATWG parameter semantics)" {
|
||||
try expect(.{ .content_type = .{ .text_html = {} }, .charset = "UTF-8" }, "text/html;charset =gbk");
|
||||
|
||||
// A long preceding parameter doesn't hide a later charset.
|
||||
try expect(.{ .content_type = .{ .text_html = {} }, .charset = "gbk" }, "text/html;" ++ ("a" ** 130) ++ "=x;charset=gbk");
|
||||
try expect(.{ .content_type = .{ .text_html = {} }, .charset = "gbk" }, "text/html;" ++ (repeat("a", 130)) ++ "=x;charset=gbk");
|
||||
}
|
||||
|
||||
test "Mime: isHTML" {
|
||||
|
||||
@@ -406,7 +406,7 @@ pub fn createBlobUrl(self: *Page, blob: *Blob, origin: ?[]const u8, creator_fram
|
||||
var uuid: [36]u8 = undefined;
|
||||
@import("../id.zig").uuidv4(&uuid);
|
||||
|
||||
const url = try std.fmt.allocPrint(self.frame_arena, "blob:{s}/{s}", .{ origin orelse "null", uuid });
|
||||
const url = try self.frame_arena.print("blob:{s}/{s}", .{ origin orelse "null", uuid });
|
||||
try self.blob_urls.put(self.frame_arena, url, .{ .blob = blob, .creator = creator_frame_id });
|
||||
blob.acquireRef();
|
||||
return url;
|
||||
|
||||
@@ -141,7 +141,7 @@ pub fn preloadScript(self: *ScriptManager, element: ?*Element.Html, url: []const
|
||||
const arena = try frame.getArena(.small, "SM.preloadScript");
|
||||
errdefer arena.release();
|
||||
|
||||
const owned_url = try arena.dupeZ(u8, url);
|
||||
const owned_url = try arena.dupeSentinel(u8, url, 0);
|
||||
|
||||
const script = try arena.create(Script);
|
||||
script.* = .{
|
||||
|
||||
@@ -63,7 +63,7 @@ fn buildGreedy(self: SelectorPath, target: *Element) !?[]const u8 {
|
||||
var el = target.parentElement();
|
||||
while (el) |ancestor| {
|
||||
el = ancestor.parentElement();
|
||||
const trial = try std.fmt.allocPrint(self.arena, "{s} {s}", .{ try self.localSegment(ancestor), candidate });
|
||||
const trial = try self.arena.print("{s} {s}", .{ try self.localSegment(ancestor), candidate });
|
||||
const trial_count = self.matchCount(trial);
|
||||
if (trial_count != 0 and trial_count < count) {
|
||||
candidate = trial;
|
||||
@@ -92,7 +92,7 @@ fn buildStrictPath(self: SelectorPath, target: *Element) !?[]const u8 {
|
||||
fn localSegment(self: SelectorPath, el: *Element) ![]const u8 {
|
||||
if (el.getId()) |id| {
|
||||
if (id.len != 0) {
|
||||
const id_sel = try std.fmt.allocPrint(self.arena, "#{s}", .{try CSS.escape(id, self.frame)});
|
||||
const id_sel = try self.arena.print("#{s}", .{try CSS.escape(id, self.frame)});
|
||||
if (self.isFirstMatch(el, id_sel)) return id_sel;
|
||||
}
|
||||
}
|
||||
@@ -101,7 +101,7 @@ fn localSegment(self: SelectorPath, el: *Element) ![]const u8 {
|
||||
|
||||
if (!self.siblingMatches(el, base)) return base;
|
||||
if (try self.hasSegment(el, base)) |sel| return sel;
|
||||
if (nthOfType(el)) |n| return try std.fmt.allocPrint(self.arena, "{s}:nth-of-type({d})", .{ base, n });
|
||||
if (nthOfType(el)) |n| return try self.arena.print("{s}:nth-of-type({d})", .{ base, n });
|
||||
return base;
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ fn hasSegment(self: SelectorPath, el: *Element, base: []const u8) !?[]const u8 {
|
||||
try self.enqueueChildren(&queue, d);
|
||||
|
||||
const desc = (try self.descriptor(d)) orelse continue;
|
||||
const candidate = try std.fmt.allocPrint(self.arena, "{s}:has({s})", .{ base, desc });
|
||||
const candidate = try self.arena.print("{s}:has({s})", .{ base, desc });
|
||||
if (self.isFirstMatch(el, candidate)) return candidate;
|
||||
}
|
||||
return null;
|
||||
@@ -150,7 +150,7 @@ fn qualifyByAttrs(self: SelectorPath, base: []const u8, el: *Element, comptime a
|
||||
inline for (attrs) |attr| {
|
||||
if (el.getAttributeSafe(comptime .wrap(attr))) |value| {
|
||||
if (value.len != 0 and isPlainAttrValue(value)) {
|
||||
sel = try std.fmt.allocPrint(self.arena, "{s}[{s}=\"{s}\"]", .{ sel, attr, value });
|
||||
sel = try self.arena.print("{s}[{s}=\"{s}\"]", .{ sel, attr, value });
|
||||
added = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -312,7 +312,7 @@ fn registerLayerPath(self: *StyleManager, build_arena: Allocator, parent: u16, d
|
||||
fn internAnonymousLayer(self: *StyleManager, build_arena: Allocator, parent: u16) Allocator.Error!u16 {
|
||||
const id = self.next_anon_layer;
|
||||
// \x00{d} isn't a valid layer name, so this can't conflict
|
||||
const name = try std.fmt.allocPrint(build_arena, "\x00{d}", .{id});
|
||||
const name = try build_arena.print("\x00{d}", .{id});
|
||||
self.next_anon_layer = id + 1;
|
||||
return self.internLayer(build_arena, parent, name);
|
||||
}
|
||||
@@ -321,7 +321,7 @@ fn internLayer(self: *StyleManager, build_arena: Allocator, parent: u16, name: [
|
||||
const path = if (parent == NO_LAYER)
|
||||
try build_arena.dupe(u8, name)
|
||||
else
|
||||
try std.fmt.allocPrint(build_arena, "{s}.{s}", .{ self.layers.items[parent].path, name });
|
||||
try build_arena.print("{s}.{s}", .{ self.layers.items[parent].path, name });
|
||||
|
||||
const gop = try self.layer_ids.getOrPut(build_arena, path);
|
||||
if (gop.found_existing) {
|
||||
@@ -738,7 +738,7 @@ fn Group(comptime Spec: type) type {
|
||||
const Declared = Spec.Declared;
|
||||
const Computed = Spec.Computed;
|
||||
const Field = std.meta.FieldEnum(Declared);
|
||||
const fields = std.meta.fieldNames(Declared);
|
||||
const fields = @typeInfo(Declared).@"struct".field_names;
|
||||
|
||||
comptime {
|
||||
// compute copies each declared value into its Computed namesake
|
||||
@@ -1026,7 +1026,7 @@ pub fn ruleInserted(self: *StyleManager, sheet: *CSSStyleSheet, rule: *CSSRule)
|
||||
|
||||
fn appendable(self: *const StyleManager, sheet: *CSSStyleSheet, rule: *CSSRule) bool {
|
||||
const rules = sheet._css_rules orelse return false;
|
||||
if (rules._rules.getLastOrNull() != rule) {
|
||||
if (rules._rules.last() != rule) {
|
||||
return false;
|
||||
}
|
||||
const sheets = self.frame.document._style_sheets orelse return false;
|
||||
@@ -1282,7 +1282,7 @@ const Visibility = struct {
|
||||
// element — per CSS Cascade §6.1 any normal-origin author rule beats UA
|
||||
// origin regardless of specificity, so `.x { display: flex }` on a
|
||||
// `<div class="x" hidden>` must report visible.
|
||||
fn finish(p: *Computed, el: *Element, priorities: *const Priorities(Declared)) void {
|
||||
pub fn finish(p: *Computed, el: *Element, priorities: *const Priorities(Declared)) void {
|
||||
p.author_display = priorities.get(.display) != 0;
|
||||
if (!p.author_display and matchesUaDisplayNoneRule(el)) {
|
||||
p.display = .none;
|
||||
@@ -1367,10 +1367,10 @@ const Declarations = struct {
|
||||
}
|
||||
};
|
||||
|
||||
const group_fields = std.meta.fieldNames(Declarations);
|
||||
const group_fields = @typeInfo(Declarations).@"struct".field_names;
|
||||
|
||||
fn declaresAny(declared: anytype) bool {
|
||||
inline for (comptime std.meta.fieldNames(@TypeOf(declared))) |field| {
|
||||
inline for (@typeInfo(@TypeOf(declared)).@"struct".field_names) |field| {
|
||||
if (@field(declared, field) != null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
+19
-20
@@ -47,7 +47,7 @@ pub fn resolve(
|
||||
}
|
||||
defer href.deinit();
|
||||
|
||||
return allocator.dupeZ(u8, href.slice());
|
||||
return allocator.dupeSentinel(u8, href.slice(), 0);
|
||||
}
|
||||
|
||||
/// Resolves a user-provided "address bar" URL the way curl does. Bare host like
|
||||
@@ -55,7 +55,7 @@ pub fn resolve(
|
||||
pub fn resolveNavigation(allocator: Allocator, url: []const u8, options: ResolveOptions) ![:0]const u8 {
|
||||
return resolve(allocator, "", url, options) catch |err| switch (err) {
|
||||
error.TypeError => {
|
||||
const with_scheme = try std.fmt.allocPrintSentinel(allocator, "http://{s}", .{url}, 0);
|
||||
const with_scheme = try allocator.printSentinel("http://{s}", .{url}, 0);
|
||||
return resolve(allocator, "", with_scheme, options);
|
||||
},
|
||||
else => return err,
|
||||
@@ -241,7 +241,7 @@ pub fn isLoopbackHost(hostname: []const u8) bool {
|
||||
const address = std.Io.net.IpAddress.parseLiteral(host) catch return false;
|
||||
return switch (address) {
|
||||
.ip4 => |ip4| ip4.bytes[0] == 127,
|
||||
.ip6 => |ip6| std.mem.eql(u8, &ip6.bytes, &([_]u8{0} ** 15 ++ [_]u8{1})),
|
||||
.ip6 => |ip6| std.mem.eql(u8, &ip6.bytes, &(@as([15]u8, @splat(0)) ++ [_]u8{1})),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -332,7 +332,7 @@ pub fn getOrigin(allocator: Allocator, raw: [:0]const u8) !?[]const u8 {
|
||||
// Not a port (probably IPv6)
|
||||
if (has_user_info) {
|
||||
// Need to allocate to exclude user info
|
||||
return try std.fmt.allocPrint(allocator, "{s}//{s}", .{ raw[0 .. scheme_end + 1], host_part });
|
||||
return try allocator.print("{s}//{s}", .{ raw[0 .. scheme_end + 1], host_part });
|
||||
}
|
||||
// Can return a slice
|
||||
return raw[0..authority_end];
|
||||
@@ -348,14 +348,14 @@ pub fn getOrigin(allocator: Allocator, raw: [:0]const u8) !?[]const u8 {
|
||||
// Need to allocate to build origin without default port and/or user info
|
||||
const hostname = host_part[0..colon_pos_in_host];
|
||||
if (is_default) {
|
||||
return try std.fmt.allocPrint(allocator, "{s}//{s}", .{ protocol, hostname });
|
||||
return try allocator.print("{s}//{s}", .{ protocol, hostname });
|
||||
} else {
|
||||
return try std.fmt.allocPrint(allocator, "{s}//{s}", .{ protocol, host_part });
|
||||
return try allocator.print("{s}//{s}", .{ protocol, host_part });
|
||||
}
|
||||
}
|
||||
} else if (has_user_info) {
|
||||
// No port, but has user info - need to allocate
|
||||
return try std.fmt.allocPrint(allocator, "{s}//{s}", .{ raw[0 .. scheme_end + 1], host_part });
|
||||
return try allocator.print("{s}//{s}", .{ raw[0 .. scheme_end + 1], host_part });
|
||||
}
|
||||
|
||||
// Common case: no user info, no default port - return slice (zero allocation!)
|
||||
@@ -409,7 +409,7 @@ fn buildUrl(
|
||||
search: []const u8,
|
||||
hash: []const u8,
|
||||
) ![:0]const u8 {
|
||||
return std.fmt.allocPrintSentinel(allocator, "{s}//{s}{s}{s}{s}", .{
|
||||
return allocator.printSentinel("{s}//{s}{s}{s}{s}", .{
|
||||
protocol,
|
||||
host,
|
||||
pathname,
|
||||
@@ -426,7 +426,7 @@ pub fn setProtocol(current: [:0]const u8, value: []const u8, allocator: Allocato
|
||||
|
||||
// Add : suffix if not present
|
||||
const protocol = if (value.len > 0 and value[value.len - 1] != ':')
|
||||
try std.fmt.allocPrint(allocator, "{s}:", .{value})
|
||||
try allocator.print("{s}:", .{value})
|
||||
else
|
||||
value;
|
||||
|
||||
@@ -455,7 +455,7 @@ pub fn setHost(current: [:0]const u8, value: []const u8, allocator: Allocator) !
|
||||
// No port in new value - preserve existing port
|
||||
const current_port = getPort(current);
|
||||
if (current_port.len > 0) {
|
||||
break :blk try std.fmt.allocPrint(allocator, "{s}:{s}", .{ value, current_port });
|
||||
break :blk try allocator.print("{s}:{s}", .{ value, current_port });
|
||||
}
|
||||
break :blk value;
|
||||
};
|
||||
@@ -466,7 +466,7 @@ pub fn setHost(current: [:0]const u8, value: []const u8, allocator: Allocator) !
|
||||
pub fn setHostname(current: [:0]const u8, value: []const u8, allocator: Allocator) ![:0]const u8 {
|
||||
const current_port = getPort(current);
|
||||
const new_host = if (current_port.len > 0)
|
||||
try std.fmt.allocPrint(allocator, "{s}:{s}", .{ value, current_port })
|
||||
try allocator.print("{s}:{s}", .{ value, current_port })
|
||||
else
|
||||
value;
|
||||
|
||||
@@ -492,7 +492,7 @@ pub fn setPort(current: [:0]const u8, value: ?[]const u8, allocator: Allocator)
|
||||
if (std.mem.eql(u8, protocol, "http:") and std.mem.eql(u8, port_str, "80")) {
|
||||
break :blk hostname;
|
||||
}
|
||||
break :blk try std.fmt.allocPrint(allocator, "{s}:{s}", .{ hostname, port_str });
|
||||
break :blk try allocator.print("{s}:{s}", .{ hostname, port_str });
|
||||
} else hostname;
|
||||
|
||||
return buildUrl(allocator, protocol, new_host, pathname, search, hash);
|
||||
@@ -508,7 +508,7 @@ pub fn setPathname(current: [:0]const u8, value: []const u8, allocator: Allocato
|
||||
|
||||
// Add / prefix if not present and value is not empty
|
||||
const pathname = if (encoded.len > 0 and encoded[0] != '/')
|
||||
try std.fmt.allocPrint(allocator, "/{s}", .{encoded})
|
||||
try allocator.print("/{s}", .{encoded})
|
||||
else
|
||||
encoded;
|
||||
|
||||
@@ -525,7 +525,7 @@ pub fn setSearch(current: [:0]const u8, value: []const u8, allocator: Allocator)
|
||||
|
||||
// Add ? prefix if not present and value is not empty
|
||||
const search = if (encoded.len > 0 and value[0] != '?')
|
||||
try std.fmt.allocPrint(allocator, "?{s}", .{encoded})
|
||||
try allocator.print("?{s}", .{encoded})
|
||||
else
|
||||
encoded;
|
||||
|
||||
@@ -542,7 +542,7 @@ pub fn setHash(current: [:0]const u8, value: []const u8, allocator: Allocator) !
|
||||
|
||||
// Add # prefix if not present and value is not empty
|
||||
const hash = if (encoded.len > 0 and encoded[0] != '#')
|
||||
try std.fmt.allocPrint(allocator, "#{s}", .{encoded})
|
||||
try allocator.print("#{s}", .{encoded})
|
||||
else
|
||||
encoded;
|
||||
|
||||
@@ -586,7 +586,7 @@ fn buildUrlWithUserInfo(
|
||||
if (username.len == 0 and password.len == 0) {
|
||||
return buildUrl(allocator, protocol, host, pathname, search, hash);
|
||||
} else if (password.len == 0) {
|
||||
return std.fmt.allocPrintSentinel(allocator, "{s}//{s}@{s}{s}{s}{s}", .{
|
||||
return allocator.printSentinel("{s}//{s}@{s}{s}{s}{s}", .{
|
||||
protocol,
|
||||
username,
|
||||
host,
|
||||
@@ -595,7 +595,7 @@ fn buildUrlWithUserInfo(
|
||||
hash,
|
||||
}, 0);
|
||||
} else {
|
||||
return std.fmt.allocPrintSentinel(allocator, "{s}//{s}:{s}@{s}{s}{s}{s}", .{
|
||||
return allocator.printSentinel("{s}//{s}:{s}@{s}{s}{s}{s}", .{
|
||||
protocol,
|
||||
username,
|
||||
password,
|
||||
@@ -609,7 +609,7 @@ fn buildUrlWithUserInfo(
|
||||
|
||||
pub fn concatQueryString(arena: Allocator, url: []const u8, query_string: []const u8) ![:0]const u8 {
|
||||
if (query_string.len == 0) {
|
||||
return arena.dupeZ(u8, url);
|
||||
return arena.dupeSentinel(u8, url, 0);
|
||||
}
|
||||
|
||||
var buf: std.ArrayList(u8) = .empty;
|
||||
@@ -633,8 +633,7 @@ pub fn concatQueryString(arena: Allocator, url: []const u8, query_string: []cons
|
||||
|
||||
pub fn getRobotsUrl(arena: Allocator, url: [:0]const u8) ![:0]const u8 {
|
||||
const origin = try getOrigin(arena, url) orelse return error.NoOrigin;
|
||||
return try std.fmt.allocPrintSentinel(
|
||||
arena,
|
||||
return try arena.printSentinel(
|
||||
"{s}/robots.txt",
|
||||
.{origin},
|
||||
0,
|
||||
|
||||
@@ -102,7 +102,7 @@ fn describe(node: *Node) []const u8 {
|
||||
const S = struct {
|
||||
threadlocal var buf: [96]u8 = undefined;
|
||||
};
|
||||
return std.fmt.bufPrint(&S.buf, "{s}.{s}#{s}", .{ @tagName(el.getTag()), el.getClassName() orelse "", el.getId() orelse "" }) catch S.buf[0..];
|
||||
return std.mem.print(&S.buf, "{s}.{s}#{s}", .{ @tagName(el.getTag()), el.getClassName() orelse "", el.getId() orelse "" }) catch S.buf[0..];
|
||||
}
|
||||
|
||||
const Stats = struct {
|
||||
|
||||
@@ -55,7 +55,7 @@ pub fn parse(arena: Allocator, url: []const u8) !Parsed {
|
||||
content_type = "text/plain;charset=US-ASCII";
|
||||
} else if (content_type[0] == ';') {
|
||||
// e.g. "data:;charset=utf-8,x" -> "text/plain;charset=utf-8"
|
||||
content_type = try std.fmt.allocPrint(arena, "text/plain{s}", .{content_type});
|
||||
content_type = try arena.print("text/plain{s}", .{content_type});
|
||||
}
|
||||
|
||||
const body_text = try URL.unescape(arena, encoded_body);
|
||||
|
||||
@@ -57,7 +57,7 @@ pub fn allowed(frame: *const Frame, transfer: *HttpClient.Transfer) bool {
|
||||
fn hasFrameAncestors(csp: []const u8) bool {
|
||||
const name = "frame-ancestors";
|
||||
var pos: usize = 0;
|
||||
while (std.ascii.indexOfIgnoreCasePos(csp, pos, name)) |start| {
|
||||
while (std.ascii.findIgnoreCasePos(csp, pos, name)) |start| {
|
||||
pos = start + name.len;
|
||||
|
||||
// A directive name starts a policy (',') or a directive (';'), so
|
||||
|
||||
@@ -1156,7 +1156,7 @@ fn parserAttributeName(frame: *Frame, qname: Parser.QualName) ![]const u8 {
|
||||
if (prefix.len == 0) {
|
||||
return local;
|
||||
}
|
||||
return std.fmt.allocPrint(frame.local_arena, "{s}:{s}", .{ prefix, local });
|
||||
return frame.local_arena.print("{s}:{s}", .{ prefix, local });
|
||||
}
|
||||
|
||||
// Called when `new MyElement()` is invoked directly in JS (not via the
|
||||
@@ -1300,7 +1300,7 @@ fn isXmlNameChar(c: u21) bool {
|
||||
(c >= 0x203F and c <= 0x2040);
|
||||
}
|
||||
|
||||
fn asUint(comptime string: anytype) std.meta.Int(
|
||||
fn asUint(comptime string: anytype) @Int(
|
||||
.unsigned,
|
||||
@bitSizeOf(@TypeOf(string.*)) - 8, // (- 8) to exclude sentinel 0
|
||||
) {
|
||||
|
||||
@@ -113,7 +113,7 @@ fn exifOrientation(segment: []const u8) u16 {
|
||||
}
|
||||
|
||||
const tiff = segment[6..];
|
||||
const endian: std.builtin.Endian = if (std.mem.eql(u8, tiff[0..2], "II"))
|
||||
const endian: std.lang.Endian = if (std.mem.eql(u8, tiff[0..2], "II"))
|
||||
.little
|
||||
else if (std.mem.eql(u8, tiff[0..2], "MM"))
|
||||
.big
|
||||
|
||||
@@ -238,7 +238,7 @@ fn walkInteractive(
|
||||
if (filter.name) |nf| {
|
||||
const n = name orelse continue;
|
||||
const hit = switch (nf) {
|
||||
.substring => |s| std.ascii.indexOfIgnoreCase(n, s) != null,
|
||||
.substring => |s| std.ascii.findIgnoreCase(n, s) != null,
|
||||
.regex => |re| re.matches(n),
|
||||
};
|
||||
if (!hit) continue;
|
||||
|
||||
+25
-25
@@ -105,7 +105,7 @@ pub fn deinit(self: *Caller) void {
|
||||
// Unlike call_arena, local_arena is reset on _every_ return, since its
|
||||
// users promise not to hold data across a nested call. In debug, free
|
||||
// back to the backing allocator so a stale pointer trips the
|
||||
// DebugAllocator's use-after-free detection; in release, retain a buffer
|
||||
// SafeAllocator's use-after-free detection; in release, retain a buffer
|
||||
// to avoid realloc churn.
|
||||
{
|
||||
const local_arena: *ArenaAllocator = @ptrCast(@alignCast(ctx.local_arena.ptr));
|
||||
@@ -202,7 +202,7 @@ fn _getIndex(comptime T: type, local: *const Local, func: anytype, idx: u32, inf
|
||||
var args: ParameterTypes(F) = undefined;
|
||||
@field(args, "0") = try TaggedOpaque.fromJS(*T, info.getThis());
|
||||
@field(args, "1") = idx;
|
||||
if (@typeInfo(F).@"fn".params.len == 3) {
|
||||
if (@typeInfo(F).@"fn".param_types.len == 3) {
|
||||
@field(args, "2") = getGlobalArg(@TypeOf(args.@"2"), local.ctx);
|
||||
}
|
||||
const ret = @call(.auto, func, args);
|
||||
@@ -228,7 +228,7 @@ fn _getNamedIndex(comptime T: type, local: *const Local, func: anytype, name: *c
|
||||
var args: ParameterTypes(F) = undefined;
|
||||
@field(args, "0") = try TaggedOpaque.fromJS(*T, info.getThis());
|
||||
@field(args, "1") = try nameToString(local, @TypeOf(args.@"1"), name);
|
||||
if (@typeInfo(F).@"fn".params.len == 3) {
|
||||
if (@typeInfo(F).@"fn".param_types.len == 3) {
|
||||
@field(args, "2") = getGlobalArg(@TypeOf(args.@"2"), local.ctx);
|
||||
}
|
||||
const ret = @call(.auto, func, args);
|
||||
@@ -255,7 +255,7 @@ fn _setIndex(comptime T: type, local: *const Local, func: anytype, idx: u32, js_
|
||||
@field(args, "0") = try TaggedOpaque.fromJS(*T, info.getThis());
|
||||
@field(args, "1") = idx;
|
||||
@field(args, "2") = try local.jsValueToZig(@TypeOf(@field(args, "2")), js_value);
|
||||
if (@typeInfo(F).@"fn".params.len == 4) {
|
||||
if (@typeInfo(F).@"fn".param_types.len == 4) {
|
||||
@field(args, "3") = getGlobalArg(@TypeOf(args.@"3"), local.ctx);
|
||||
}
|
||||
const ret = @call(.auto, func, args);
|
||||
@@ -281,7 +281,7 @@ fn _deleteOrDefineIndex(comptime T: type, local: *const Local, func: anytype, id
|
||||
var args: ParameterTypes(F) = undefined;
|
||||
@field(args, "0") = try TaggedOpaque.fromJS(*T, info.getThis());
|
||||
@field(args, "1") = idx;
|
||||
if (@typeInfo(F).@"fn".params.len == 3) {
|
||||
if (@typeInfo(F).@"fn".param_types.len == 3) {
|
||||
@field(args, "2") = getGlobalArg(@TypeOf(args.@"2"), local.ctx);
|
||||
}
|
||||
const ret = @call(.auto, func, args);
|
||||
@@ -308,7 +308,7 @@ fn _setNamedIndex(comptime T: type, local: *const Local, func: anytype, name: *c
|
||||
@field(args, "0") = try TaggedOpaque.fromJS(*T, info.getThis());
|
||||
@field(args, "1") = try nameToString(local, @TypeOf(args.@"1"), name);
|
||||
@field(args, "2") = try local.jsValueToZig(@TypeOf(@field(args, "2")), js_value);
|
||||
if (@typeInfo(F).@"fn".params.len == 4) {
|
||||
if (@typeInfo(F).@"fn".param_types.len == 4) {
|
||||
@field(args, "3") = getGlobalArg(@TypeOf(args.@"3"), local.ctx);
|
||||
}
|
||||
const ret = @call(.auto, func, args);
|
||||
@@ -334,7 +334,7 @@ fn _deleteOrDefineNamedIndex(comptime T: type, local: *const Local, func: anytyp
|
||||
var args: ParameterTypes(F) = undefined;
|
||||
@field(args, "0") = try TaggedOpaque.fromJS(*T, info.getThis());
|
||||
@field(args, "1") = try nameToString(local, @TypeOf(args.@"1"), name);
|
||||
if (@typeInfo(F).@"fn".params.len == 3) {
|
||||
if (@typeInfo(F).@"fn".param_types.len == 3) {
|
||||
@field(args, "2") = getGlobalArg(@TypeOf(args.@"2"), local.ctx);
|
||||
}
|
||||
const ret = @call(.auto, func, args);
|
||||
@@ -359,7 +359,7 @@ fn _getEnumerator(comptime T: type, local: *const Local, func: anytype, info: Pr
|
||||
const F = @TypeOf(func);
|
||||
var args: ParameterTypes(F) = undefined;
|
||||
@field(args, "0") = try TaggedOpaque.fromJS(*T, info.getThis());
|
||||
if (@typeInfo(F).@"fn".params.len == 2) {
|
||||
if (@typeInfo(F).@"fn".param_types.len == 2) {
|
||||
@field(args, "1") = getGlobalArg(@TypeOf(args.@"1"), local.ctx);
|
||||
}
|
||||
const ret = @call(.auto, func, args);
|
||||
@@ -385,7 +385,7 @@ fn _getIndexQuery(comptime T: type, local: *const Local, func: anytype, idx: u32
|
||||
var args: ParameterTypes(F) = undefined;
|
||||
@field(args, "0") = try TaggedOpaque.fromJS(*T, info.getThis());
|
||||
@field(args, "1") = idx;
|
||||
if (@typeInfo(F).@"fn".params.len == 3) {
|
||||
if (@typeInfo(F).@"fn".param_types.len == 3) {
|
||||
@field(args, "2") = getGlobalArg(@TypeOf(args.@"2"), local.ctx);
|
||||
}
|
||||
return queryReturn(local, @call(.auto, func, args), info);
|
||||
@@ -410,7 +410,7 @@ fn _getNamedQuery(comptime T: type, local: *const Local, func: anytype, name: *c
|
||||
var args: ParameterTypes(F) = undefined;
|
||||
@field(args, "0") = try TaggedOpaque.fromJS(*T, info.getThis());
|
||||
@field(args, "1") = try nameToString(local, @TypeOf(args.@"1"), name);
|
||||
if (@typeInfo(F).@"fn".params.len == 3) {
|
||||
if (@typeInfo(F).@"fn".param_types.len == 3) {
|
||||
@field(args, "2") = getGlobalArg(@TypeOf(args.@"2"), local.ctx);
|
||||
}
|
||||
return queryReturn(local, @call(.auto, func, args), info);
|
||||
@@ -483,8 +483,8 @@ fn returnsBool(comptime F: type) bool {
|
||||
}
|
||||
|
||||
fn isInErrorSet(err: anyerror, comptime T: type) bool {
|
||||
inline for (@typeInfo(T).error_set.?) |e| {
|
||||
if (err == @field(anyerror, e.name)) return true;
|
||||
inline for (@typeInfo(T).error_set.error_names.?) |name| {
|
||||
if (err == @field(anyerror, name)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -666,11 +666,11 @@ fn serializeFunctionArgs(local: *const Local, info: FunctionCallbackInfo) ![]con
|
||||
// Takes a function, and returns a tuple for its argument. Used when we
|
||||
// @call a function
|
||||
fn ParameterTypes(comptime F: type) type {
|
||||
const params = @typeInfo(F).@"fn".params;
|
||||
var types: [params.len]type = undefined;
|
||||
const param_types = @typeInfo(F).@"fn".param_types;
|
||||
var types: [param_types.len]type = undefined;
|
||||
|
||||
inline for (params, 0..) |param, i| {
|
||||
types[i] = param.type.?;
|
||||
inline for (param_types, 0..) |param_type, i| {
|
||||
types[i] = param_type.?;
|
||||
}
|
||||
|
||||
return @Tuple(&types);
|
||||
@@ -1018,7 +1018,7 @@ pub const Function = struct {
|
||||
fn getArgs(comptime F: type, comptime offset: usize, local: *const Local, info: FunctionCallbackInfo) !ParameterTypes(F) {
|
||||
var args: ParameterTypes(F) = undefined;
|
||||
|
||||
const params = @typeInfo(F).@"fn".params[offset..];
|
||||
const params = @typeInfo(F).@"fn".param_types[offset..];
|
||||
// Except for the constructor, the first parameter is always `self`
|
||||
// This isn't something we'll bind from JS, so skip it.
|
||||
const params_to_map = blk: {
|
||||
@@ -1029,7 +1029,7 @@ fn getArgs(comptime F: type, comptime offset: usize, local: *const Local, info:
|
||||
// If the last parameter is Frame/Page/Execution, set it from
|
||||
// context and exclude it from our params slice, because we don't want
|
||||
// to bind it to a JS argument.
|
||||
const LastParamType = params[params.len - 1].type.?;
|
||||
const LastParamType = params[params.len - 1].?;
|
||||
if (comptime isFrame(LastParamType) or isPage(LastParamType) or isExecution(LastParamType)) {
|
||||
@field(args, tupleFieldName(params.len - 1 + offset)) = getGlobalArg(LastParamType, local.ctx);
|
||||
break :blk params[0 .. params.len - 1];
|
||||
@@ -1053,7 +1053,7 @@ fn getArgs(comptime F: type, comptime offset: usize, local: *const Local, info:
|
||||
// is a slice AND the corresponding javascript parameter is
|
||||
// NOT an an array, then we'll treat it as a variadic.
|
||||
|
||||
const last_parameter_type = params_to_map[params_to_map.len - 1].type.?;
|
||||
const last_parameter_type = params_to_map[params_to_map.len - 1].?;
|
||||
const last_parameter_type_info = @typeInfo(last_parameter_type);
|
||||
if (last_parameter_type_info == .pointer and last_parameter_type_info.pointer.size == .slice) {
|
||||
const slice_type = last_parameter_type_info.pointer.child;
|
||||
@@ -1075,7 +1075,7 @@ fn getArgs(comptime F: type, comptime offset: usize, local: *const Local, info:
|
||||
}
|
||||
}
|
||||
|
||||
inline for (params_to_map, 0..) |param, i| {
|
||||
inline for (params_to_map, 0..) |param_type, i| {
|
||||
const field_index = comptime i + offset;
|
||||
if (comptime i == params_to_map.len - 1) {
|
||||
if (is_variadic) {
|
||||
@@ -1083,14 +1083,14 @@ fn getArgs(comptime F: type, comptime offset: usize, local: *const Local, info:
|
||||
}
|
||||
}
|
||||
|
||||
if (comptime isFrame(param.type.?)) {
|
||||
if (comptime isFrame(param_type.?)) {
|
||||
@compileError("Frame must be the last parameter: " ++ @typeName(F));
|
||||
} else if (comptime isPage(param.type.?)) {
|
||||
} else if (comptime isPage(param_type.?)) {
|
||||
@compileError("Page must be the last parameter: " ++ @typeName(F));
|
||||
} else if (comptime isExecution(param.type.?)) {
|
||||
} else if (comptime isExecution(param_type.?)) {
|
||||
@compileError("Execution must be the last parameter: " ++ @typeName(F));
|
||||
} else if (i >= js_parameter_count) {
|
||||
if (@typeInfo(param.type.?) != .optional) {
|
||||
if (@typeInfo(param_type.?) != .optional) {
|
||||
return error.InvalidArgument;
|
||||
}
|
||||
@field(args, tupleFieldName(field_index)) = null;
|
||||
@@ -1102,7 +1102,7 @@ fn getArgs(comptime F: type, comptime offset: usize, local: *const Local, info:
|
||||
// to the right DOMException. Compared by name because the per-
|
||||
// type instantiation of jsValueToZig may not include such errors
|
||||
// in its inferred error set.
|
||||
@field(args, tupleFieldName(field_index)) = local.jsValueToZig(param.type.?, js_val) catch |err| {
|
||||
@field(args, tupleFieldName(field_index)) = local.jsValueToZig(param_type.?, js_val) catch |err| {
|
||||
if (err == error.JsException) {
|
||||
// an exception thrown by user code (e.g. a toString
|
||||
// getter) is pending; propagate it untouched
|
||||
|
||||
@@ -367,7 +367,7 @@ pub fn module(self: *Context, comptime want_result: bool, local: *const js.Local
|
||||
}
|
||||
}
|
||||
|
||||
const owned_url = try arena.dupeZ(u8, url);
|
||||
const owned_url = try arena.dupeSentinel(u8, url, 0);
|
||||
if (cacheable and !gop.found_existing) {
|
||||
gop.key_ptr.* = owned_url;
|
||||
}
|
||||
@@ -529,7 +529,7 @@ fn postCompileModule(self: *Context, mod: js.Module, url: [:0]const u8, local: *
|
||||
};
|
||||
const nested_gop = try self.module_cache.getOrPut(self.arena.allocator(), normalized_specifier);
|
||||
if (!nested_gop.found_existing) {
|
||||
const owned_specifier = try self.arena.dupeZ(u8, normalized_specifier);
|
||||
const owned_specifier = try self.arena.dupeSentinel(u8, normalized_specifier, 0);
|
||||
nested_gop.key_ptr.* = owned_specifier;
|
||||
nested_gop.value_ptr.* = .{};
|
||||
try script_manager.preloadImport(owned_specifier, url, .{});
|
||||
@@ -537,7 +537,7 @@ fn postCompileModule(self: *Context, mod: js.Module, url: [:0]const u8, local: *
|
||||
// Entry exists but module failed to compile previously.
|
||||
// The imported_modules entry may have been consumed, so
|
||||
// re-preload to ensure waitForImport can find it.
|
||||
// Key was stored via dupeZ so it has a sentinel in memory.
|
||||
// Key was stored via dupeSentinel so it has a sentinel in memory.
|
||||
const key = nested_gop.key_ptr.*;
|
||||
const key_z: [:0]const u8 = key.ptr[0..key.len :0];
|
||||
try script_manager.preloadImport(key_z, url, .{});
|
||||
|
||||
@@ -196,12 +196,12 @@ fn _tryCallWithThis(self: *const Function, comptime T: type, this: anytype, args
|
||||
|
||||
const js_args: []const *const v8.Value = switch (@typeInfo(@TypeOf(aargs))) {
|
||||
.@"struct" => |s| blk: {
|
||||
const fields = s.fields;
|
||||
var js_args: [fields.len]*const v8.Value = undefined;
|
||||
inline for (fields, 0..) |f, i| {
|
||||
js_args[i] = (try local.zigValueToJs(@field(aargs, f.name), .{})).handle;
|
||||
const field_names = s.field_names;
|
||||
var js_args: [field_names.len]*const v8.Value = undefined;
|
||||
inline for (field_names, 0..) |field_name, i| {
|
||||
js_args[i] = (try local.zigValueToJs(@field(aargs, field_name), .{})).handle;
|
||||
}
|
||||
const cargs: [fields.len]*const v8.Value = js_args;
|
||||
const cargs: [field_names.len]*const v8.Value = js_args;
|
||||
break :blk &cargs;
|
||||
},
|
||||
.pointer => blk: {
|
||||
|
||||
@@ -48,7 +48,7 @@ pub const MemoryPressureLevel = enum(u32) {
|
||||
};
|
||||
|
||||
pub fn memoryPressureNotification(self: Isolate, level: MemoryPressureLevel) void {
|
||||
v8.v8__Isolate__MemoryPressureNotification(self.handle, @intFromEnum(level));
|
||||
v8.v8__Isolate__MemoryPressureNotification(self.handle, @backingInt(level));
|
||||
}
|
||||
|
||||
// Tells V8 how much native memory is hanging off objects in this isolate, so
|
||||
|
||||
+35
-35
@@ -496,9 +496,9 @@ pub fn zigValueToJs(self: *const Local, value: anytype, comptime opts: CallOpts)
|
||||
|
||||
if (s.is_tuple) {
|
||||
// return the tuple struct as an array
|
||||
var js_arr = self.newArray(@intCast(s.fields.len));
|
||||
inline for (s.fields, 0..) |f, i| {
|
||||
if (try js_arr.set(@intCast(i), @field(value, f.name), opts) == false) {
|
||||
var js_arr = self.newArray(@intCast(s.field_names.len));
|
||||
inline for (s.field_names, 0..) |field_name, i| {
|
||||
if (try js_arr.set(@intCast(i), @field(value, field_name), opts) == false) {
|
||||
return error.FailedToCreateArray;
|
||||
}
|
||||
}
|
||||
@@ -506,8 +506,8 @@ pub fn zigValueToJs(self: *const Local, value: anytype, comptime opts: CallOpts)
|
||||
}
|
||||
|
||||
const js_obj = self.newObject();
|
||||
inline for (s.fields) |f| {
|
||||
if (try js_obj.set(f.name, @field(value, f.name), opts) == false) {
|
||||
inline for (s.field_names) |field_name| {
|
||||
if (try js_obj.set(field_name, @field(value, field_name), opts) == false) {
|
||||
return error.CreateObjectFailure;
|
||||
}
|
||||
}
|
||||
@@ -518,9 +518,9 @@ pub fn zigValueToJs(self: *const Local, value: anytype, comptime opts: CallOpts)
|
||||
return self.zigJsonToJs(value);
|
||||
}
|
||||
if (un.tag_type) |UnionTagType| {
|
||||
inline for (un.fields) |field| {
|
||||
if (value == @field(UnionTagType, field.name)) {
|
||||
return self.zigValueToJs(@field(value, field.name), opts);
|
||||
inline for (un.field_names) |field_name| {
|
||||
if (value == @field(UnionTagType, field_name)) {
|
||||
return self.zigValueToJs(@field(value, field_name), opts);
|
||||
}
|
||||
}
|
||||
unreachable;
|
||||
@@ -695,13 +695,13 @@ pub fn jsValueToZig(self: *const Local, comptime T: type, js_val: js.Value) !T {
|
||||
// compatible with. A compatible field has higher precedence
|
||||
// than a coercible, but still isn't a perfect match.
|
||||
var compatible_index: ?usize = null;
|
||||
inline for (u.fields, 0..) |field, i| {
|
||||
switch (try self.probeJsValueToZig(field.type, js_val)) {
|
||||
.value => |v| return @unionInit(T, field.name, v),
|
||||
inline for (u.field_names, u.field_types, 0..) |field_name, field_type, i| {
|
||||
switch (try self.probeJsValueToZig(field_type, js_val)) {
|
||||
.value => |v| return @unionInit(T, field_name, v),
|
||||
.ok => {
|
||||
// a perfect match like above case, except the probing
|
||||
// didn't get the value for us.
|
||||
return @unionInit(T, field.name, try self.jsValueToZig(field.type, js_val));
|
||||
return @unionInit(T, field_name, try self.jsValueToZig(field_type, js_val));
|
||||
},
|
||||
.coerce => if (coerce_index == null) {
|
||||
coerce_index = i;
|
||||
@@ -715,9 +715,9 @@ pub fn jsValueToZig(self: *const Local, comptime T: type, js_val: js.Value) !T {
|
||||
|
||||
// We didn't find a perfect match.
|
||||
const closest = compatible_index orelse coerce_index orelse return error.InvalidArgument;
|
||||
inline for (u.fields, 0..) |field, i| {
|
||||
inline for (u.field_names, u.field_types, 0..) |field_name, field_type, i| {
|
||||
if (i == closest) {
|
||||
return @unionInit(T, field.name, try self.jsValueToZig(field.type, js_val));
|
||||
return @unionInit(T, field_name, try self.jsValueToZig(field_type, js_val));
|
||||
}
|
||||
}
|
||||
unreachable;
|
||||
@@ -767,7 +767,7 @@ fn jsValueToStruct(self: *const Local, comptime T: type, js_val: js.Value) !?T {
|
||||
js.TypedArray(f32), js.TypedArray(f64),
|
||||
// zig fmt: on
|
||||
=> {
|
||||
const ValueType = @typeInfo(std.meta.fieldInfo(T, .values).type).pointer.child;
|
||||
const ValueType = @typeInfo(@FieldType(T, "values")).pointer.child;
|
||||
const arr = (try jsValueToTypedArray(ValueType, js_val)) orelse return null;
|
||||
return .{ .values = arr };
|
||||
},
|
||||
@@ -846,27 +846,27 @@ fn jsValueToStruct(self: *const Local, comptime T: type, js_val: js.Value) !?T {
|
||||
const js_obj = js_val.toObject();
|
||||
|
||||
var value: T = undefined;
|
||||
inline for (@typeInfo(T).@"struct".fields) |field| {
|
||||
if (comptime std.mem.eql(u8, field.name, dictionary_group_marker)) {
|
||||
const info = @typeInfo(T).@"struct";
|
||||
inline for (info.field_names, info.field_types, info.field_attrs) |name, FieldType, attrs| {
|
||||
if (comptime std.mem.eql(u8, name, dictionary_group_marker)) {
|
||||
continue;
|
||||
}
|
||||
const name = field.name;
|
||||
const key = isolate.initStringHandle(name);
|
||||
if (js_obj.has(key)) {
|
||||
const member = try js_obj.get(key);
|
||||
const default_for_undefined = comptime field.defaultValue();
|
||||
const default_for_undefined = comptime attrs.defaultValue(FieldType);
|
||||
@field(value, name) = blk: {
|
||||
if (comptime default_for_undefined) |dflt| {
|
||||
if (member.isUndefined()) {
|
||||
break :blk dflt;
|
||||
}
|
||||
}
|
||||
break :blk try self.jsValueToZig(field.type, member);
|
||||
break :blk try self.jsValueToZig(FieldType, member);
|
||||
};
|
||||
} else if (@typeInfo(field.type) == .optional) {
|
||||
} else if (@typeInfo(FieldType) == .optional) {
|
||||
@field(value, name) = null;
|
||||
} else {
|
||||
const dflt = field.defaultValue() orelse return null;
|
||||
const dflt = attrs.defaultValue(FieldType) orelse return null;
|
||||
@field(value, name) = dflt;
|
||||
}
|
||||
}
|
||||
@@ -883,10 +883,10 @@ pub const dictionary_group_marker = "js_grouped_dictionary";
|
||||
// fire in a predictable order. Could probably comptime this to work
|
||||
// automatically, but it's a lot easier just to check it and ask for a manual fix.
|
||||
pub fn assertDictionaryFieldOrder(comptime T: type) void {
|
||||
const fields = @typeInfo(T).@"struct".fields;
|
||||
const field_names = @typeInfo(T).@"struct".field_names;
|
||||
var i: usize = 1;
|
||||
while (i < fields.len) : (i += 1) {
|
||||
if (std.mem.order(u8, fields[i - 1].name, fields[i].name) == .gt) {
|
||||
while (i < field_names.len) : (i += 1) {
|
||||
if (std.mem.order(u8, field_names[i - 1], field_names[i]) == .gt) {
|
||||
@compileError("dictionary fields must be declared in lexicographic order: " ++ @typeName(T));
|
||||
}
|
||||
}
|
||||
@@ -1350,17 +1350,17 @@ fn resolveValue(value: anytype) Resolved {
|
||||
}
|
||||
|
||||
const U = @typeInfo(@TypeOf(value._type)).@"union";
|
||||
inline for (U.fields) |field| {
|
||||
if (value._type == @field(U.tag_type.?, field.name)) {
|
||||
const child = switch (@typeInfo(field.type)) {
|
||||
.pointer => @field(value._type, field.name),
|
||||
.@"struct" => &@field(value._type, field.name),
|
||||
inline for (U.field_names, U.field_types) |field_name, field_type| {
|
||||
if (value._type == @field(U.tag_type.?, field_name)) {
|
||||
const child = switch (@typeInfo(field_type)) {
|
||||
.pointer => @field(value._type, field_name),
|
||||
.@"struct" => &@field(value._type, field_name),
|
||||
.void => {
|
||||
// Unusual case, but the Event (and maybe others) can be
|
||||
// returned as-is. In that case, it has a dummy void type.
|
||||
return resolveT(T, value);
|
||||
},
|
||||
else => @compileError(@typeName(field.type) ++ " has an unsupported _type field"),
|
||||
else => @compileError(@typeName(field_type) ++ " has an unsupported _type field"),
|
||||
};
|
||||
return resolveValue(child);
|
||||
}
|
||||
@@ -1573,8 +1573,8 @@ pub fn ToLocalReturnType(comptime T: type) type {
|
||||
if (@typeInfo(T) == .optional) {
|
||||
const GlobalType = @typeInfo(T).optional.child;
|
||||
const struct_info = @typeInfo(GlobalType).@"struct";
|
||||
inline for (struct_info.decls) |decl| {
|
||||
if (std.mem.eql(u8, decl.name, "local")) {
|
||||
inline for (struct_info.decl_names) |decl_name| {
|
||||
if (std.mem.eql(u8, decl_name, "local")) {
|
||||
const Fn = @TypeOf(@field(GlobalType, "local"));
|
||||
const fn_info = @typeInfo(Fn).@"fn";
|
||||
return ?fn_info.return_type.?;
|
||||
@@ -1583,8 +1583,8 @@ pub fn ToLocalReturnType(comptime T: type) type {
|
||||
@compileError("Type does not have local method");
|
||||
} else {
|
||||
const struct_info = @typeInfo(T).@"struct";
|
||||
inline for (struct_info.decls) |decl| {
|
||||
if (std.mem.eql(u8, decl.name, "local")) {
|
||||
inline for (struct_info.decl_names) |decl_name| {
|
||||
if (std.mem.eql(u8, decl_name, "local")) {
|
||||
const Fn = @TypeOf(@field(T, "local"));
|
||||
const fn_info = @typeInfo(Fn).@"fn";
|
||||
return fn_info.return_type.?;
|
||||
|
||||
@@ -36,7 +36,7 @@ pub const Status = enum(u32) {
|
||||
};
|
||||
|
||||
pub fn getStatus(self: Module) Status {
|
||||
return @enumFromInt(v8.v8__Module__GetStatus(self.handle));
|
||||
return @fromBackingInt(@intCast(v8.v8__Module__GetStatus(self.handle)));
|
||||
}
|
||||
|
||||
pub fn getException(self: Module) js.Value {
|
||||
|
||||
@@ -55,7 +55,7 @@ pub const State = enum(u32) {
|
||||
};
|
||||
|
||||
pub fn state(self: Promise) State {
|
||||
return @enumFromInt(v8.v8__Promise__State(self.handle));
|
||||
return @fromBackingInt(@intCast(v8.v8__Promise__State(self.handle)));
|
||||
}
|
||||
|
||||
/// Settled value (fulfillment or rejection). Caller must check `state` first.
|
||||
|
||||
+21
-22
@@ -348,10 +348,10 @@ fn createSnapshotContext(
|
||||
const func_obj: *const v8.Object = @ptrCast(func);
|
||||
if (v8.v8__Object__Get(func_obj, context, prototype_key)) |proto_handle| {
|
||||
const proto_obj: *const v8.Object = @ptrCast(proto_handle);
|
||||
inline for (@typeInfo(JsApi).@"struct".decls) |d| {
|
||||
const exposed = comptime memberExposed(@field(JsApi, d.name));
|
||||
inline for (@typeInfo(JsApi).@"struct".decl_names) |decl_name| {
|
||||
const exposed = comptime memberExposed(@field(JsApi, decl_name));
|
||||
if (comptime exposed != .both and exposed != realm.asExposed()) {
|
||||
const name: [:0]const u8 = d.name;
|
||||
const name: [:0]const u8 = decl_name;
|
||||
const name_v8 = v8.v8__String__NewFromUtf8(isolate, name.ptr, v8.kNormal, @intCast(name.len));
|
||||
var maybe_deleted: v8.MaybeBool = undefined;
|
||||
v8.v8__Object__Delete(proto_obj, context, name_v8, &maybe_deleted);
|
||||
@@ -399,8 +399,8 @@ fn createSnapshotContext(
|
||||
|
||||
fn hasGatedMember(comptime JsApi: type) bool {
|
||||
comptime {
|
||||
for (@typeInfo(JsApi).@"struct".decls) |d| {
|
||||
if (memberExposed(@field(JsApi, d.name)) != .both) {
|
||||
for (@typeInfo(JsApi).@"struct".decl_names) |decl_name| {
|
||||
if (memberExposed(@field(JsApi, decl_name)) != .both) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -444,9 +444,9 @@ fn countExternalReferences() comptime_int {
|
||||
count += 1;
|
||||
}
|
||||
|
||||
const declarations = @typeInfo(JsApi).@"struct".decls;
|
||||
inline for (declarations) |d| {
|
||||
const value = @field(JsApi, d.name);
|
||||
const decl_names = @typeInfo(JsApi).@"struct".decl_names;
|
||||
inline for (decl_names) |decl_name| {
|
||||
const value = @field(JsApi, decl_name);
|
||||
const T = @TypeOf(value);
|
||||
if (T == bridge.Accessor) {
|
||||
if (value.wpt_only and wpt_extensions_enabled == false) {
|
||||
@@ -524,9 +524,9 @@ fn collectExternalReferences() [countExternalReferences()]isize {
|
||||
idx += 1;
|
||||
}
|
||||
|
||||
const declarations = @typeInfo(JsApi).@"struct".decls;
|
||||
inline for (declarations) |d| {
|
||||
const value = @field(JsApi, d.name);
|
||||
const decl_names = @typeInfo(JsApi).@"struct".decl_names;
|
||||
inline for (decl_names) |decl_name| {
|
||||
const value = @field(JsApi, decl_name);
|
||||
const T = @TypeOf(value);
|
||||
if (T == bridge.Accessor) {
|
||||
if (value.wpt_only and wpt_extensions_enabled == false) {
|
||||
@@ -619,8 +619,8 @@ fn countInternalFields(comptime JsApi: type) u8 {
|
||||
var last_used_id = 0;
|
||||
var cache_count: u8 = 0;
|
||||
|
||||
inline for (@typeInfo(JsApi).@"struct".decls) |d| {
|
||||
const name: [:0]const u8 = d.name;
|
||||
inline for (@typeInfo(JsApi).@"struct".decl_names) |decl_name| {
|
||||
const name: [:0]const u8 = decl_name;
|
||||
const value = @field(JsApi, name);
|
||||
const definition = @TypeOf(value);
|
||||
|
||||
@@ -687,9 +687,9 @@ fn illegalConstructorCallback(raw_info: ?*const v8.FunctionCallbackInfo) callcon
|
||||
|
||||
// Helper to check if a JsApi has a NamedIndexed handler (public for reuse)
|
||||
fn hasNamedIndexedGetter(comptime JsApi: type) bool {
|
||||
const declarations = @typeInfo(JsApi).@"struct".decls;
|
||||
inline for (declarations) |d| {
|
||||
const value = @field(JsApi, d.name);
|
||||
const decl_names = @typeInfo(JsApi).@"struct".decl_names;
|
||||
inline for (decl_names) |decl_name| {
|
||||
const value = @field(JsApi, decl_name);
|
||||
const T = @TypeOf(value);
|
||||
if (T == bridge.NamedIndexed) {
|
||||
return true;
|
||||
@@ -805,13 +805,12 @@ fn attachClass(comptime JsApi: type, comptime flatten: bool, isolate: *v8.Isolat
|
||||
const own_properties = @hasDecl(JsApi.Meta, "own_properties") and JsApi.Meta.own_properties;
|
||||
const member_template = if (own_properties) instance else prototype;
|
||||
|
||||
const declarations = @typeInfo(JsApi).@"struct".decls;
|
||||
const decl_names = @typeInfo(JsApi).@"struct".decl_names;
|
||||
var has_named_index_getter = false;
|
||||
|
||||
const wpt_extensions_enabled = lp.build_config.wpt_extensions;
|
||||
|
||||
inline for (declarations) |d| {
|
||||
const name: [:0]const u8 = d.name;
|
||||
inline for (decl_names) |name| {
|
||||
const value = @field(JsApi, name);
|
||||
const definition = @TypeOf(value);
|
||||
|
||||
@@ -992,10 +991,10 @@ const unforgeables: []const Unforgeable = blk: {
|
||||
@setEvalBranchQuota(100_000);
|
||||
var list: []const Unforgeable = &.{};
|
||||
for (JsApis) |Api| {
|
||||
for (@typeInfo(Api).@"struct".decls) |d| {
|
||||
const value = @field(Api, d.name);
|
||||
for (@typeInfo(Api).@"struct".decl_names) |decl_name| {
|
||||
const value = @field(Api, decl_name);
|
||||
if (@TypeOf(value) == bridge.Accessor and value.unforgeable and !value.static) {
|
||||
list = list ++ &[_]Unforgeable{.{ .Owner = Api, .name = d.name, .accessor = value }};
|
||||
list = list ++ &[_]Unforgeable{.{ .Owner = Api, .name = decl_name, .accessor = value }};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ const bridge = js.bridge;
|
||||
//
|
||||
// In a simple/perfect world, we could use this knowledge to cast the *anyopaque
|
||||
// to the parameter type:
|
||||
// const arg: @typeInfo(@TypeOf(function)).@"fn".params[0] = @ptrCast(v8_data);
|
||||
// const arg: @typeInfo(@TypeOf(function)).@"fn".param_types[0].? = @ptrCast(v8_data);
|
||||
//
|
||||
// But there are 2 reasons we can't do that.
|
||||
//
|
||||
|
||||
@@ -136,10 +136,10 @@ pub const Caught = struct {
|
||||
|
||||
pub fn logFmt(self: Caught, prefix: []const u8, writer: anytype) !void {
|
||||
var buf: [64]u8 = undefined;
|
||||
try writer.write(try std.fmt.bufPrint(&buf, "{s}.exception", .{prefix}), self.exception orelse "???");
|
||||
try writer.write(try std.fmt.bufPrint(&buf, "{s}.stack", .{prefix}), self.stack orelse "na");
|
||||
try writer.write(try std.fmt.bufPrint(&buf, "{s}.line", .{prefix}), self.line);
|
||||
try writer.write(try std.fmt.bufPrint(&buf, "{s}.caught", .{prefix}), self.caught);
|
||||
try writer.write(try std.mem.print(&buf, "{s}.exception", .{prefix}), self.exception orelse "???");
|
||||
try writer.write(try std.mem.print(&buf, "{s}.stack", .{prefix}), self.stack orelse "na");
|
||||
try writer.write(try std.mem.print(&buf, "{s}.line", .{prefix}), self.line);
|
||||
try writer.write(try std.mem.print(&buf, "{s}.caught", .{prefix}), self.caught);
|
||||
}
|
||||
|
||||
pub fn jsonStringify(self: Caught, jw: anytype) !void {
|
||||
|
||||
@@ -853,7 +853,7 @@ const Inert = struct {
|
||||
if (i != 0) {
|
||||
try writer.writeByte(',');
|
||||
}
|
||||
const key = std.fmt.bufPrint(&key_buf, "{d}", .{i}) catch unreachable;
|
||||
const key = std.mem.print(&key_buf, "{d}", .{i}) catch unreachable;
|
||||
const element = self.ownDataProperty(@ptrCast(handle), key) orelse continue;
|
||||
if (v8.v8__Value__IsNullOrUndefined(element)) {
|
||||
continue;
|
||||
@@ -1012,7 +1012,7 @@ test "Value: inert formatting runs no page JS" {
|
||||
};
|
||||
for (cases) |case| {
|
||||
const value = try ls.local.exec(case.expr, null);
|
||||
const out = try std.fmt.allocPrint(testing.allocator, "{f}", .{value});
|
||||
const out = try testing.allocator.print("{f}", .{value});
|
||||
defer testing.allocator.free(out);
|
||||
try testing.expectEqualSlices(u8, case.expected, out);
|
||||
}
|
||||
|
||||
+14
-14
@@ -207,9 +207,9 @@ pub const Function = struct {
|
||||
const Session = @import("../Session.zig");
|
||||
|
||||
var count: usize = 0;
|
||||
var params = @typeInfo(T).@"fn".params;
|
||||
for (params[start..]) |p| { // start at 1, skip self
|
||||
const PT = p.type.?;
|
||||
const param_types = @typeInfo(T).@"fn".param_types;
|
||||
for (param_types[start..]) |param_type| { // start at 1, skip self
|
||||
const PT = param_type.?;
|
||||
if (PT == *Frame or PT == *const Frame) {
|
||||
break;
|
||||
}
|
||||
@@ -440,18 +440,18 @@ pub const Indexed = struct {
|
||||
|
||||
fn hasNotHandled(comptime E: type) bool {
|
||||
// anyerror includes it
|
||||
const errors = @typeInfo(E).error_set orelse return true;
|
||||
for (errors) |e| {
|
||||
if (std.mem.eql(u8, e.name, "NotHandled")) return true;
|
||||
const error_names = @typeInfo(E).error_set.error_names orelse return true;
|
||||
for (error_names) |name| {
|
||||
if (std.mem.eql(u8, name, "NotHandled")) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Default index query if one isn't provided. Uses the getter to determine the result
|
||||
fn GetterQuery(comptime getter: anytype, comptime attrs: u32) type {
|
||||
const params = @typeInfo(@TypeOf(getter)).@"fn".params;
|
||||
const Self = params[0].type.?;
|
||||
const Index = params[1].type.?;
|
||||
const param_types = @typeInfo(@TypeOf(getter)).@"fn".param_types;
|
||||
const Self = param_types[0].?;
|
||||
const Index = param_types[1].?;
|
||||
|
||||
// A getter that can return neither null nor error.NotHandled would report
|
||||
// every index as present.
|
||||
@@ -465,13 +465,13 @@ fn GetterQuery(comptime getter: anytype, comptime attrs: u32) type {
|
||||
}
|
||||
|
||||
return struct {
|
||||
const query = if (params.len == 3) withGlobal else plain;
|
||||
const query = if (param_types.len == 3) withGlobal else plain;
|
||||
|
||||
fn plain(self: Self, idx: Index) !u32 {
|
||||
return attributes(getter(self, idx));
|
||||
}
|
||||
|
||||
fn withGlobal(self: Self, idx: Index, global: params[2].type.?) !u32 {
|
||||
fn withGlobal(self: Self, idx: Index, global: param_types[2].?) !u32 {
|
||||
return attributes(getter(self, idx, global));
|
||||
}
|
||||
|
||||
@@ -804,7 +804,7 @@ pub fn unknownWindowPropertyCallback(c_name: ?*const v8.Name, handle: ?*const v8
|
||||
// });
|
||||
// if (!ignored.has(property)) {
|
||||
// var buf: [2048]u8 = undefined;
|
||||
// const key = std.fmt.bufPrint(&buf, "Window:{s}", .{property}) catch return js.Intercepted.no;
|
||||
// const key = std.mem.print(&buf, "Window:{s}", .{property}) catch return js.Intercepted.no;
|
||||
// logUnknownProperty(local, key) catch return js.Intercepted.no;
|
||||
// }
|
||||
// }
|
||||
@@ -870,7 +870,7 @@ pub fn unknownWindowPropertyCallback(c_name: ?*const v8.Name, handle: ?*const v8
|
||||
// const ignored = std.StaticStringMap(void).initComptime(.{});
|
||||
// if (!ignored.has(property)) {
|
||||
// var buf: [2048]u8 = undefined;
|
||||
// const key = std.fmt.bufPrint(&buf, "{s}:{s}", .{ if (@hasDecl(JsApi.Meta, "name")) JsApi.Meta.name else @typeName(JsApi), property }) catch return js.Intercepted.no;
|
||||
// const key = std.mem.print(&buf, "{s}:{s}", .{ if (@hasDecl(JsApi.Meta, "name")) JsApi.Meta.name else @typeName(JsApi), property }) catch return js.Intercepted.no;
|
||||
// logUnknownProperty(local, key) catch return js.Intercepted.no;
|
||||
// }
|
||||
// return js.Intercepted.no;
|
||||
@@ -1001,7 +1001,7 @@ pub const JsApiLookup = struct {
|
||||
|
||||
/// Returns the ID for the given type.
|
||||
pub inline fn getId(t: type) BackingInt {
|
||||
return @intFromEnum(getIndex(t));
|
||||
return @backingInt(getIndex(t));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ const Slot = @import("webapi/element/html/Slot.zig");
|
||||
|
||||
const LimitedWriter = @import("../LimitedWriter.zig");
|
||||
const isAllWhitespace = @import("../string.zig").isAllWhitespace;
|
||||
const repeat = @import("../string.zig").repeat;
|
||||
|
||||
pub const Opts = struct {
|
||||
max_bytes: ?u32 = null,
|
||||
@@ -895,7 +896,7 @@ test "browser.markdown: max_bytes truncates with marker" {
|
||||
|
||||
const doc = frame.window._document;
|
||||
const div = try doc.createElement("div", null, frame);
|
||||
try Frame.parse.htmlAsChildren(frame, div.asNode(), "<p>" ++ ("AAAA " ** 100) ++ "</p>");
|
||||
try Frame.parse.htmlAsChildren(frame, div.asNode(), "<p>" ++ (repeat("AAAA ", 100)) ++ "</p>");
|
||||
|
||||
var aw: std.Io.Writer.Allocating = .init(testing.allocator);
|
||||
defer aw.deinit();
|
||||
|
||||
@@ -542,7 +542,7 @@ fn _createElementCallback(self: *Parser, data: *anyopaque, qname: h5e.QualName,
|
||||
// like createElementNS. html5ever never sets a prefix; xml5ever does.
|
||||
const name = if (qname.prefix.unwrap()) |prefix| blk: {
|
||||
if (prefix.len == 0) break :blk local;
|
||||
break :blk try std.fmt.allocPrint(frame.local_arena, "{s}:{s}", .{ prefix.slice(), local });
|
||||
break :blk try frame.local_arena.print("{s}:{s}", .{ prefix.slice(), local });
|
||||
} else local;
|
||||
const namespace_string = qname.ns.slice();
|
||||
const namespace = if (namespace_string.len == 0) default_namespace else Element.Namespace.parse(namespace_string);
|
||||
@@ -953,7 +953,7 @@ fn getNode(ref: *anyopaque) *Node {
|
||||
return getParsed(ref).node;
|
||||
}
|
||||
|
||||
fn asUint(comptime string: anytype) std.meta.Int(
|
||||
fn asUint(comptime string: anytype) @Int(
|
||||
.unsigned,
|
||||
@bitSizeOf(@TypeOf(string.*)) - 8, // (- 8) to exclude sentinel 0
|
||||
) {
|
||||
|
||||
+8
-8
@@ -291,7 +291,7 @@ const Document = struct {
|
||||
const layout = self.layout;
|
||||
const lines = layout.lines();
|
||||
for (layout.blocks(), 0..) |b, bi| {
|
||||
if (b.kind == @intFromEnum(screenshot.LpBlock.Kind.rule)) {
|
||||
if (b.kind == @backingInt(screenshot.LpBlock.Kind.rule)) {
|
||||
const pg, const py = self.pageOf(b.y);
|
||||
if (self.selected[pg]) {
|
||||
try rect(&self.pages[pg].writer, layout.raw.rule_color, b.x, py, self.column_w - b.x, 1);
|
||||
@@ -311,7 +311,7 @@ const Document = struct {
|
||||
const h = boxes[j].bottom - boxes[i].top;
|
||||
if (self.selected[pg]) {
|
||||
const w = &self.pages[pg].writer;
|
||||
if (b.kind == @intFromEnum(screenshot.LpBlock.Kind.pre) and self.opts.print_background) {
|
||||
if (b.kind == @backingInt(screenshot.LpBlock.Kind.pre) and self.opts.print_background) {
|
||||
const x0 = b.x - layout.raw.pre_pad;
|
||||
try rect(w, layout.raw.pre_bg, x0, top, self.column_w - x0, h);
|
||||
}
|
||||
@@ -351,7 +351,7 @@ const Document = struct {
|
||||
/// Each line's vertical extent. A <pre> grows its first and last line by
|
||||
/// the padding so the background stays with the text across a break.
|
||||
fn lineBoxes(self: *const Document, b: screenshot.LpLayoutBlock, block_lines: []const screenshot.LpLine) ![]const Box {
|
||||
const pad: f32 = if (b.kind == @intFromEnum(screenshot.LpBlock.Kind.pre)) self.layout.raw.pre_pad else 0;
|
||||
const pad: f32 = if (b.kind == @backingInt(screenshot.LpBlock.Kind.pre)) self.layout.raw.pre_pad else 0;
|
||||
const boxes = try self.arena.alloc(Box, block_lines.len);
|
||||
for (boxes, block_lines, 0..) |*box, line, i| {
|
||||
box.* = .{
|
||||
@@ -584,11 +584,11 @@ fn paginate(arena: Allocator, layout: *const screenshot.Layout, page_h: f32) ![]
|
||||
try breaks.append(arena, 0);
|
||||
const lines = layout.lines();
|
||||
for (layout.blocks()) |b| {
|
||||
if (b.kind == @intFromEnum(screenshot.LpBlock.Kind.rule)) {
|
||||
if (b.kind == @backingInt(screenshot.LpBlock.Kind.rule)) {
|
||||
try fit(arena, &breaks, b.y, b.y + 1, page_h);
|
||||
continue;
|
||||
}
|
||||
const pad: f32 = if (b.kind == @intFromEnum(screenshot.LpBlock.Kind.pre)) layout.raw.pre_pad else 0;
|
||||
const pad: f32 = if (b.kind == @backingInt(screenshot.LpBlock.Kind.pre)) layout.raw.pre_pad else 0;
|
||||
for (lines[b.lines..][0..b.lines_len], 0..) |line, i| {
|
||||
const top = line.top - if (i == 0) pad else 0;
|
||||
const bottom = line.bottom + if (i + 1 == b.lines_len) pad else 0;
|
||||
@@ -673,10 +673,10 @@ const FontUse = struct {
|
||||
const ttf = &self.ttf;
|
||||
const k = 1000 / @as(f32, @floatFromInt(ttf.upem));
|
||||
const gids = try self.sortedGids(arena);
|
||||
const name = try std.fmt.allocPrint(arena, "{s}+{s}", .{ SUBSET_TAG, self.info.name[0..self.info.name_len] });
|
||||
const name = try arena.print("{s}+{s}", .{ SUBSET_TAG, self.info.name[0..self.info.name_len] });
|
||||
|
||||
const file = ttf.subset(arena, gids) catch ttf.data;
|
||||
const file_id = try out.stream(try std.fmt.allocPrint(arena, "/Length1 {d}", .{file.len}), file);
|
||||
const file_id = try out.stream(try arena.print("/Length1 {d}", .{file.len}), file);
|
||||
|
||||
const descriptor = try out.alloc();
|
||||
try out.begin(descriptor);
|
||||
@@ -988,7 +988,7 @@ const Out = struct {
|
||||
}
|
||||
|
||||
fn print(self: *Out, comptime fmt: []const u8, args: anytype) !void {
|
||||
try self.write(try std.fmt.allocPrint(self.arena, fmt, args));
|
||||
try self.write(try self.arena.print(fmt, args));
|
||||
}
|
||||
|
||||
fn alloc(self: *Out) !usize {
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
// Referrer Policy: https://www.w3.org/TR/referrer-policy/
|
||||
const std = @import("std");
|
||||
const URL = @import("URL.zig");
|
||||
const repeat = @import("../string.zig").repeat;
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
@@ -106,7 +107,7 @@ pub fn compute(arena: Allocator, policy: Policy, referrer_url: [:0]const u8, tar
|
||||
if (full) {
|
||||
// Serializing through origin + path + query strips credentials and
|
||||
// the fragment, and normalizes away default ports.
|
||||
const value = try std.fmt.allocPrint(arena, "{s}{s}{s}", .{
|
||||
const value = try arena.print("{s}{s}{s}", .{
|
||||
referrer_origin,
|
||||
URL.getPathname(referrer_url),
|
||||
URL.getSearch(referrer_url),
|
||||
@@ -117,7 +118,7 @@ pub fn compute(arena: Allocator, policy: Policy, referrer_url: [:0]const u8, tar
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return try std.fmt.allocPrint(arena, "{s}/", .{referrer_origin});
|
||||
return try arena.print("{s}/", .{referrer_origin});
|
||||
}
|
||||
|
||||
fn staticStringMapEqlAsciiIgnoreCase(a: []const u8, b: []const u8) bool {
|
||||
@@ -207,14 +208,14 @@ test "referrer: compute" {
|
||||
}
|
||||
|
||||
test "referrer: compute caps at 4096 bytes" {
|
||||
const path = "/" ++ ("a" ** 4096);
|
||||
const path = "/" ++ (repeat("a", 4096));
|
||||
const url = "http://a.com" ++ path;
|
||||
// over the cap: falls back to the origin form
|
||||
try testing.expectEqual("http://a.com/", (try compute(testing.arena_allocator, .unsafe_url, url, "http://b.com/x")).?);
|
||||
try testing.expectEqual("http://a.com/", (try compute(testing.arena_allocator, .no_referrer_when_downgrade, url, "http://a.com/x")).?);
|
||||
|
||||
// exactly at the cap: sent in full
|
||||
const at_cap = "http://a.com/" ++ ("a" ** (4096 - "http://a.com/".len));
|
||||
const at_cap = "http://a.com/" ++ (repeat("a", 4096 - "http://a.com/".len));
|
||||
try testing.expectEqual(at_cap, (try compute(testing.arena_allocator, .unsafe_url, at_cap, "http://b.com/x")).?);
|
||||
|
||||
// origin-only policies are unaffected by the referrer's length
|
||||
|
||||
@@ -887,7 +887,7 @@ const Builder = struct {
|
||||
if (stray) self.list_depth = 1;
|
||||
if (!stray and self.list_stack[self.list_depth - 1].ordered) {
|
||||
const state = &self.list_stack[self.list_depth - 1];
|
||||
self.pending_marker = try std.fmt.allocPrint(self.arena, "{d}.", .{state.index});
|
||||
self.pending_marker = try self.arena.print("{d}.", .{state.index});
|
||||
state.index += 1;
|
||||
} else {
|
||||
self.pending_marker = "•";
|
||||
@@ -1171,9 +1171,9 @@ test "browser.screenshot: rust abi matches" {
|
||||
.span_strike = SPAN_STRIKE,
|
||||
.span_has_color = SPAN_HAS_COLOR,
|
||||
|
||||
.block_heading = @intFromEnum(LpBlock.Kind.heading),
|
||||
.block_pre = @intFromEnum(LpBlock.Kind.pre),
|
||||
.block_rule = @intFromEnum(LpBlock.Kind.rule),
|
||||
.block_heading = @backingInt(LpBlock.Kind.heading),
|
||||
.block_pre = @backingInt(LpBlock.Kind.pre),
|
||||
.block_rule = @backingInt(LpBlock.Kind.rule),
|
||||
.block_tight = BLOCK_TIGHT,
|
||||
|
||||
.render_measure_only = RENDER_MEASURE_ONLY,
|
||||
@@ -1189,9 +1189,9 @@ test "browser.screenshot: rust abi matches" {
|
||||
// Size first: a field present on only one side of LpAbi itself shifts
|
||||
// everything after it, and the per-field loop would just report noise.
|
||||
try testing.expectEqual(expected.size, got.size);
|
||||
inline for (@typeInfo(LpAbi).@"struct".fields) |f| {
|
||||
testing.expectEqual(@field(expected, f.name), @field(got, f.name)) catch |err| {
|
||||
std.debug.print("rust/zig abi mismatch on {s}\n", .{f.name});
|
||||
inline for (@typeInfo(LpAbi).@"struct".field_names) |field_name| {
|
||||
testing.expectEqual(@field(expected, field_name), @field(got, field_name)) catch |err| {
|
||||
std.debug.print("rust/zig abi mismatch on {s}\n", .{field_name});
|
||||
return err;
|
||||
};
|
||||
}
|
||||
|
||||
+45
-47
@@ -783,11 +783,11 @@ const url_params_schema = minify(
|
||||
\\}
|
||||
);
|
||||
|
||||
/// Materialized form of `Tool.definition` keyed by `@intFromEnum(Tool)`.
|
||||
/// Materialized form of `Tool.definition` keyed by `@backingInt(Tool)`.
|
||||
/// Built at comptime by iterating every `Tool` tag — order and count
|
||||
/// can't drift because both come from the enum itself.
|
||||
pub const tool_defs: [@typeInfo(Tool).@"enum".fields.len]Tool.Definition = blk: {
|
||||
var arr: [@typeInfo(Tool).@"enum".fields.len]Tool.Definition = undefined;
|
||||
pub const tool_defs: [@typeInfo(Tool).@"enum".field_names.len]Tool.Definition = blk: {
|
||||
var arr: [@typeInfo(Tool).@"enum".field_names.len]Tool.Definition = undefined;
|
||||
for (std.enums.values(Tool), 0..) |t, i| arr[i] = t.definition();
|
||||
break :blk arr;
|
||||
};
|
||||
@@ -795,10 +795,10 @@ pub const tool_defs: [@typeInfo(Tool).@"enum".fields.len]Tool.Definition = blk:
|
||||
/// Comptime-built flat array of tool names, in `Tool` declaration order.
|
||||
/// Use this when callers only need the names (slash-command lookup, MCP
|
||||
/// `tools/list`).
|
||||
pub const names: [@typeInfo(Tool).@"enum".fields.len][]const u8 = blk: {
|
||||
const fields = @typeInfo(Tool).@"enum".fields;
|
||||
var arr: [fields.len][]const u8 = undefined;
|
||||
for (fields, 0..) |f, i| arr[i] = f.name;
|
||||
pub const names: [@typeInfo(Tool).@"enum".field_names.len][]const u8 = blk: {
|
||||
const field_names = @typeInfo(Tool).@"enum".field_names;
|
||||
var arr: [field_names.len][]const u8 = undefined;
|
||||
for (field_names, 0..) |field_name, i| arr[i] = field_name;
|
||||
break :blk arr;
|
||||
};
|
||||
|
||||
@@ -913,7 +913,7 @@ pub fn call(
|
||||
// `multi_tool_use.parallel` wrapper) learns the name is wrong instead of
|
||||
// retrying it with different arguments.
|
||||
const tool = std.meta.stringToEnum(Tool, tool_name) orelse return .{
|
||||
.text = try std.fmt.allocPrint(arena, "Unknown tool: {s}", .{tool_name}),
|
||||
.text = try arena.print("Unknown tool: {s}", .{tool_name}),
|
||||
.is_error = true,
|
||||
};
|
||||
if (diagnoseArgs(arena, arguments)) |msg|
|
||||
@@ -1012,7 +1012,7 @@ fn dispatch(
|
||||
fn formatNavigationError(arena: std.mem.Allocator, session: *lp.Session) ?[]const u8 {
|
||||
const frame = session.currentFrame() orelse return null;
|
||||
const err = frame._last_navigate_error orelse return null;
|
||||
return std.fmt.allocPrint(arena, "navigation failed: {s}", .{@errorName(err)}) catch null;
|
||||
return arena.print("navigation failed: {s}", .{@errorName(err)}) catch null;
|
||||
}
|
||||
|
||||
/// Run JavaScript against the current page. The script need not be
|
||||
@@ -1023,7 +1023,7 @@ pub fn evalScript(
|
||||
registry: *NodeRegistry,
|
||||
script: []const u8,
|
||||
) ToolError!ToolResult {
|
||||
const z = try arena.dupeZ(u8, script);
|
||||
const z = try arena.dupeSentinel(u8, script, 0);
|
||||
const page = try ensurePage(session, registry, null, null);
|
||||
return runEval(arena, page, z, null);
|
||||
}
|
||||
@@ -1109,9 +1109,9 @@ fn navStatus(arena: std.mem.Allocator, frame: *const lp.Frame) []const u8 {
|
||||
// `std.http.Status` is an enum(u10) and `_http_status` is only clamped to
|
||||
// u16 (`http.getResponseCode`), so a server answering with a 4-digit code
|
||||
// would make the cast illegal behaviour rather than an unknown phrase.
|
||||
const phrase = if (status > 599) "" else @as(std.http.Status, @enumFromInt(status)).phrase() orelse "";
|
||||
if (phrase.len == 0) return std.fmt.allocPrint(arena, "{d}", .{status}) catch "unknown";
|
||||
return std.fmt.allocPrint(arena, "{d} {s}", .{ status, phrase }) catch "unknown";
|
||||
const phrase = if (status > 599) "" else @as(std.http.Status, @fromBackingInt(@intCast(status))).phrase() orelse "";
|
||||
if (phrase.len == 0) return arena.print("{d}", .{status}) catch "unknown";
|
||||
return arena.print("{d} {s}", .{ status, phrase }) catch "unknown";
|
||||
}
|
||||
|
||||
fn execGoto(arena: std.mem.Allocator, session: *lp.Session, registry: *NodeRegistry, arguments: ?std.json.Value) ToolError![]const u8 {
|
||||
@@ -1119,8 +1119,8 @@ fn execGoto(arena: std.mem.Allocator, session: *lp.Session, registry: *NodeRegis
|
||||
const result = try performGoto(session, registry, args.url, .{ .timeout = args.timeout, .wait_until = args.waitUntil });
|
||||
const status = if (session.currentFrame()) |frame| navStatus(arena, frame) else "unknown";
|
||||
return switch (result) {
|
||||
.completed => std.fmt.allocPrint(arena, "Navigated successfully. HTTP {s}.", .{status}),
|
||||
.timeout => std.fmt.allocPrint(arena, "Navigation started (HTTP {s}) but the page did not finish loading before the timeout.", .{status}),
|
||||
.completed => arena.print("Navigated successfully. HTTP {s}.", .{status}),
|
||||
.timeout => arena.print("Navigation started (HTTP {s}) but the page did not finish loading before the timeout.", .{status}),
|
||||
} catch ToolError.InternalError;
|
||||
}
|
||||
|
||||
@@ -1521,17 +1521,17 @@ fn execScreenshot(arena: std.mem.Allocator, session: *lp.Session, registry: *Nod
|
||||
|
||||
if (args.path) |path| {
|
||||
const content_height = writePng(&prepared, path) catch |err| return .{
|
||||
.text = std.fmt.allocPrint(arena, "could not write {s}: {s}", .{ path, @errorName(err) }) catch return ToolError.OutOfMemory,
|
||||
.text = arena.print("could not write {s}: {s}", .{ path, @errorName(err) }) catch return ToolError.OutOfMemory,
|
||||
.is_error = true,
|
||||
};
|
||||
// The renderer reports the content height; a fixed strip is its own height.
|
||||
const height = if (prepared.opts.height == 0) content_height else prepared.opts.height;
|
||||
return .{ .text = std.fmt.allocPrint(arena, "Saved {d}x{d} PNG to {s}", .{ prepared.opts.width, height, absolutePath(arena, path) }) catch return ToolError.OutOfMemory };
|
||||
return .{ .text = arena.print("Saved {d}x{d} PNG to {s}", .{ prepared.opts.width, height, absolutePath(arena, path) }) catch return ToolError.OutOfMemory };
|
||||
}
|
||||
|
||||
prepared.fit(inline_image_max_width, inline_image_max_height) catch return ToolError.InternalError;
|
||||
return .{
|
||||
.text = std.fmt.allocPrint(arena, "PNG, {d}x{d}", .{ prepared.opts.width, prepared.opts.height }) catch return ToolError.OutOfMemory,
|
||||
.text = arena.print("PNG, {d}x{d}", .{ prepared.opts.width, prepared.opts.height }) catch return ToolError.OutOfMemory,
|
||||
.image = prepared,
|
||||
};
|
||||
}
|
||||
@@ -1646,14 +1646,12 @@ fn execEvaluate(arena: std.mem.Allocator, session: *lp.Session, registry: *NodeR
|
||||
|
||||
// Block scope preserves a trailing expression's value and keeps top-level
|
||||
// `let`/`const` from leaking; top-level `await`/`return` need the async IIFE.
|
||||
const block_script = std.fmt.allocPrintSentinel(
|
||||
arena,
|
||||
const block_script = arena.printSentinel(
|
||||
"{{ {s}\n}}",
|
||||
.{args.script},
|
||||
0,
|
||||
) catch return ToolError.OutOfMemory;
|
||||
const iife_script = std.fmt.allocPrintSentinel(
|
||||
arena,
|
||||
const iife_script = arena.printSentinel(
|
||||
"(async function(){{ \"use strict\"; {s} }})()",
|
||||
.{args.script},
|
||||
0,
|
||||
@@ -1697,7 +1695,7 @@ fn execEvaluate(arena: std.mem.Allocator, session: *lp.Session, registry: *NodeR
|
||||
if (result.text.len == 0) return result; // silenced save=; don't re-emit via nav suffix
|
||||
|
||||
const page_title = after.getTitle() catch null;
|
||||
const text = std.fmt.allocPrint(arena, "{s}\n(Navigated to {s}, HTTP {s}, title: {s})", .{
|
||||
const text = arena.print("{s}\n(Navigated to {s}, HTTP {s}, title: {s})", .{
|
||||
result.text, after.url, navStatus(arena, after), page_title orelse "(none)",
|
||||
}) catch return ToolError.InternalError;
|
||||
return .{ .text = text };
|
||||
@@ -1811,7 +1809,7 @@ fn bridgePrelude(arena: std.mem.Allocator, store: *const BridgeStore) ![:0]const
|
||||
try aw.writer.writeAll(kv.value_ptr.*);
|
||||
}
|
||||
try aw.writer.writeAll("};");
|
||||
return arena.dupeZ(u8, aw.written());
|
||||
return arena.dupeSentinel(u8, aw.written(), 0);
|
||||
}
|
||||
|
||||
const bridge_postlude: [:0]const u8 = "JSON.stringify(globalThis.lp)";
|
||||
@@ -1925,7 +1923,7 @@ fn formatActionResult(
|
||||
target: ActionTarget,
|
||||
suffix: []const u8,
|
||||
) ToolError![]const u8 {
|
||||
return std.fmt.allocPrint(arena, "{s} ({f}){s}", .{ prefix, target, suffix }) catch ToolError.InternalError;
|
||||
return arena.print("{s} ({f}){s}", .{ prefix, target, suffix }) catch ToolError.InternalError;
|
||||
}
|
||||
|
||||
/// What `finalizeAction` compares against; take it before the action runs.
|
||||
@@ -1972,7 +1970,7 @@ fn finalizeAction(arena: std.mem.Allocator, session: *lp.Session, registry: *Nod
|
||||
}
|
||||
|
||||
const page_title = page.getTitle() catch null;
|
||||
return std.fmt.allocPrint(arena, "{s}.{s} Page url: {s}, HTTP {s}, title: {s}", .{
|
||||
return arena.print("{s}.{s} Page url: {s}, HTTP {s}, title: {s}", .{
|
||||
body, note, page.url, navStatus(arena, page), page_title orelse "(none)",
|
||||
}) catch ToolError.InternalError;
|
||||
}
|
||||
@@ -2009,7 +2007,7 @@ fn execFill(arena: std.mem.Allocator, session: *lp.Session, registry: *NodeRegis
|
||||
lp.actions.fill(resolved.node, text, resolved.page) catch |err| return mapActionError(err);
|
||||
|
||||
// Show the original reference (e.g. $LP_PASSWORD) in the result, not the resolved value
|
||||
const suffix = std.fmt.allocPrint(arena, " with \"{s}\"", .{raw_text}) catch return ToolError.InternalError;
|
||||
const suffix = arena.print(" with \"{s}\"", .{raw_text}) catch return ToolError.InternalError;
|
||||
const body = try formatActionResult(arena, "Filled element", resolved.target, suffix);
|
||||
return finalizeAction(arena, session, registry, scope, body);
|
||||
}
|
||||
@@ -2032,15 +2030,15 @@ fn execScroll(arena: std.mem.Allocator, session: *lp.Session, registry: *NodeReg
|
||||
const result = lp.actions.scroll(if (resolved) |r| r.node else null, args.x, args.y, page) catch |err| return mapActionError(err);
|
||||
|
||||
const body = (switch (result.target) {
|
||||
.window => std.fmt.allocPrint(arena, "Scrolled window to x: {d}, y: {d}", .{ result.x, result.y }),
|
||||
.node => std.fmt.allocPrint(arena, "Scrolled element ({f}) to x: {d}, y: {d}", .{
|
||||
.window => arena.print("Scrolled window to x: {d}, y: {d}", .{ result.x, result.y }),
|
||||
.node => arena.print("Scrolled element ({f}) to x: {d}, y: {d}", .{
|
||||
resolved.?.target,
|
||||
result.x,
|
||||
result.y,
|
||||
}),
|
||||
.container => |container| blk: {
|
||||
const registered = registry.register(container) catch return ToolError.InternalError;
|
||||
break :blk std.fmt.allocPrint(arena, "Scrolled scroll container ({f}) of element ({f}) to x: {d}, y: {d}", .{
|
||||
break :blk arena.print("Scrolled scroll container ({f}) of element ({f}) to x: {d}, y: {d}", .{
|
||||
ActionTarget{ .backend_node_id = registered.id },
|
||||
resolved.?.target,
|
||||
result.x,
|
||||
@@ -2087,7 +2085,7 @@ fn execWaitForSelector(arena: std.mem.Allocator, session: *lp.Session, registry:
|
||||
};
|
||||
|
||||
const registered = registry.register(node) catch return ToolError.InternalError;
|
||||
return std.fmt.allocPrint(arena, "Element found. backendNodeId: {d}", .{registered.id}) catch return ToolError.InternalError;
|
||||
return arena.print("Element found. backendNodeId: {d}", .{registered.id}) catch return ToolError.InternalError;
|
||||
}
|
||||
|
||||
fn execWaitForScript(arena: std.mem.Allocator, session: *lp.Session, arguments: ?std.json.Value) ToolError![]const u8 {
|
||||
@@ -2138,7 +2136,7 @@ fn execWaitForState(arena: std.mem.Allocator, session: *lp.Session, arguments: ?
|
||||
},
|
||||
};
|
||||
|
||||
return std.fmt.allocPrint(arena, "Page reached {s}.", .{@tagName(args.state)}) catch return ToolError.InternalError;
|
||||
return arena.print("Page reached {s}.", .{@tagName(args.state)}) catch return ToolError.InternalError;
|
||||
}
|
||||
|
||||
fn execHover(arena: std.mem.Allocator, session: *lp.Session, registry: *NodeRegistry, arguments: ?std.json.Value) ToolError![]const u8 {
|
||||
@@ -2182,7 +2180,7 @@ fn execPress(arena: std.mem.Allocator, session: *lp.Session, registry: *NodeRegi
|
||||
|
||||
// Pressing Enter on a form input triggers implicit form submission;
|
||||
// `finalizeAction` drains the queued navigation before tagging the body.
|
||||
const body = std.fmt.allocPrint(arena, "Pressed key '{s}'", .{args.key}) catch return ToolError.InternalError;
|
||||
const body = arena.print("Pressed key '{s}'", .{args.key}) catch return ToolError.InternalError;
|
||||
return finalizeAction(arena, session, registry, scope, body);
|
||||
}
|
||||
|
||||
@@ -2199,7 +2197,7 @@ fn execSelectOption(arena: std.mem.Allocator, session: *lp.Session, registry: *N
|
||||
|
||||
lp.actions.selectOption(resolved.node, args.value, resolved.page) catch |err| return mapActionError(err);
|
||||
|
||||
const prefix = std.fmt.allocPrint(arena, "Selected option '{s}'", .{args.value}) catch return ToolError.InternalError;
|
||||
const prefix = arena.print("Selected option '{s}'", .{args.value}) catch return ToolError.InternalError;
|
||||
const body = try formatActionResult(arena, prefix, resolved.target, "");
|
||||
return finalizeAction(arena, session, registry, scope, body);
|
||||
}
|
||||
@@ -2218,7 +2216,7 @@ fn execSetChecked(arena: std.mem.Allocator, session: *lp.Session, registry: *Nod
|
||||
lp.actions.setChecked(resolved.node, args.checked, resolved.page) catch |err| return mapActionError(err);
|
||||
|
||||
const state_str: []const u8 = if (args.checked) "checked" else "unchecked";
|
||||
const suffix = std.fmt.allocPrint(arena, " to {s}", .{state_str}) catch return ToolError.InternalError;
|
||||
const suffix = arena.print(" to {s}", .{state_str}) catch return ToolError.InternalError;
|
||||
const body = try formatActionResult(arena, "Set element", resolved.target, suffix);
|
||||
return finalizeAction(arena, session, registry, scope, body);
|
||||
}
|
||||
@@ -2247,7 +2245,7 @@ fn execFindElement(arena: std.mem.Allocator, session: *lp.Session, registry: *No
|
||||
's' => options.dot_all = true,
|
||||
'm' => options.multiline = true,
|
||||
else => return .{
|
||||
.text = try std.fmt.allocPrint(arena, "findElement: unsupported regex flag '{c}' in '{s}'", .{ flag, name }),
|
||||
.text = try arena.print("findElement: unsupported regex flag '{c}' in '{s}'", .{ flag, name }),
|
||||
.is_error = true,
|
||||
},
|
||||
};
|
||||
@@ -2255,7 +2253,7 @@ fn execFindElement(arena: std.mem.Allocator, session: *lp.Session, registry: *No
|
||||
const regex = session.browser.app.regex_context.compile(lit.body, options, &diag) catch |err| switch (err) {
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
error.InvalidRegex => return .{
|
||||
.text = try std.fmt.allocPrint(arena, "findElement: invalid name regex '{s}': {s} at offset {d}", .{ lit.body, diag.message(), diag.offset }),
|
||||
.text = try arena.print("findElement: invalid name regex '{s}': {s} at offset {d}", .{ lit.body, diag.message(), diag.offset }),
|
||||
.is_error = true,
|
||||
},
|
||||
};
|
||||
@@ -2315,7 +2313,7 @@ fn execGetEnv(arena: std.mem.Allocator, arguments: ?std.json.Value) ToolError![]
|
||||
|
||||
if (args.name) |name| {
|
||||
if (lookupLpEnv(name)) |value| return value;
|
||||
return std.fmt.allocPrint(arena, "Environment variable '{s}' is not set", .{name}) catch ToolError.InternalError;
|
||||
return arena.print("Environment variable '{s}' is not set", .{name}) catch ToolError.InternalError;
|
||||
}
|
||||
|
||||
const env_names = lpEnvNames(arena) catch return ToolError.InternalError;
|
||||
@@ -2390,7 +2388,7 @@ fn execGetCookies(arena: std.mem.Allocator, session: *lp.Session, arguments: ?st
|
||||
|
||||
const filter_url: ?[:0]const u8 = blk: {
|
||||
if (args.all) break :blk null;
|
||||
if (args.url) |u| break :blk arena.dupeZ(u8, u) catch return ToolError.InternalError;
|
||||
if (args.url) |u| break :blk arena.dupeSentinel(u8, u, 0) catch return ToolError.InternalError;
|
||||
if (session.currentFrame()) |f| break :blk f.url;
|
||||
return "No current page. Pass `url` to filter by host or `all=true` to list every cookie.";
|
||||
};
|
||||
@@ -2410,7 +2408,7 @@ fn execGetCookies(arena: std.mem.Allocator, session: *lp.Session, arguments: ?st
|
||||
}
|
||||
if (count == 0) {
|
||||
const label = filter_url orelse "(unfiltered)";
|
||||
return std.fmt.allocPrint(arena, "No cookies for {s}.", .{label}) catch ToolError.InternalError;
|
||||
return arena.print("No cookies for {s}.", .{label}) catch ToolError.InternalError;
|
||||
}
|
||||
return aw.written();
|
||||
}
|
||||
@@ -2544,7 +2542,7 @@ fn diagnoseArgs(arena: std.mem.Allocator, arguments: ?std.json.Value) ?[]const u
|
||||
if (args.object.get("state")) |v| switch (v) {
|
||||
.string => |s| if (std.meta.stringToEnum(lp.Config.WaitUntil, s) == null)
|
||||
return formatEnumError(arena, "state", s, lp.Config.WaitUntil),
|
||||
else => return std.fmt.allocPrint(arena, "state must be a string", .{}) catch null,
|
||||
else => return arena.print("state must be a string", .{}) catch null,
|
||||
};
|
||||
|
||||
return null;
|
||||
@@ -2553,9 +2551,9 @@ fn diagnoseArgs(arena: std.mem.Allocator, arguments: ?std.json.Value) ?[]const u
|
||||
fn formatEnumError(arena: std.mem.Allocator, field: []const u8, got: []const u8, comptime E: type) ?[]const u8 {
|
||||
var aw: std.Io.Writer.Allocating = .init(arena);
|
||||
aw.writer.print("invalid {s} '{s}'. Expected one of: ", .{ field, got }) catch return null;
|
||||
inline for (std.meta.fields(E), 0..) |f, i| {
|
||||
inline for (@typeInfo(E).@"enum".field_names, 0..) |field_name, i| {
|
||||
if (i > 0) aw.writer.writeAll(", ") catch return null;
|
||||
aw.writer.writeAll(f.name) catch return null;
|
||||
aw.writer.writeAll(field_name) catch return null;
|
||||
}
|
||||
return aw.written();
|
||||
}
|
||||
@@ -2601,7 +2599,7 @@ pub fn normalizeArgKeys(arena: std.mem.Allocator, tool: Tool, args: ?std.json.Va
|
||||
if (v != .object) return v;
|
||||
|
||||
const schemas = lp.Schema.all();
|
||||
const tool_idx = @intFromEnum(tool);
|
||||
const tool_idx = @backingInt(tool);
|
||||
if (tool_idx >= schemas.len) return v;
|
||||
const schema = schemas[tool_idx];
|
||||
|
||||
@@ -2719,7 +2717,7 @@ pub fn reverseSubstituteEnvVars(arena: std.mem.Allocator, input: []const u8) err
|
||||
var changed = false;
|
||||
for (pairs.items) |p| {
|
||||
if (std.mem.indexOf(u8, current, p.value) == null) continue;
|
||||
const placeholder = try std.fmt.allocPrint(arena, "${s}", .{p.name});
|
||||
const placeholder = try arena.print("${s}", .{p.name});
|
||||
current = try std.mem.replaceOwned(u8, arena, current, p.value, placeholder);
|
||||
changed = true;
|
||||
}
|
||||
@@ -2751,12 +2749,12 @@ test "tree and nodeDetails read the node's own frame" {
|
||||
const input_id = (try registry.register(input)).id;
|
||||
|
||||
const aa = testing.arena_allocator;
|
||||
const tree_args = try std.json.parseFromSliceLeaky(std.json.Value, aa, try std.fmt.allocPrint(aa, "{{\"backendNodeId\":{d}}}", .{html_id}), .{});
|
||||
const tree_args = try std.json.parseFromSliceLeaky(std.json.Value, aa, try aa.print("{{\"backendNodeId\":{d}}}", .{html_id}), .{});
|
||||
const tree = try call(aa, page.session, ®istry, "tree", tree_args, .{});
|
||||
try std.testing.expect(std.mem.indexOf(u8, tree.text, "child-label") != null);
|
||||
try std.testing.expect(std.mem.indexOf(u8, tree.text, "parent-") == null);
|
||||
|
||||
const details_args = try std.json.parseFromSliceLeaky(std.json.Value, aa, try std.fmt.allocPrint(aa, "{{\"backendNodeId\":{d}}}", .{input_id}), .{});
|
||||
const details_args = try std.json.parseFromSliceLeaky(std.json.Value, aa, try aa.print("{{\"backendNodeId\":{d}}}", .{input_id}), .{});
|
||||
const details = try call(aa, page.session, ®istry, "nodeDetails", details_args, .{});
|
||||
try std.testing.expect(std.mem.indexOf(u8, details.text, "child-label") != null);
|
||||
}
|
||||
|
||||
@@ -277,7 +277,7 @@ fn writePartWithEndings(part: []const u8, use_native_endings: bool, writer: *Wri
|
||||
const match = chunk == cr;
|
||||
|
||||
// Create a bitset out of match vector.
|
||||
const bitset = std.bit_set.IntegerBitSet(vector_len){
|
||||
const bitset = std.bit_set.Integer(vector_len){
|
||||
.mask = @bitCast(@intFromBool(match)),
|
||||
};
|
||||
|
||||
@@ -453,7 +453,7 @@ test "Blob: a pinned arena reaches the browser's account and is given back" {
|
||||
browser.flushArenaMemory();
|
||||
try testing.expectEqual(0, browser.arena_account.pending);
|
||||
|
||||
const data = [_]u8{'x'} ** (64 * 1024);
|
||||
const data: [64 * 1024]u8 = @splat('x');
|
||||
const blob = try Blob.initFromBytes(&data, "text/plain", &frame.js.execution);
|
||||
try testing.expect(browser.arena_account.pending >= data.len);
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ pub fn escape(value: []const u8, frame: *Frame) ![]const u8 {
|
||||
// Second char (i==0) is a digit and first is '-', needs hex escape
|
||||
if (i == 0 and first == '-' and c >= '0' and c <= '9') {
|
||||
result[pos] = '\\';
|
||||
const hex_str = std.fmt.bufPrint(result[pos + 1 ..], "{x} ", .{c}) catch unreachable;
|
||||
const hex_str = std.mem.print(result[pos + 1 ..], "{x} ", .{c}) catch unreachable;
|
||||
pos += 1 + hex_str.len;
|
||||
} else if (!needsEscape(false, c)) {
|
||||
result[pos] = c;
|
||||
@@ -180,7 +180,7 @@ fn writeEscape(comptime is_first: bool, buf: []u8, c: u8) usize {
|
||||
var data = buf[1..];
|
||||
|
||||
if (isHexEscape(c) or ((comptime is_first) and c >= '0' and c <= '9')) {
|
||||
const hex_str = std.fmt.bufPrint(data, "{x} ", .{c}) catch unreachable;
|
||||
const hex_str = std.mem.print(data, "{x} ", .{c}) catch unreachable;
|
||||
return 1 + hex_str.len;
|
||||
}
|
||||
|
||||
|
||||
@@ -203,7 +203,7 @@ const ValueWriter = struct {
|
||||
pub fn logFmt(self: ValueWriter, _: []const u8, writer: anytype) !void {
|
||||
var buf: [32]u8 = undefined;
|
||||
for (self.valuesToLog(), 0..) |value, i| {
|
||||
const name = try std.fmt.bufPrint(&buf, "param.{d}", .{i});
|
||||
const name = try std.mem.print(&buf, "param.{d}", .{i});
|
||||
try writer.write(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ fn getCode(self: *const DOMException) u8 {
|
||||
return switch (self._code) {
|
||||
// no legacy numeric code
|
||||
.operation_error, .data_error, .constraint_error, .version_error, .transaction_inactive_error, .read_only_error => 0,
|
||||
else => @intFromEnum(self._code),
|
||||
else => @backingInt(self._code),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -162,7 +162,7 @@ pub fn toString(self: *const DOMException, exec: *js.Execution) ![]const u8 {
|
||||
else => break :blk self.getMessage(),
|
||||
}
|
||||
};
|
||||
return std.fmt.bufPrint(exec.buf, "{s}: {s}", .{ self.getName(), msg }) catch return msg;
|
||||
return std.mem.print(exec.buf, "{s}: {s}", .{ self.getName(), msg }) catch return msg;
|
||||
}
|
||||
|
||||
const Code = enum(u8) {
|
||||
|
||||
@@ -206,7 +206,7 @@ fn invertSelf(self: *DOMMatrix) !*DOMMatrix {
|
||||
if (RO.invertMatrix(state.matrix)) |v| {
|
||||
state.matrix = v;
|
||||
} else {
|
||||
state.matrix = .{std.math.nan(f64)} ** 16;
|
||||
state.matrix = @splat(std.math.nan(f64));
|
||||
state.is_2d = false;
|
||||
}
|
||||
return self.applyState(state);
|
||||
|
||||
@@ -758,7 +758,7 @@ fn inverse(self: *const DOMMatrixReadOnly, page: *Page) !*DOMMatrix {
|
||||
return DOMMatrix.create(v, self._is_2d, page);
|
||||
}
|
||||
// Non-invertible matrices become all-NaN with is2D = false.
|
||||
return DOMMatrix.create(.{std.math.nan(f64)} ** 16, false, page);
|
||||
return DOMMatrix.create(@splat(std.math.nan(f64)), false, page);
|
||||
}
|
||||
|
||||
fn toFloat32Array(self: *const DOMMatrixReadOnly, exec: *const js.Execution) !js.TypedArray(f32) {
|
||||
@@ -783,7 +783,7 @@ pub fn toString(self: *const DOMMatrixReadOnly, exec: *const js.Execution) ![]co
|
||||
return error.InvalidStateError;
|
||||
}
|
||||
}
|
||||
return std.fmt.allocPrint(exec.local_arena, "matrix({d}, {d}, {d}, {d}, {d}, {d})", .{
|
||||
return exec.local_arena.print("matrix({d}, {d}, {d}, {d}, {d}, {d})", .{
|
||||
m[0], m[1], m[4], m[5], m[12], m[13],
|
||||
});
|
||||
}
|
||||
@@ -792,7 +792,7 @@ pub fn toString(self: *const DOMMatrixReadOnly, exec: *const js.Execution) ![]co
|
||||
return error.InvalidStateError;
|
||||
}
|
||||
}
|
||||
return std.fmt.allocPrint(exec.local_arena, "matrix3d({d}, {d}, {d}, {d}, {d}, {d}, {d}, {d}, {d}, {d}, {d}, {d}, {d}, {d}, {d}, {d})", .{
|
||||
return exec.local_arena.print("matrix3d({d}, {d}, {d}, {d}, {d}, {d}, {d}, {d}, {d}, {d}, {d}, {d}, {d}, {d}, {d}, {d})", .{
|
||||
m[0], m[1], m[2], m[3],
|
||||
m[4], m[5], m[6], m[7],
|
||||
m[8], m[9], m[10], m[11],
|
||||
|
||||
@@ -218,7 +218,7 @@ fn getLastModified(self: *const Document, frame: *Frame) ![]const u8 {
|
||||
};
|
||||
|
||||
const tm = try dt.localTime(timestamp);
|
||||
return std.fmt.allocPrint(frame.local_arena, "{d:0>2}/{d:0>2}/{d} {d:0>2}:{d:0>2}:{d:0>2}", .{
|
||||
return frame.local_arena.print("{d:0>2}/{d:0>2}/{d} {d:0>2}:{d:0>2}:{d:0>2}", .{
|
||||
@as(u32, @intCast(tm.tm_mon + 1)),
|
||||
@as(u32, @intCast(tm.tm_mday)),
|
||||
tm.tm_year + 1900,
|
||||
@@ -1223,7 +1223,7 @@ fn writeInternal(self: *Document, text: []const []const u8, append_newline: bool
|
||||
}
|
||||
|
||||
frame.domChanged();
|
||||
self._write_insertion_point = children_to_insert.getLast();
|
||||
self._write_insertion_point = children_to_insert.last().?;
|
||||
}
|
||||
|
||||
pub fn open(self: *Document, call_frame: *Frame) !*Document {
|
||||
|
||||
@@ -733,7 +733,7 @@ fn prefixedAttributeName(namespace: []const u8, local_name: []const u8, frame: *
|
||||
}
|
||||
return null;
|
||||
};
|
||||
return try std.fmt.allocPrint(frame.local_arena, "{s}:{s}", .{ prefix, local_name });
|
||||
return try frame.local_arena.print("{s}:{s}", .{ prefix, local_name });
|
||||
}
|
||||
|
||||
pub fn getAttributeSafe(self: *const Element, name: String) ?[]const u8 {
|
||||
|
||||
@@ -295,7 +295,7 @@ fn setCancelBubble(self: *Event) void {
|
||||
}
|
||||
|
||||
fn getEventPhase(self: *const Event) u8 {
|
||||
return @intFromEnum(self._event_phase);
|
||||
return @backingInt(self._event_phase);
|
||||
}
|
||||
|
||||
fn getTimeStamp(self: *const Event, exec: *js.Execution) f64 {
|
||||
@@ -399,42 +399,30 @@ pub fn inheritOptions(comptime T: type, comptime additions: anytype) type {
|
||||
// this per-level check produce.
|
||||
js.Local.assertDictionaryFieldOrder(additions);
|
||||
|
||||
var all_fields: []const std.builtin.Type.StructField = &.{};
|
||||
var names: []const [:0]const u8 = &.{};
|
||||
var types: []const type = &.{};
|
||||
var attrs: []const std.lang.Type.Struct.FieldAttributes = &.{};
|
||||
|
||||
if (@hasField(T, "_proto")) {
|
||||
const t_fields = @typeInfo(T).@"struct".fields;
|
||||
|
||||
inline for (t_fields) |field| {
|
||||
if (std.mem.eql(u8, field.name, "_proto")) {
|
||||
const ProtoType = @typeInfo(field.type).pointer.child;
|
||||
if (@hasDecl(ProtoType, "Options")) {
|
||||
const parent_options = @typeInfo(ProtoType.Options);
|
||||
for (parent_options.@"struct".fields) |f| {
|
||||
if (!std.mem.eql(u8, f.name, js.Local.dictionary_group_marker)) {
|
||||
all_fields = all_fields ++ &[_]std.builtin.Type.StructField{f};
|
||||
}
|
||||
}
|
||||
const ProtoType = @typeInfo(@FieldType(T, "_proto")).pointer.child;
|
||||
if (@hasDecl(ProtoType, "Options")) {
|
||||
const parent_options = @typeInfo(ProtoType.Options).@"struct";
|
||||
for (parent_options.field_names, parent_options.field_types, parent_options.field_attrs) |field_name, field_type, field_attrs| {
|
||||
if (!std.mem.eql(u8, field_name, js.Local.dictionary_group_marker)) {
|
||||
names = names ++ .{field_name};
|
||||
types = types ++ .{field_type};
|
||||
attrs = attrs ++ .{field_attrs};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const additions_info = @typeInfo(additions);
|
||||
all_fields = all_fields ++ additions_info.@"struct".fields;
|
||||
|
||||
const additions_info = @typeInfo(additions).@"struct";
|
||||
const marker_default: void = {};
|
||||
var names: [all_fields.len + 1][:0]const u8 = undefined;
|
||||
var types: [all_fields.len + 1]type = undefined;
|
||||
var attrs: [all_fields.len + 1]std.builtin.Type.StructField.Attributes = undefined;
|
||||
for (all_fields, 0..) |f, i| {
|
||||
names[i] = f.name;
|
||||
types[i] = f.type;
|
||||
attrs[i] = .{ .@"comptime" = f.is_comptime, .@"align" = f.alignment, .default_value_ptr = f.default_value_ptr };
|
||||
}
|
||||
names[all_fields.len] = js.Local.dictionary_group_marker;
|
||||
types[all_fields.len] = void;
|
||||
attrs[all_fields.len] = .{ .default_value_ptr = @ptrCast(&marker_default) };
|
||||
return @Struct(.auto, null, &names, &types, &attrs);
|
||||
names = names ++ additions_info.field_names ++ .{js.Local.dictionary_group_marker};
|
||||
types = types ++ additions_info.field_types ++ .{void};
|
||||
attrs = attrs ++ additions_info.field_attrs ++ .{std.lang.Type.Struct.FieldAttributes{ .default_value_ptr = @ptrCast(&marker_default) }};
|
||||
return @Struct(.auto, null, names, types, attrs);
|
||||
}
|
||||
|
||||
pub fn populatePrototypes(self: anytype, opts: anytype, trusted: bool) void {
|
||||
@@ -494,10 +482,10 @@ pub const JsApi = struct {
|
||||
pub const cancelBubble = bridge.accessor(Event.getCancelBubble, Event.setCancelBubble, .{});
|
||||
|
||||
// Event phase constants
|
||||
pub const NONE = bridge.property(@intFromEnum(EventPhase.none), .{ .template = true });
|
||||
pub const CAPTURING_PHASE = bridge.property(@intFromEnum(EventPhase.capturing_phase), .{ .template = true });
|
||||
pub const AT_TARGET = bridge.property(@intFromEnum(EventPhase.at_target), .{ .template = true });
|
||||
pub const BUBBLING_PHASE = bridge.property(@intFromEnum(EventPhase.bubbling_phase), .{ .template = true });
|
||||
pub const NONE = bridge.property(@backingInt(EventPhase.none), .{ .template = true });
|
||||
pub const CAPTURING_PHASE = bridge.property(@backingInt(EventPhase.capturing_phase), .{ .template = true });
|
||||
pub const AT_TARGET = bridge.property(@backingInt(EventPhase.at_target), .{ .template = true });
|
||||
pub const BUBBLING_PHASE = bridge.property(@backingInt(EventPhase.bubbling_phase), .{ .template = true });
|
||||
};
|
||||
|
||||
// tested in event_target
|
||||
@@ -77,7 +77,7 @@ const tracked_event_types = [_][]const u8{
|
||||
};
|
||||
|
||||
// Counts stored in a fixed array
|
||||
_counts: [tracked_event_types.len]u32 = [_]u32{0} ** tracked_event_types.len,
|
||||
_counts: [tracked_event_types.len]u32 = @splat(0),
|
||||
|
||||
pub fn increment(self: *EventCounts, event_type: []const u8) void {
|
||||
if (getIndex(event_type)) |idx| {
|
||||
|
||||
@@ -150,7 +150,7 @@ fn setOnProgress(self: *FileReader, cb: ?js.Function.Global) !void {
|
||||
}
|
||||
|
||||
fn getReadyState(self: *const FileReader) u8 {
|
||||
return @intFromEnum(self._ready_state);
|
||||
return @backingInt(self._ready_state);
|
||||
}
|
||||
|
||||
fn getResult(self: *const FileReader) ?Result {
|
||||
@@ -466,9 +466,9 @@ pub const JsApi = struct {
|
||||
pub const constructor = bridge.constructor(FileReader.init, .{});
|
||||
|
||||
// State constants
|
||||
pub const EMPTY = bridge.property(@intFromEnum(FileReader.ReadyState.empty), .{ .template = true });
|
||||
pub const LOADING = bridge.property(@intFromEnum(FileReader.ReadyState.loading), .{ .template = true });
|
||||
pub const DONE = bridge.property(@intFromEnum(FileReader.ReadyState.done), .{ .template = true });
|
||||
pub const EMPTY = bridge.property(@backingInt(FileReader.ReadyState.empty), .{ .template = true });
|
||||
pub const LOADING = bridge.property(@backingInt(FileReader.ReadyState.loading), .{ .template = true });
|
||||
pub const DONE = bridge.property(@backingInt(FileReader.ReadyState.done), .{ .template = true });
|
||||
|
||||
// Properties
|
||||
pub const readyState = bridge.accessor(FileReader.getReadyState, null, .{});
|
||||
|
||||
@@ -56,7 +56,7 @@ pub fn pushState(_: *History, state: js.Value, _: ?[]const u8, _url: ?[]const u8
|
||||
const url = if (_url) |u|
|
||||
try @import("../URL.zig").resolve(arena.allocator(), frame.url, u, .{})
|
||||
else
|
||||
try arena.dupeZ(u8, frame.url);
|
||||
try arena.dupeSentinel(u8, frame.url, 0);
|
||||
|
||||
const json = state.toJson(arena.allocator()) catch return error.DataClone;
|
||||
_ = try session.navigation.pushEntry(url, .{ .source = .history, .value = json }, frame, true);
|
||||
@@ -80,7 +80,7 @@ fn replaceState(_: *History, state: js.Value, _: ?[]const u8, _url: ?[]const u8,
|
||||
const url = if (_url) |u|
|
||||
try @import("../URL.zig").resolve(arena.allocator(), frame.url, u, .{})
|
||||
else
|
||||
try arena.dupeZ(u8, frame.url);
|
||||
try arena.dupeSentinel(u8, frame.url, 0);
|
||||
|
||||
const json = state.toJson(arena.allocator()) catch return error.DataClone;
|
||||
_ = try session.navigation.replaceEntry(url, .{ .source = .history, .value = json }, frame, true);
|
||||
|
||||
@@ -114,7 +114,7 @@ fn setHash(_: *const Location, hash: []const u8, frame: *Frame) !void {
|
||||
}
|
||||
// Scratch only: scheduleNavigation dupes the URL into its own arena
|
||||
// synchronously, so the local arena suffices.
|
||||
break :blk try std.fmt.allocPrint(frame.local_arena, "#{s}", .{hash});
|
||||
break :blk try frame.local_arena.print("#{s}", .{hash});
|
||||
};
|
||||
|
||||
// Per the Location hash setter, when the fragment doesn't change no
|
||||
|
||||
@@ -122,7 +122,7 @@ pub fn getGlobalPrivacyControl(_: *const Navigator) bool {
|
||||
}
|
||||
|
||||
pub fn getPlatform(_: *const Navigator) []const u8 {
|
||||
return switch (builtin.os.tag) {
|
||||
return switch (builtin.target.os.tag) {
|
||||
.macos => "MacIntel",
|
||||
.windows => "Win32",
|
||||
.linux => "Linux x86_64",
|
||||
|
||||
@@ -93,7 +93,7 @@ fn brandList() []const Brand {
|
||||
}
|
||||
|
||||
fn uaPlatform() []const u8 {
|
||||
return switch (builtin.os.tag) {
|
||||
return switch (builtin.target.os.tag) {
|
||||
.macos => "macOS",
|
||||
.windows => "Windows",
|
||||
.linux => "Linux",
|
||||
@@ -103,7 +103,7 @@ fn uaPlatform() []const u8 {
|
||||
}
|
||||
|
||||
fn uaArchitecture() []const u8 {
|
||||
return switch (builtin.cpu.arch) {
|
||||
return switch (builtin.target.cpu.arch) {
|
||||
.x86, .x86_64 => "x86",
|
||||
.aarch64, .aarch64_be, .arm, .armeb => "arm",
|
||||
else => "",
|
||||
@@ -111,7 +111,7 @@ fn uaArchitecture() []const u8 {
|
||||
}
|
||||
|
||||
fn uaBitness() []const u8 {
|
||||
return switch (builtin.cpu.arch) {
|
||||
return switch (builtin.target.cpu.arch) {
|
||||
.x86_64, .aarch64, .aarch64_be, .powerpc64, .powerpc64le, .riscv64 => "64",
|
||||
else => "32",
|
||||
};
|
||||
|
||||
@@ -112,10 +112,10 @@ pub fn observe(self: *PerformanceObserver, maybe_options: ?ObserveOptions) !void
|
||||
// Update entries.
|
||||
var interests: u16 = 0;
|
||||
for (entry_types) |entry_type| {
|
||||
const fields = @typeInfo(Performance.Entry.Type.Enum).@"enum".fields;
|
||||
inline for (fields) |field| {
|
||||
if (std.mem.eql(u8, field.name, entry_type)) {
|
||||
const flag = @as(u16, 1) << @as(u16, field.value);
|
||||
const info = @typeInfo(Performance.Entry.Type.Enum).@"enum";
|
||||
inline for (info.field_names, info.field_values) |field_name, field_value| {
|
||||
if (std.mem.eql(u8, field_name, entry_type)) {
|
||||
const flag = @as(u16, 1) << @as(u16, field_value);
|
||||
interests |= flag;
|
||||
}
|
||||
}
|
||||
@@ -182,7 +182,7 @@ pub fn interested(
|
||||
}
|
||||
|
||||
pub fn interestedIn(self: *const PerformanceObserver, kind: Performance.Entry.Type.Enum) bool {
|
||||
const flag = @as(u16, 1) << @intCast(@intFromEnum(kind));
|
||||
const flag = @as(u16, 1) << @intCast(@backingInt(kind));
|
||||
return self._interests & flag != 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -127,7 +127,7 @@ const NameContext = struct {
|
||||
pub fn hash(_: NameContext, key: Name) u32 {
|
||||
var hasher = std.hash.Wyhash.init(0);
|
||||
hasher.update(key.name.str());
|
||||
hasher.update(&.{@intFromEnum(std.meta.activeTag(key.namespace))});
|
||||
hasher.update(&.{@backingInt(std.meta.activeTag(key.namespace))});
|
||||
if (key.namespace == .other) {
|
||||
hasher.update(key.namespace.other);
|
||||
}
|
||||
@@ -1181,7 +1181,7 @@ fn sanitize(self: *const Sanitizer, root: *Node, safe: bool, frame: *Frame) !voi
|
||||
fn touch(touched: *std.ArrayList(*Node), parent: *Node, arena: Allocator) !void {
|
||||
// Siblings are removed one after another, so this catches most repeats.
|
||||
// Those it misses just get a second, no-op, merge.
|
||||
if (touched.getLastOrNull() != parent) {
|
||||
if (touched.last() != parent) {
|
||||
try touched.append(arena, parent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ fn init(
|
||||
const arena = try session.getArena(.small, "ServiceWorker");
|
||||
errdefer arena.release();
|
||||
|
||||
const owned_url = try arena.dupeZ(u8, script_url);
|
||||
const owned_url = try arena.dupeSentinel(u8, script_url, 0);
|
||||
const frame_id = session.nextFrameId();
|
||||
const loader_id = session.nextLoaderId();
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ pub fn init(url: []const u8, name_or_options: ?NameOrOpts, frame: *Frame) !*Shar
|
||||
const scope = blk: {
|
||||
const session = frame._session;
|
||||
// \x00 can appear in neither a URL nor a name
|
||||
const lookup_key = try std.fmt.allocPrint(frame.call_arena, "{s}\x00{s}", .{ resolved_url, options.name });
|
||||
const lookup_key = try frame.call_arena.print("{s}\x00{s}", .{ resolved_url, options.name });
|
||||
if (session.shared_workers.get(lookup_key)) |existing| {
|
||||
break :blk existing;
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ pub fn init(frame: *Frame, url: [:0]const u8, name: []const u8, worker_type: Wor
|
||||
const arena = try session.getArena(.small, "SharedWorker");
|
||||
errdefer arena.release();
|
||||
|
||||
const owned_url = try arena.dupeZ(u8, url);
|
||||
const owned_url = try arena.dupeSentinel(u8, url, 0);
|
||||
const frame_id = session.nextFrameId();
|
||||
const loader_id = session.nextLoaderId();
|
||||
const self = try WorkerGlobalScope.init(
|
||||
|
||||
@@ -286,13 +286,13 @@ fn exportJwk(key: *CryptoKey, exec: *const Execution) !js.Promise {
|
||||
|
||||
// The `alg` registry value depends on the algorithm and key length.
|
||||
const alg: []const u8 = switch (key._type) {
|
||||
.aes => try std.fmt.allocPrint(exec.local_arena, "A{d}{s}", .{
|
||||
.aes => try exec.local_arena.print("A{d}{s}", .{
|
||||
key._key.len * 8,
|
||||
key._algorithm.name[4..], // strip "AES-"
|
||||
}),
|
||||
.hmac => blk: {
|
||||
const hash: []const u8 = key._algorithm.hash orelse "SHA-";
|
||||
break :blk try std.fmt.allocPrint(exec.local_arena, "HS{s}", .{hash[4..]}); // strip "SHA-"
|
||||
break :blk try exec.local_arena.print("HS{s}", .{hash[4..]}); // strip "SHA-"
|
||||
},
|
||||
else => {
|
||||
log.debug(.not_implemented, "SubtleCrypto.exportKey", .{ .format = "jwk", .type = key._type });
|
||||
|
||||
@@ -154,7 +154,7 @@ fn setHost(self: *URL, value: []const u8) void {
|
||||
|
||||
pub fn getPort(self: *URL) []const u8 {
|
||||
const port = U.urlGetPort(self._url) orelse return "";
|
||||
return std.fmt.bufPrint(&self._port, "{d}", .{port}) catch unreachable;
|
||||
return std.mem.print(&self._port, "{d}", .{port}) catch unreachable;
|
||||
}
|
||||
|
||||
/// Spec requires us to silently ignore errors of this setter.
|
||||
|
||||
@@ -312,9 +312,9 @@ fn match(self: *const URLPattern, input: ?Input, base_url: ?[]const u8, exec: *c
|
||||
// The IDL conversion yields a fresh dictionary; that, not the
|
||||
// caller's object, is what ends up in result.inputs.
|
||||
const dict = local.newObject();
|
||||
inline for (@typeInfo(Init).@"struct".fields) |f| {
|
||||
if (@field(dict_init, f.name)) |v| {
|
||||
_ = try dict.set(f.name, v, .{});
|
||||
inline for (@typeInfo(Init).@"struct".field_names) |field_name| {
|
||||
if (@field(dict_init, field_name)) |v| {
|
||||
_ = try dict.set(field_name, v, .{});
|
||||
}
|
||||
}
|
||||
inputs = local.newArray(1);
|
||||
@@ -357,7 +357,7 @@ fn match(self: *const URLPattern, input: ?Input, base_url: ?[]const u8, exec: *c
|
||||
const groups = local.newObject();
|
||||
var key_buf: [16]u8 = undefined;
|
||||
for (component.group_names, 1..) |group_name, i| {
|
||||
const key = std.fmt.bufPrint(&key_buf, "{d}", .{i}) catch unreachable;
|
||||
const key = std.mem.print(&key_buf, "{d}", .{i}) catch unreachable;
|
||||
_ = try groups.set(group_name, try exec_result.get(key), .{});
|
||||
}
|
||||
@field(result, name) = .{ .input = value, .groups = groups };
|
||||
@@ -874,7 +874,7 @@ fn urlHost(url: *const U.Url) []const u8 {
|
||||
|
||||
fn urlPort(arena: Allocator, url: *const U.Url) Error![]const u8 {
|
||||
const port = U.urlGetPort(url) orelse return "";
|
||||
return std.fmt.allocPrint(arena, "{d}", .{port});
|
||||
return arena.print("{d}", .{port});
|
||||
}
|
||||
|
||||
fn urlPath(url: *const U.Url) []const u8 {
|
||||
@@ -1005,7 +1005,7 @@ fn canonicalizePort(arena: Allocator, value: []const u8, protocol: ?[]const u8)
|
||||
if (digits == 0) {
|
||||
return error.TypeError;
|
||||
}
|
||||
const serialized = try std.fmt.allocPrint(arena, "{d}", .{port});
|
||||
const serialized = try arena.print("{d}", .{port});
|
||||
if (protocol) |p| {
|
||||
if (defaultPort(p)) |default| {
|
||||
if (std.mem.eql(u8, default, serialized)) {
|
||||
@@ -1546,7 +1546,7 @@ const Parser = struct {
|
||||
if (name_token) |t| {
|
||||
name = t.value;
|
||||
} else if (regexp_or_wildcard != null) {
|
||||
name = try std.fmt.allocPrint(self.env.arena, "{d}", .{self.next_numeric_name});
|
||||
name = try self.env.arena.print("{d}", .{self.next_numeric_name});
|
||||
self.next_numeric_name += 1;
|
||||
}
|
||||
for (self.parts.items) |part| {
|
||||
|
||||
@@ -173,10 +173,17 @@ const ActionSequence = struct {
|
||||
frame.js.localScope(&ls);
|
||||
defer ls.deinit();
|
||||
|
||||
errdefer |err| {
|
||||
performSources(self, &ls) catch |err| {
|
||||
ls.toLocal(self.resolver).reject("WebDriver.actionSequence", ls.local.newString(@errorName(err)));
|
||||
}
|
||||
return err;
|
||||
};
|
||||
|
||||
ls.toLocal(self.resolver).resolve("WebDriver.actionSequence", {});
|
||||
return null;
|
||||
}
|
||||
|
||||
fn performSources(self: *ActionSequence, ls: *js.Local.Scope) !void {
|
||||
const frame = self.frame;
|
||||
const sources = self.sources.local(&ls.local).toArray();
|
||||
for (0..sources.len()) |i| {
|
||||
const source_val = try sources.get(@intCast(i));
|
||||
@@ -194,9 +201,6 @@ const ActionSequence = struct {
|
||||
}
|
||||
// "none" sources only carry pauses, which have no observable effect here.
|
||||
}
|
||||
|
||||
ls.toLocal(self.resolver).resolve("WebDriver.actionSequence", {});
|
||||
return null;
|
||||
}
|
||||
|
||||
fn finalize(ptr: *anyopaque) void {
|
||||
|
||||
Vendored
+3
-3
@@ -113,7 +113,7 @@ fn keys(self: *Cache, exec: *const Execution) !js.Promise {
|
||||
};
|
||||
|
||||
for (entries) |entry| {
|
||||
const url = try exec.call_arena.dupeZ(u8, entry.url);
|
||||
const url = try exec.call_arena.dupeSentinel(u8, entry.url, 0);
|
||||
const request = try Request.init(.{ .url = url }, null, exec);
|
||||
request.acquireRef();
|
||||
requests.appendAssumeCapacity(request);
|
||||
@@ -324,7 +324,7 @@ fn toEntry(allocator: Allocator, url: []const u8, response: *const Response, bod
|
||||
kv.* = .{ try arena.dupe(u8, header.name.str()), try arena.dupe(u8, header.value.str()) };
|
||||
}
|
||||
|
||||
entry.response_url = try arena.dupeZ(u8, response._url);
|
||||
entry.response_url = try arena.dupeSentinel(u8, response._url, 0);
|
||||
entry.status = response._status;
|
||||
entry.status_text = try arena.dupe(u8, response._status_text);
|
||||
entry.response_type = response._type;
|
||||
@@ -343,7 +343,7 @@ fn toResponse(entry: *const Store.Entry, exec: *const Execution) !*Response {
|
||||
._arena = arena,
|
||||
._status = entry.status,
|
||||
._status_text = try arena.dupe(u8, entry.status_text),
|
||||
._url = try arena.dupeZ(u8, entry.response_url),
|
||||
._url = try arena.dupeSentinel(u8, entry.response_url, 0),
|
||||
._body = .{ .bytes = try arena.dupe(u8, entry.body) },
|
||||
._type = entry.response_type,
|
||||
._is_redirected = entry.is_redirected,
|
||||
|
||||
@@ -79,15 +79,9 @@ const Extension = union(enum) {
|
||||
|
||||
/// Reified enum type from the fields of this union.
|
||||
const Kind = blk: {
|
||||
const info = @typeInfo(Extension).@"union";
|
||||
const fields = info.fields;
|
||||
const Tag = std.math.IntFittingRange(0, if (fields.len == 0) 0 else fields.len - 1);
|
||||
var names: [fields.len][:0]const u8 = undefined;
|
||||
for (fields, 0..) |field, i| {
|
||||
names[i] = field.name;
|
||||
}
|
||||
|
||||
break :blk @Enum(Tag, .exhaustive, &names, &std.simd.iota(Tag, fields.len));
|
||||
const names = @typeInfo(Extension).@"union".field_names;
|
||||
const Tag = std.math.IntFittingRange(0, if (names.len == 0) 0 else names.len - 1);
|
||||
break :blk @Enum(Tag, .exhaustive, names, &std.simd.iota(Tag, names.len));
|
||||
};
|
||||
|
||||
/// Returns the `Extension.Kind` by its name.
|
||||
@@ -98,9 +92,9 @@ const Extension = union(enum) {
|
||||
const kvs = comptime build_kvs: {
|
||||
const T = Extension.Kind;
|
||||
const EnumKV = struct { []const u8, T };
|
||||
var kvs_array: [@typeInfo(T).@"enum".fields.len]EnumKV = undefined;
|
||||
for (@typeInfo(T).@"enum".fields, 0..) |enumField, i| {
|
||||
kvs_array[i] = .{ enumField.name, @field(T, enumField.name) };
|
||||
var kvs_array: [@typeInfo(T).@"enum".field_names.len]EnumKV = undefined;
|
||||
for (@typeInfo(T).@"enum".field_names, 0..) |field_name, i| {
|
||||
kvs_array[i] = .{ field_name, @field(T, field_name) };
|
||||
}
|
||||
break :build_kvs kvs_array[0..];
|
||||
};
|
||||
@@ -180,7 +174,7 @@ fn getExtension(_: *const WebGLRenderingContext, name: []const u8, frame: *Frame
|
||||
|
||||
/// Returns a list of all the supported WebGL extensions.
|
||||
fn getSupportedExtensions(_: *const WebGLRenderingContext) []const []const u8 {
|
||||
return std.meta.fieldNames(Extension.Kind);
|
||||
return @typeInfo(Extension.Kind).@"enum".field_names;
|
||||
}
|
||||
|
||||
pub const JsApi = struct {
|
||||
|
||||
@@ -66,7 +66,7 @@ pub const State = struct {
|
||||
stroke_style: Style = .{ .color = color.RGBA.Named.black },
|
||||
|
||||
font_size: f64 = 10,
|
||||
font_buf: [font_capacity]u8 = default_font.* ++ [_]u8{0} ** (font_capacity - default_font.len),
|
||||
font_buf: [font_capacity]u8 = default_font.* ++ @as([font_capacity - default_font.len]u8, @splat(0)),
|
||||
font_len: u16 = default_font.len,
|
||||
font_overflow: ?[]const u8 = null,
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ fn reflect(comptime Inner: type, comptime field: ?[]const u8) Reflect {
|
||||
const R = fn_info.return_type.?;
|
||||
const has_error_return = @typeInfo(R) == .error_union;
|
||||
// The executor type is the last parameter of inner.next (after self)
|
||||
const Executor = fn_info.params[1].type.?;
|
||||
const Executor = fn_info.param_types[1].?;
|
||||
return .{
|
||||
.has_error_return = has_error_return,
|
||||
.ValueType = ValueType(unwrapOptional(unwrapError(R)), field),
|
||||
@@ -121,9 +121,9 @@ fn unwrapOptional(comptime T: type) type {
|
||||
|
||||
fn ValueType(comptime R: type, comptime field_: ?[]const u8) type {
|
||||
const field = field_ orelse return R;
|
||||
inline for (@typeInfo(R).@"struct".fields) |f| {
|
||||
if (comptime std.mem.eql(u8, f.name, field)) {
|
||||
return f.type;
|
||||
inline for (@typeInfo(R).@"struct".field_names, @typeInfo(R).@"struct".field_types) |field_name, field_type| {
|
||||
if (comptime std.mem.eql(u8, field_name, field)) {
|
||||
return field_type;
|
||||
}
|
||||
}
|
||||
@compileError("Unknown EntryIterator field " ++ @typeName(R) ++ "." ++ field);
|
||||
|
||||
Loaded 100 of 192 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user