Repository navigation
Conversation
View() registers data frames, matrices and lists with jdv and relays the jdv protocol through a new jdv_rpc sess request. The existing AG Grid and List Viewer webviews are reused; an extension-side adapter converts AG Grid sort/filter models to jdv queries and maps List Viewer paths to jdv typed paths. Arrow data and options(sess.dataviewer = "sess") keep the sess data viewer.
Arrow tables, record batch readers, nanoarrow streams and Polars data frames are viewed with jdv without converting them to data frames. The extension host listens for jdv's local transport per session; sess asks for the address with request_client() and sets it only while calling jdv_view(). Received Arrow IPC pages are kept in a bounded cache in the extension host, decoded with apache-arrow, and served to the existing AG Grid infinite row model with an unknown row count. Sorting and filtering are disabled for these forward-only streams.
…view jdv now treats an embedded session and the transport as mutually exclusive, so View() connects jdv to the per-session listener once and registers all views there. The jdv_rpc relay is removed.
Grids, trees and child views now arrive as view/open notifications on the socket. Tree children use atomic leaves and hide attributes, and child grids are opened in paged mode.
When View() is called with a single symbol, bind the jdv view to the variable that holds the value so that reassigning it updates the view. The binding is only used on R 4.6.0 or later, can be disabled with options(sess.dataviewer.track = FALSE), and registration falls back to an untracked view if jdv rejects the binding.
Handle the view/update_failed notification that jdv sends when a tracked variable changed but the view could not be rebuilt, and show it as a warning.
…ta viewer The new r.session.viewers.trackVariables setting (default on) is passed to sess as connect(track_variables =) by the attach script and, for terminals started by the extension, through SESS_TRACK_VARIABLES. options(sess.dataviewer.track) still takes precedence when set. The setting applies to sessions attached after it is changed.
…dates in place When the view descriptor has capabilities.refresh, the grid and tree viewers show a Refresh button that sends view/refresh and reports failures in the status area. A newer generation announced with reason "tracked" or "refresh" updates the panel without revealing it; other reasons keep revealing it.
Look up the variable to follow with jdv::jdv_binding() instead of a hand-written environment walk, never pass a binding for sequential Arrow sources, and retry without the binding only on jdv errors.
- Offer text filters only for string and factor columns; list, other and unknown column types are display-only. - Support duration columns with numeric filters in the column's units. - Prefer the title jdv gives a child view. - Add a Follow toggle that pauses or resumes variable tracking with view/track and reflects view/tracking notifications.
Use grid/rows, source_row and row_labels, the jdv-json encoding, categorical columns and native_type. Validate grid descriptors, treat omitted capabilities as false, require max_page_rows for Arrow streams, and read the producer hello (opaque session, required unacked limits, wake flag). Unknown error codes become producer_error. The expected R pid check is dropped because the session id is opaque; the 0600 listener address is only given to this session.
Hold one registry-free jdv handle per table or list output, answer paged queries and child pages through inspections, and open the value in the Data Viewer by registering it with jdv over a host-provided address. The dataview registry still serves outputs when jdv is not installed.
Convert the handle descriptor and first page into the existing renderer data, query pages with sort and filter through the handle, explore lists with typed paths, open tables and list items in the Data Viewer, and release handles when completed cells are cleared. Legacy dataview outputs keep working when jdv is not used.
renkun-ken
left a comment
There was a problem hiding this comment.
Reviewed 5599b4ff7204bc451626686e7139122cb23a571b. I found two issues in the Interactive jdv path, both reproduced with the real agent/R backend: shortened pages can skip rows, and opening a nested data frame can dispatch a custom [[ method that jdv's tree browser deliberately avoids. Details and reproduction inputs are inline.
Validation used R 4.6.1, the PR's built dist/resources/sess installed in an isolated library, development jdv at 2cd06199364baa547d952366ea77df178ee4c86e, and nanoarrow 0.9.0. Build, TypeScript compilation, lint, 35 focused Node tests, 12 Data Viewer script tests, five existing real-R jdv integration tests, 68 assertions in the two new sess test files, and source-identity checks passed. An additional real-R Arrow IPC test decoded numeric, string, logical, date, timestamp, and missing values successfully. The two additional regression reproductions failed as described inline.
All five GitHub checks are green. I did not manually exercise the VS Code webviews.
renkun-ken
left a comment
There was a problem hiding this comment.
Follow-up review of 55799dfeddb76add0b78243c625044b4298f7f8c.
The previous nested-list extraction finding is fixed: the original custom-[[ reproduction now opens successfully through the real Interactive agent, and the new root/child handle tests pass. The on-demand paging loop also now returns IDs 1–100 and 101–150 without gaps when the combined initial preview fits the event limit.
Two issues remain in the new changes, detailed inline:
- Refilling the initial preview can exceed the 2 MiB rich-event limit. The original 100,000-character-cell reproduction now emits only a truncation event, losing the entire inline table.
- The new handle-registration test leaves an embedded jdv session behind, so running it followed by
test-jdv.Rproduces an order-dependent test failure.
Validation used R 4.6.1, this revision's built sess in an isolated library, jdv 660703e (including jdv_handle_register()), and nanoarrow 0.9.0. Build, TypeScript compilation, lint, 54 focused Node/viewer tests, six existing real-R jdv integration tests, source-identity checks, and additional nested-list, contiguous-paging, and Arrow IPC checks passed. The two R files pass separately (51 and 50 assertions), but together produce 100 passes and one failure. The original wide-preview regression fails through the real agent/R path as described inline.
All five GitHub checks are green; the current Ubuntu log confirms both jdv R test files are skipped because jdv is not installed. I did not manually exercise the VS Code webviews.
|
I believe I have addressed all of the points. |
renkun-ken
left a comment
There was a problem hiding this comment.
Reviewed de07a676c7af729ba8e30ea99a3091b34d885048. All of my previously reported findings are resolved, and I found no remaining actionable issues in the latest changes. LGTM.
- The original 100,000-character-cell input now produces a bounded table display instead of a truncation event. Real-agent tests retrieve all 150 rows without gaps at both 20- and 100-row page sizes. Browser checks also confirm automatic completion of partial/empty previews, correct Next/Reset behavior, and no requests for disconnected, stopped, or archived outputs.
- The handle and View R test files now pass together: 134 assertions, with no leaked embedded jdv session.
- The nested classed-list reproduction still passes. I also checked the Arrow numeric-string preservation, row-count hint scoping, and a real Polars stream publishing its known row total while continuing to page through Arrow IPC.
Validation: build, TypeScript compilation, lint, 69 focused Node/viewer tests, eight existing real-R jdv integration tests, an additional real-Polars integration check, 135 browser-renderer assertions, and source-identity checks all passed. Native tests used this revision's built sess in an isolated library with R 4.6.1, jdv 660703e, and nanoarrow 0.9.0. Renderer interaction was exercised in the browser harness. All five GitHub checks are green on the reviewed head.
Large jdv responses arrive in many socket chunks. Concatenating the whole receive buffer on every chunk made reception quadratic in the frame size. Hold chunks until a JSON line or Arrow body can complete and concatenate them once.
jdv builds every selected column for each grid/rows page, so wide data frames were slow to scroll even with most columns hidden. Send the displayed column positions as cols and reload the infinite cache when a hidden column is shown again. Fall back to all columns when an explicit selection exceeds jdv's page budget, since jdv only shortens pages that select every column.
jdv now shortens pages for explicit column selections as well, so a limit_exceeded response is a genuine failure. Cover the shortened selected-column page in the real R runtime test.
jdv now sends missingness as `na_rows`, a list of zero-based positions within the page, instead of a dense boolean `na` array. Build a set per column from it when converting grid pages. The `special` channel became a position object as well, but the viewer only shows R's display text for non-finite values, so it needs no change.
|
@renkun-ken Thanks for the approval.
Fetching only the columns in the visible horizontal range, which would help when all columns of a wide table are shown, is left as a follow-up (noted in the PR description). |
String and categorical columns offer "Is empty" and "Is not empty" next to "Is NA" and "Is not NA", so empty strings and missing values can be filtered separately. Is empty maps to jdv's text_equals with an empty value; Is not empty also excludes NA, like the other negated text conditions. Combine Is NA and Is empty with OR to match either. Inline tables label the NA options as such instead of reusing blank, and jdv columns no longer accept blank/notBlank.
PoC for #1860. Not intended to merge until jdv is on CRAN.
Requires the current development version of jdv. jdv is unreleased, so older jdv versions are not supported.
Summary
When the jdv package is installed,
View()on a data frame, matrix, list or Arrow data is served by jdv instead of the data viewer code in sess, in both R terminals and Interactive. Interactive inline tables and lists are also served by jdv. The existing AG Grid and List Viewer webviews are reused; the R-side data handling moves to jdv.src/jdvTransport.ts) and implements the host side of the jdv transport:hellovalidation (protocol version, producer, opaque session id, required limits),ackcredit, wakes only when the producer asks for them, at most 32 live requests, and length-prefixed Arrow bodies. On the firstView(), sess gets the address withrequest_client("jdv/address")and opens a persistent connection withjdv::jdv_connect(address), so jdv never uses a shared discovery file oroptions(jdv.address). The listener is private to the user (mode 0600, random name) and its address is only given to that session.View()registers the object withjdv::jdv_register(mode = "paged"); jdv announces the view to the host itself with aview/opennotification.src/jdvAdapter.ts(VS Code-independent, unit tested) validates view descriptors, converts AG Grid sort/filter models to the jdv query AST, jdv column pages to grid rows, and List Viewer index paths to jdv typed paths.src/jdvViewer.tsmanages the panels per session. Grid pages request only the displayed columns (jdvcols), so hidden columns of a wide data frame cost nothing.View()in an Interactive cell opens the Data Viewer panel through a jdv listener owned by that notebook (see below). Inline previews use jdv handles.options(sess.dataviewer = "sess"), or when jdv is already connected elsewhere or used by an embedding host, the current sess viewer is used.Why jdv
The goal is separation of responsibilities, not speed (see benchmark below).
?jdv_spec,?jdv_query_spec). Data viewing no longer has to live in sess or depend on jsonlite, and the same backend can be tested and used outside vscode-R.NaNis kept distinct fromNAin the display.[[,$ornamesmethods. It detects cycles and reports unreadable children individually instead of failing the whole list.View()and rebuild the view when it is reassigned.Following variables, Refresh and Follow
View(df)passes the binding ofdf(found withjdv::jdv_binding(), without evaluating anything) so thatdf <- transform(df, ...)updates the open view in place. Updates from tracking or Refresh do not bring the tab to the front; an explicitView()does (jdv'sview/open.reason).r.session.viewers.trackVariables(defaulttrue), passed tosess::connect(track_variables = ).options(sess.dataviewer.track = TRUE/FALSE)in R overrides it in both directions. Arrow sources are never tracked.view/refresh, when the view supports it) and, for tracked views, a Follow toggle (view/track) that pauses or resumes following. The toggle reflectsview/trackingnotifications (paused, or lost when the variable is removed).view/update_failed) are reported with a warning.connect()change.Opening cells
Cells of columns that jdv marks as
drillable(e.g. list columns) get an open button in the grid. It sendsobject/openwith the cell's originalsource_row, so it opens the right cell after sorting and filtering. The child opens as its own grid or List Viewer panel, titled by jdv (e.g.df[2, "l"]).Interactive
View(). For an Interactive notebook, the extension host creates a jdv listener keyed by the notebook and its R generation, and answers thejdv/addressclient request from the agent. The listener is closed on detach, stop, restart and host dispose. ExplicitView()now opens the Data Viewer panel instead of an inline preview.jdv::jdv_handle(mode = "paged")in R. Handles take no viewer slot, send no notifications and do not evict open views. The first page (20 rows, or 200 list children, at most 256 KiB) is stored in the cell output as before, so saving and exporting are unchanged. Paging, sorting, filtering and list exploration go throughjdv_handle_request(). At most 64 handles are kept per R process (oldest closed first); clearing a completed cell, stopping the notebook or clearing the runtime closes them.Cell N: ....options(sess.dataviewer = "sess"), for Arrow/Polars values, and for values jdv cannot represent. Outputs saved before this change stay static, and live interaction after a restart shows the existing "previous R process" message.Arrow data
apache-arrowand formatted from the physical buffers (exact 64-bit integers, decimals, and timestamps with time zones; formatting ported from jdv's reference viewer). The webview keeps the existing AG Grid infinite row model and receives JSON rows for the requested block, with an unknown row count until the stream ends. Sorting and filtering are disabled. Nested values show a summary (<list: 2 items>), and unsupported columns show jdv's reason.Decoding in the extension host rather than in the webview keeps the webview and its message protocol almost unchanged, keeps a single cache next to the data, and leaves the Arrow data where a future extension-side query engine or nested-cell inspection could use it. Measured cost: about 14 ms to decode and format a 2,000-row, 5-column page.
Behavior changes
3.0on one page and3on another.difftime/hmsdurations, in the column's units), date filters, and "Is NA / Is not NA" for every column. List columns and other classes cannot be filtered. Text columns also offer "Is empty / Is not empty", kept separate from "Is NA / Is not NA" (combine them with OR to match either); AG Grid's "Blank / Not blank" are not offered. Number ranges are inclusive.View(x$a$b)opens the value ofx$a$bas its own root, instead of openingxnavigated toa/b. RepeatedView()reuses a tab per title, not per root object. Child views are titled by jdv (x$a,x[[3]],df[12, "col"]).namesas children.View()opens a panel instead of an inline preview, and inline table previews reference the original object instead of a copy of its first 1,000 rows (the printed text is still taken when the cell runs).Benchmark (informational)
1e6-row, 8-column data frame, one 500-row page, R 4.5.2 on Linux, elapsed seconds (measured with an earlier relay; the query work in R is the same):
Both are interactive-speed for this size; jdv is somewhat slower in these cases.
Testing
src/test/node/jdvAdapter.test.ts: descriptor validation (reason,tracking, capabilities), query and column conversion (including display-only and duration columns), row labels, tree paths, cellobject/openpaths.src/test/node/jdvArrow.test.ts: value formatting, the page cache, and the transport against a fake producer (hello, wakes, ack, Arrow bodies,view/trackandview/tracking, errors, disconnect). Runs on Linux and Windows (named pipe) in CI.src/test/node/jdvTable.test.ts,interactiveJdvAddress.test.ts,interactiveRuntime.test.ts: Interactive handle tables (page, sort, filter, reconnect, close), list exploration, opening in the Data Viewer, the per-notebook jdv listener, andView()from a real R cell.src/test/suite/dataViewer.test.ts: jdv column definitions.sess/inst/tinytest/test-jdv.Randtest-interactive-handles.R(skipped when jdv is not installed):View()through a fake TCP host, tracking (R >= 4.6), Arrow, release, and Interactive handles. Existing sess viewer tests pinoptions(sess.dataviewer = "sess").Not included
trackVariablessetting to already attached sessions.Follow-up
getAllDisplayedVirtualColumns(),virtualColumnsChanged) and reloading the visible blocks when the view scrolls past them can be done in vscode-R alone, reusing the cache purge used when a hidden column is shown. Filling missing columns into cached rows instead of reloading would avoid the brief reload but needs per-block column tracking, so it will be considered only if the simple version flickers noticeably.