Conversation
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
|
Tested end-to-end with real Chrome DevTools (Chrome's bundled inspector connected to All four flows work:
Minor observations (non-blocking)
|
|
Re-verified the computed-style used-value fixes (0182075, e186e63) with real Chrome DevTools:
|
3dd2492 to
525afa5
Compare
e186e63 to
a97827c
Compare
a97827c to
19e8e20
Compare
|
Re-tested the rebased branch (onto
Non-blocking observations
|
|
Fixed the "picker doesn't expand/reveal the picked node in the tree" issue (7fff47c): the session now tracks which nodes' children were already sent and skips resending Verified with real Chrome DevTools on the CPU backend ( |
7fff47c to
829e833
Compare
|
Fixed comments showing empty in devtools (62cd6fe): Verified with real Chrome DevTools on the CPU backend against a page containing |
|
Fixed inspect-mode hover not revealing nodes in the tree (1e37614): hovering now emits the node's ancestor path via Verified with real Chrome DevTools on the CPU backend against a nested page, from a fresh connection with the tree collapsed: merely hovering elements in the Blitz window during inspect mode expands and highlights the hovered row live, updating as the hover moves between elements. Picking and Escape-cancel still work. |
1e37614 to
61d98fb
Compare
1d125db to
b646f5a
Compare
5044eb2 to
c9641b9
Compare
c9641b9 to
1464222
Compare
|
Migrated the transport to std::net + blocking tungstenite (995703a): nothing here needs async — all real work already happens synchronously on the event-loop thread via Smoke-tested end-to-end with real Chrome DevTools on the CPU backend ( |
d7c18f7 to
1f6494c
Compare
|
Verified the live-editing feature (11d1f5e) end-to-end with real Chrome DevTools on the CPU backend (
Style edit applied — Blitz window repainted orange with updated tree row: |
|
Verified the sub-document targets feature (b09eefe) end-to-end with real Chrome DevTools against the actual browser app (
Picker on the tab target — hover hit the exact "Learn more" link with the tree revealed live: Note: about: pages (e.g. a fresh about:newtab tab) render inside the chrome document and only appear as separate targets once navigated to a real page. |
|
Verified inline style editing end-to-end with real Chrome DevTools on the CPU backend (
Key behaviors the implementation needed for real DevTools (beyond a naive setStyleTexts):
|
58d0c59 to
f0d1bc0
Compare
Implements HTTP discovery (/json/list, /json/version) plus a WebSocket endpoint speaking plain-JSON CDP, with the DOM, CSS and Overlay domains needed for Chrome DevTools' Elements panel: DOM tree inspection (with anonymous/whitespace nodes filtered), matched/computed/inline styles from Stylo, box model geometry from Taffy (incl. inline fragment rects), node highlight overlays and the element picker (inspect mode). Integrated into blitz-shell behind the devtools feature, opt-in via the BLITZ_CDP_PORT env var, using synchronous document access on the event loop thread via a DocumentProvider adapter.
Chrome DevTools builds the Box Model diagram from computed style, and browsers report used (post-layout) values there: width/height, margins, paddings and border widths now come from layout instead of the specified values, so the content area no longer shows 'auto x auto'.
Resending DOM.setChildNodes for a parent whose children were already sent makes the devtools frontend replace its node objects, detaching the tree's selection/expansion state — so picking an element updated breadcrumbs and styles but didn't expand/reveal the node in the Elements tree. Track which nodes have had their children sent per session and skip them when emitting ancestor paths for querySelector / pushNodesByBackendIdsToFrontend.
Chrome reveals the node under the cursor in the Elements tree in realtime while inspect mode is active, which requires the frontend to know the node before the Overlay.nodeHighlightRequested event: send the (not yet sent parts of the) node's ancestor path via DOM.setChildNodes first.
Forward to blitz-shell/devtools so the CDP server can be enabled with e.g. 'cargo run -p rdme --features devtools' + BLITZ_CDP_PORT.
Nothing in the server needs async: all real work happens synchronously on the event-loop thread via process_messages(), and connection counts are tiny. Replace the tokio runtime with a listener thread and one thread per connection, which alternates between reading (with a short socket read timeout) and draining the outgoing message queue. Drops the tokio, tokio-tungstenite and futures-util dependencies.
DOM.setAttributeValue, DOM.setAttributesAsText, DOM.removeAttribute (with DOM.attributeModified/attributeRemoved events) and DOM.setNodeValue for text and comment nodes (with DOM.characterDataModified). Mutations go through DocumentMutator so snapshots/restyle/damage are handled, and request a redraw.
Each sub-document (e.g. a browser tab) is enumerated recursively as an inspectable target of its own. While picking on a sub-document, window coordinates are translated into the sub-document's coordinate space by the host element's position and scroll offset (mirroring pointer event forwarding), and shell redraw requests resolve windows through their sub-documents.
Inline styles now carry a synthetic per-element style sheet id and source ranges into their serialized cssText, which makes the Styles pane treat them as editable. CSS.getStyleSheetText serves that text and CSS.setStyleTexts replaces the element's style attribute (via the document mutator), returning the re-serialized style and emitting CSS.styleSheetChanged / DOM.attributeModified.
The frontend edits a sub-range of the sheet text (a single declaration's range when edited inline), so replacing the whole style attribute with the edit's text dropped the other declarations and corrupted multi-token values as the frontend's text model drifted. Each edit's text is now spliced into the current sheet text at the given range.
DevTools live-commits setStyleTexts on every keystroke and adopts the text the server echoes back as its editing model. Reporting a longhand- expanded re-serialization therefore corrupted shorthand edits mid-typing. The inline style sheet's text is now the authored style attribute value, with declarations and ranges scanned from it verbatim.
DevTools disables a declaration by commenting it out; reporting the comment as plain declaration text left the frontend without a disabled property to re-enable, so clicking the checkbox again nested a second comment and invalidated the following declarations. Declarations wrapped in /* name: value; */ comments are now reported with disabled: true and the comment as their text/range, so the checkbox round-trips.
…text The frontend computes all of a batch's ranges against the same snapshot of the sheet text, so applying edits sequentially against the mutated text misaligns later edits' offsets. Resolve every range against the original text up front and apply the splices back-to-front.
Closing tags on void elements (<img ...></img>, <br></br>) are invalid markup that re-parses into a different document. Non-void empty elements keep their explicit closing tag, matching Chrome's serializer (omitting it would make the element swallow following content when re-parsed).
d1ed18f to
17a545f
Compare




























Summary
Adds a Chrome DevTools Protocol (CDP) server so Chrome DevTools' Elements panel works against Blitz documents: DOM tree, Styles (matched rules), Computed, Box Model, highlight overlays and the element picker (inspect mode). Read-only: no rule editing, no multi-frame, no JS runtime/console (
Runtime/Page/Targetand other irrelevant domains are stubbed just enough for the frontend to boot).Based on
main(uses theDevtoolSettings.highlight_node/element_pickerfields and paint overlay from #574, and comment contents from #576, both now merged). This branch does not include the Firefox devtools server work (#557/#558); the shell plumbing they share (theDocumentProvideradapter,DevtoolsPollwake event, and picker input interception incl. swallowing the matching release of a picking click) is included here directly.New crate
packages/blitz-cdp-server:std::net+ blockingtungstenite(no async runtime — nothing here needs one): a listener thread accepts connections; each connection gets a thread serving both HTTP discovery (/json/list,/json/version— onepagetarget per document at/devtools/page/{doc_id}) and the WebSocket CDP endpoint (plain JSON{id, method, params}/ results / events, echoing flat-modesessionId), alternating between reads (short socket read timeout) and draining the outgoing message queue. Messages are queued and processed synchronously on the document-owning thread viaprocess_messages(&mut dyn DocumentProvider).DOM:getDocument,requestChildNodes(+DOM.setChildNodesevents),querySelector,pushNodesByBackendIdsToFrontend,getBoxModel,getOuterHTML. Node ids areNodeId::as_u64() + 1(CDP node ids must be non-zero);nodeId == backendNodeId. Anonymous layout nodes and whitespace-only text nodes are filtered from the exposed tree. Comment nodes report their contents asnodeValue.CSS:getMatchedStylesForNode(Stylo rule tree viastyles.rules.self_and_ancestors(), selector text/origin recovered by mapping declaration-block pointers to rules found by walking the document's stylesheets; inlinestyleattribute reported asinlineStyle;inheritedentries per ancestor with inherited-only declarations),getComputedStyleForNode(all longhands viaNonCustomPropertyId::iter(), with used post-layout px values substituted for width/height, margin, padding, border-width, and insets of positioned elements),getInlineStylesForNode.Overlay:highlightNode/hideHighlightdriveDevtoolSettings.highlight_node(per-fragment overlay for inline elements from Inline fragment rects: highlight inline spans per line box #569);setInspectModetogglesDevtoolSettings.element_picker. Embedder picker input arrives vianotify_picker_event()and emitsOverlay.nodeHighlightRequested(hover, preceded by the node's ancestor path viaDOM.setChildNodesso the frontend reveals it in the tree in realtime) /Overlay.inspectNodeRequested(click), after promotion to the nearest non-anonymous element.get_client_bounding_rect()for the border box (bounding rect of line-box fragments for non-atomic inlines, which report zero box insets) and Taffyfinal_layout()insets otherwise.blitz-shellintegration behind thedevtoolsfeature: opt-in viaBLITZ_CDP_PORT; the server is woken via aDevtoolsPollshell event and processes messages synchronously on the event-loop thread through aDocumentProvideradapter over the application's windows. Thebrowser,rdmeanddioxus-nativecrates gain forwardingdevtoolsfeatures (e.g.cargo run -p rdme --features devtools).Testing
packages/blitz-cdp-server/tests/elements_panel.rs: real WebSocket client drives the Elements-panel sequence (discovery → enables → getDocument → requestChildNodes → querySelector → matched/computed/inline styles → getBoxModel incl. wrapped inline span → highlightNode/hideHighlight → setInspectMode + simulated picker hover/pick → pushNodesByBackendIdsToFrontend) asserting on responses and events.cargo fmt,cargo clippy --workspace --features blitz-shell/devtools,cargo test -p blitz-cdp-serverpass.WPT results
No changes in test results compared to
main.Generated by the WPT workflow.
Link to Devin session: https://dioxus.staging.devinenterprise.com/sessions/f46cbcd2db8548f5a54c1fe02a0e7eea
Requested by: @nicoburns