Commit Graph
29 Commits
Author SHA1 Message Date
Karl Seguin 2e6999f20b chore: make declarations private if they don't need to be public
This change is 99%  s/pub//   + a handful of dead code removal.
2026-09-10 14:42:09 +08:00
Adrià Arrufat 88d133a676 cli: suggest the closest flag or command on a typo
An unknown --flag now logs the nearest accepted spelling within two
edits as did_you_mean, painted green next to the red typo in the pretty
log format; logfmt stays plain. A bare first argument within two edits
of a command name is rejected with the same hint instead of being
fetched as a url.

The Levenshtein helper moves from SlashCommand into string.zig so the
agent REPL and the CLI share it, with the table widened to fit the
longest flag name.
2026-09-08 16:50:46 +02:00
Adrià Arrufat f37d96c285 css: compare visibility keyword values case-insensitively
CSS keywords are ASCII case-insensitive, but StyleManager matched
display:none / visibility:hidden|collapse / opacity:0 / pointer-events:none
with exact String.eql, so `style="DISPLAY: NONE"` or a `.x { Visibility:
Hidden }` rule left the element visible to checkVisibility,
getComputedStyle, the semantic tree and interactiveElements.

Compare at the check sites via a new String.eqlSliceIgnoreCase rather than
lowercasing declared values, which would corrupt content, url() and custom
property values that el.style must reflect verbatim.
2026-08-25 14:53:35 +02:00
Karl Seguin 876ff8400b mem: rework string.String to be align(8)
Moves from packed to extern which causes alignment to drop from 16 to 8. Paired
with https://github.com/lightpanda-io/browser/pull/3104 this results in a -8
bytes per Text node.
2026-08-03 13:07:28 +08:00
Karl Seguin 6a83881634 chore: add lp.IS_DEBUG and lp.IS_TEST
Change all users to builtin.mode and built.is_test
2026-08-01 09:15:18 +08:00
Karl Seguin 122a4f1001 perf: improve ResizeObserver performance
https://github.com/lightpanda-io/browser/pull/3000 improved the correctness of
ResizeObserver. The main changes were (a) making sure an observe results in
an initial callback and (b) invoking the callback for cases that we can
identity (e.g. visibility change).

Like the other observers, we triggered a check on domChanged. But, unlike the
other observers, the check is relatively expensive, namely because it involves
style lookups.

This commit introduces a number of performance improvements to reduce the check
and dispatch frequency.

1 - Only trigger on an allow list of attribute changed (id, class, hidden, width
 ...)
2 - Pre-filter only on observed elements
3 - Leverage the visibility cache for more efficient delivery
2026-07-24 11:23:00 +08:00
Karl Seguin 8fbcc7e5c1 Merge pull request #3015 from lightpanda-io/cdp-utf8-sanitization
cdp: Sanitize non-UTF 8 values
2026-07-24 08:03:38 +08:00
Karl Seguin 5b12c42df2 cdp: Sanitize non-UTF 8 values
Builds on https://github.com/lightpanda-io/browser/pull/2972 in order to fix
https://github.com/lightpanda-io/browser/issues/2992

I couldn't think of a generic way to fix this. Created a SafeString which
wraps a `[]const u8` with a custom jsonStringify function. This is now applied
to both header names and values.

The existing latin1 to utf8 conversion is now extracted into string.js and used
in Frame for the filename. This was moved to Frame because the same issue
could cause issues trying to save the file.
2026-07-22 14:59:33 +08:00
Karl Seguin 8e42d63c1c zig: Zig 0.16
Built against https://github.com/lightpanda-io/zig-v8-fork/tree/zig-0.16 but
it doesn't require a new v8 build.

Built against https://github.com/lightpanda-io/boringssl-zig/tree/zig-0.16
since the current fork we point to isn't updated.

A global std.Io instance, lp.io. Way easier this way and requires 0 changes to
our libcurl integration / event loop.

Network code uses a new layer that does what Zig 0.15's posix package used to
do. Again, quicker migration that way. But, as long as we have the global IO,
and given the half-baked nature of networking in std.Io 0.16, this just makes
sense. Things can be migrated as needed.

The std.time.* -> std.Io.Timestamp/Clock/Duration resulted in _a lot_ of
changes. ArrayList = .{} -> ArrayList -> .empty also resulted in a lot of
changes, but that's obviously superficial. As is the trimLeft/trimRight ->
trimStart/trimEnd rename.

Locking adopt the `Uncancelable` variants, e.g. mutex.lockUncancelable() to
preserve the error-free signature (and, because cancellation would be something
we'd have to put more thought into).

std.json.ObjectMap is now unmanaged, so the allocator had to be passed along.
However, there's still a deprecated managed variant of MemoryPool, so I switched
to it (we can do a small follow up PR to move to the unmanaged after).

I tried use_llvm = false, but it locks my computer, consuming RAM until MacOS
gives me a popup I've never seen before, begging me to start killing processes.

Agent and the networking stuff saw the most significant changes.
2026-07-22 13:26:03 +08:00
Karl Seguin f32606a27b mem: Store Element's attributes as an array, not a linked list
An element's attributes are currently stored as a ?*Attribute.List which is an
intrusive doubly linkedlist of Attribute.Entry. This has two small benefits:

1 - Elements with no attributes only grow by 8 bytes
2 - Attribute list mutation (additions/deletion) are linkedlist cheap

This commit embeds an ArrayList-like structure directly in Element. The impact
being:

1 - Elements with no attributes now grow by 16 bytes (+8)
2 - Elements with 1+ attribute shrink from 32 -> 16 bytes (-16)
3 - Mutations are more expensive
4 - Fewer indirections (and better cache locality)
5 - Much fewer allocations (4 attributes go from 5 allocations to 1)
6 - Every Attribute shrinks by 16 bytes (no need for next/prev link)

While looking at a few popular sites (amazon product, redit post, ...), the
majority of elements have 1+ element and most attributes are never accessed in
JS and, when they are, reads are more frequent than writes (in fact, even
internally to support other WebAPIs, reads far outweigh writes).

There's virtually no real world site where this shouldn't reduce memory usage
by hundreds of KB and also improve performance (in a way that isn't significant
to the overall page loading though).
2026-07-08 18:42:55 +08:00
Karl Seguin 8d5a1f2450 wpt: Better blob mime handling
Largely aimed at /mimesniff/mime-types/parsing.*.html. Adds ~2000 passing cases.

The blob API is now a bit simpler (hence FormData/REquest/Response/WebSocket)
being touched, but more logic is now in Mime.zig to parse/validate MIME types.
Better escaping support, correct casing and handling edge cases with multiple
charset, or "charset" as a value, .etc...

Headers also hook into this to validate / normalize header name and values.
2026-06-17 13:56:40 +08:00
Adrià Arrufat 4b3e18fda2 agent: extract save helpers to save.zig (#2684)
* Revert "agent: enhance /save progress and verification feedback"

This reverts commit 54f467d1fa.

* Revert "agent: verify synthesized scripts during /save"

This reverts commit b141da30ca.

* agent: extract save helpers to save.zig

Moves pure helper functions related to the `/save` command (parsing,
validation, file writing, prompt shaping) from `Agent.zig` to a
dedicated `save.zig` module.
2026-06-09 19:06:09 +02:00
Adrià Arrufat b141da30ca agent: verify synthesized scripts during /save
Introduces a multi-step synthesis process for `/save` that derives a
logical JSON output schema and uses a dry-run runtime to verify
candidate scripts. The LLM can now run and self-correct its scripts
using a new `run_script` tool before finalizing the save.
2026-06-09 16:53:39 +02:00
Adrià Arrufat 2a7bda3608 string: add string.isOneOf and deduplicate helpers 2026-06-08 09:04:36 +02:00
Adrià Arrufat b4d55eb863 string: extract truncateUtf8 helper
Moves the UTF-8 truncation logic from Spinner's `utf8FloorTo` to a
shared `truncateUtf8` function in `string.zig`. Reuses it in both
Spinner and markdown rendering, and adds comprehensive tests.
2026-05-26 16:52:09 +02:00
Adrià Arrufat 45da2c8196 refactor: localize keyword check and simplify command tests 2026-05-11 20:08:38 +02:00
Adrià Arrufat 729de62012 test: add keywordSyntax and isAllUpper tests
Adds unit tests for command keyword parsing and string casing. Also removes the unused `history_path` field from the `Terminal` struct.
2026-05-11 17:52:49 +02:00
Adrià Arrufat 98b082ddc1 terminal: improve REPL prompt, completion, and highlighting
- Cache environment variable names to improve completion performance.
- Refactor terminal styles into constants.
- Move `isAllUpper` to `string.zig` and `meta_names` to `SlashCommand.zig`.
- Align quoted string scanning logic with the slash command parser.
2026-05-11 17:52:49 +02:00
Adrià Arrufat 471ba5baf6 String: refactor isAllWhitespace into String 2026-03-06 15:52:53 +09:00
Karl Seguin a50597ff27 Merge pull request #1669 from lightpanda-io/more_interned_strings
Expand the strings we intern
2026-02-27 17:30:21 +08:00
Karl Seguin 870fd1654d Change CData._data from []const to String (SSO)
After looking at a handful of websites, the # of Text and Commend nodes
that are small (<= 12 bytes) is _really_ high. Ranging from 85% to 98%. I
thought that was high, but a lot of it is indentation or a sentence that's
broken down into multiple nodes, eg:

<div><b>sale!</b> <span class=price>$1.99</span> buy now<div>

So what looks like 1 sentence to us, is actually 3 text nodes.

On a typical website, we should see thousands of fewer allocations in the
page arena for the text in text nodes.
2026-02-27 12:53:54 +08:00
Karl Seguin 38bc912e4e Expand the strings we intern
Based on analysis of a handful of websites (amazon product, github, DDG, reddit)
2026-02-27 11:17:06 +08:00
Karl Seguin a19a125aec Remove unused import
And a few unused functions
2026-01-29 19:44:10 +08:00
Karl Seguin 862520e4b1 micro-optimize String.eql(String) 2026-01-26 07:52:27 +08:00
Karl Seguin a3d2dd8366 Convert most Attribute related calls from []const u8 -> String 2026-01-26 07:52:27 +08:00
Karl Seguin 16ef487871 Make "Safe" variants of Attribute work on String 2026-01-26 07:52:27 +08:00
Karl Seguin 54c45a0cfd Make js.Bridge aware of string.String for input parameters
Avoids having to allocate small strings when going from v8 -> Zig. Also
added a discriminatory type, string.Global which uses the arena, rather than
the call_arena, if an allocation _is_ necessary. (This is similar to a feature
we had before, but was lost in zigdom). Strings from v8 that need to be
persisted, can be allocated directly v8 -> arena, rather than v8 -> call_arena
-> arena.

I think there are a lot of places where we should use string.String - where
strings are expected to be short (e.g. attribute names). But started with just
document.querySelector and querySelectorAll.
2026-01-26 07:52:27 +08:00
Karl Seguin 1164da5e7a copyright notices 2025-11-14 10:52:43 +08:00
Karl Seguin b047cb6dc1 remove libdom 2025-10-27 22:14:59 +08:00