Wire pane/browser control dispatcher to GTK state#25
Draft
mvbmir wants to merge 3 commits into
Draft
Conversation
Previously the control-socket METHODS array only exposed workspace.* and surface.send_text. Every pane.*, surface.*, and browser.* call returned -32601 unknown method. Same gap on upstream am-will/main. This commit wires the first tier of methods end-to-end against live GTK state, no JS eval: pane.list, pane.surfaces, surface.list, surface.current browser.open_split, browser.navigate, browser.url.get browser.back, browser.forward, browser.reload browser.screenshot, browser.eval IDs and refs: pane ids are u32 as string, surface ids are UUID strings, refs are "pane:N" / "surface:UUID". Inputs accept raw ids or prefixed refs via normalize_handle. Outputs always include both id and ref so callers never have to reconstruct either form. browser.open_split defaults to hosting the new browser in a pane other than the focused (caller) pane. If only one pane exists it splits the focused pane horizontally and places the browser in the new split, so a caller never clobbers its own terminal. The source pane can be overridden explicitly via source_surface. browser.screenshot uses webkit6::WebView::snapshot with SnapshotRegion:: Visible → gdk_texture_save_to_png, rejecting empty textures instead of writing a zero-byte file. The CLI now forwards --out as the `path` parameter so the server writes directly to the caller's target rather than leaking a random /tmp path. Async ops (navigate/open_split/screenshot/eval) use mpsc reply channels with a 30s timeout; sync ops default to 5s.
…rors) Adds the JS-eval tier of the browser dispatcher on top of the pane/nav wiring from 1697f3c. No CLI changes — all methods reachable via limux-cli browser subcommands or raw control socket RPC. Init script (browser_init.js) is installed via UserContentManager at InjectionTime::Start on every top-frame navigation. It exposes window.__limux with: - Ref tagger + MutationObserver that keep `data-limux-ref="eN"` on every interactive node so refs survive DOM mutations within a page. - Ring buffers for console.{log,warn,error,info,debug} and for window.onerror + unhandledrejection, capped at 5000 entries each, with a monotonic seq counter the caller filters by (webkit6 clamps Date.now() / performance.timeOrigin to i32::MIN so wall-clock is unusable — performance.now() is the only working time source). - history.pushState / replaceState hook that fires a limux:navigation event + bumps a navCount for SPA handling. - isReady() probe (readyState complete AND DOM quiet ≥ 500ms). - isEditable() probe for active-element focus state. Snapshot walker (browser_snapshot.js) returns a token-efficient AX tree keyed on the init-script's refs. Output format: page <url> title "<title>" - banner - link "Home" [ref=e1] - navigation "Main" - link "Docs" [ref=e2] - main - heading "Sign in" [level=1] - form - textbox "Email" [ref=e4, required] - button "Sign in" [ref=e7] Each snapshot returns {url, title, hash, snapshot_text, refs, ...} with djb2 hash for future --since diff support. Scope flags (--selector, --max-depth, --full-tree, --raw-html) included. New methods wired via generic BrowserEval dispatcher: browser.snapshot browser.click, dblclick, hover, focus browser.fill, type, press browser.check, uncheck, select browser.scroll, scroll_into_view browser.wait, wait_ready browser.get.{text, title, html, value, attr, count, box} browser.find.{role, text, label, placeholder, testid} browser.console.{list, clear} browser.errors.{list, clear} browser.is_ready, is_editable Every action goes through a resolve-target helper that distinguishes refs (via window.__limux.refInfo) from selectors, returning a structured REF_NOT_FOUND error when a ref is no longer attached rather than silently acting on the wrong element. find.text prefers interactive descendants over structural ancestors so a paragraph wrapping a single link doesn't shadow the link itself.
Rust 1.95 stable (released between main's last green CI run and this
PR's) promotes collapsible_match to a warning, which the workspace's
check.sh treats as an error via -D warnings.
The flagged patterns in limux-core are `match combo_norm { pattern
=> { if palette_visible { … true } else { false } } … }` — they
collapse cleanly into match guards: `pattern if palette_visible =>
{ … true }`. Behavior is unchanged; any non-match combo hits the
catch-all `_ => false` arm.
Unrelated to the redesign; included here to keep CI green.
12 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Wires the pane, surface, and browser control-socket methods to the real GTK state. Until now
limux-cliexposed a rich set of commands but the GTK host'scontrol_bridge.rsonly registeredworkspace.*+surface.send_text, so anything else returned-32601: unknown method. Closes #22 (fork tracking) and fills the gap flagged in #21.Two commits, split by layer:
1. Pane/surface introspection + browser navigation (no JS eval)
pane.list,pane.surfaces,surface.list,surface.currentbrowser.open_split,browser.navigate,browser.url.get,browser.back,browser.forward,browser.reload,browser.screenshot,browser.evalIDs: pane
u32as string, surface UUID string, refspane:N/surface:UUID. Inputs accept raw ids or prefixed refs; outputs always return both forms.browser.open_splitdefaults to hosting the new browser in a pane other than the focused (caller) pane. If only one pane exists it splits the focused pane horizontally and places the browser in the new split, so a caller never clobbers its own terminal. The source pane can be overridden viasource_surface.browser.screenshotuseswebkit6::WebView::snapshotwithSnapshotRegion::Visible→gdk_texture_save_to_png. Rejects empty textures rather than writing zero-byte files. The CLI forwards--outas thepathparameter so the server writes directly to the caller's target.2. Browser JS-eval tier (snapshot, actions, console, errors)
An init script (
browser_init.js) is installed viaUserContentManageratInjectionTime::Starton every top-frame navigation. It exposeswindow.__limuxwith:data-limux-ref=\"eN\"on every interactive node so refs survive DOM mutations within a page.console.*andwindow.onerror/unhandledrejection, capped at 5000, with a monotonicseqcounter the caller filters by (webkit6 clampsDate.now()/performance.timeOrigintoi32::MIN—performance.now()is the only working time source, so wall-clockts_msis informational andseqis authoritative).history.pushState/replaceStatehooks for SPA navigation tracking.isReady()probe (readyState complete + DOM quiet ≥ 500ms).isEditable()probe for focused-element state.A snapshot walker (
browser_snapshot.js) returns a token-efficient AX tree keyed on the init-script's refs:Each snapshot also returns a
djb2hash (future-facing--sincediff flag already plumbed through). Scope flags (--selector,--max-depth,--full-tree,--raw-html) supported.Methods wired via a generic
BrowserEvaldispatcher:browser.snapshotbrowser.click,dblclick,hover,focusbrowser.fill,type,pressbrowser.check,uncheck,selectbrowser.scroll,scroll_into_viewbrowser.wait,wait_readybrowser.get.{text, title, html, value, attr, count, box}browser.find.{role, text, label, placeholder, testid}browser.console.{list, clear}browser.errors.{list, clear}browser.is_ready,is_editableEvery action goes through a resolve-target helper that distinguishes refs (via
window.__limux.refInfo) from selectors, returning a structuredREF_NOT_FOUNDerror when a ref is no longer attached rather than silently acting on the wrong element.find.textprefers interactive descendants over structural ancestors so a paragraph wrapping a single link doesn't shadow the link itself.Not in this PR (follow-ups)
Planned in a stacked PR on top of this one:
addinitscript/ highlightnavigate_and_wait,click_and_await_nav,fill_and_submit)browser.screenshot --annotateref overlaybrowser.snapshot --since <hash>diff mode (already plumbed through, needs JS-side diff computation)Test plan
limux-cli --json list-panesreturns real panes (not-32601)limux-cli --json browser open 'about:blank'returns a surface idlimux-cli browser --surface <S> navigate https://example.com+urlround-triplimux-cli browser --surface <S> screenshot --out /tmp/shot.pngproduces a valid PNG (non-empty, correct dimensions)limux-cli browser --surface <S> snapshotreturns AX tree + refs keyed on interactive nodeslimux-cli browser --surface <S> click --selector @e1fires and navigates where expectedbrowser.console.list+browser.errors.listvia raw socket return ring-buffer contents with monotonicseqbrowser.open_splitwithout--source-surfacetargets a non-caller pane (splits if none exists)