Skip to content

Commit b904965

Browse files
grantmcdermottrandy3k
authored andcommitted
fix(plot): reconnect orphaned jgd device on reattach
After a VS Code window reload, the JGD socket server starts on a new socket path and the attach script updates JGD_SOCKET accordingly. But a jgd device opened before the reload remains bound to the old, dead socket: jgd::jgd() only reads JGD_SOCKET at device-creation time, so the stale device never reconnects and subsequent plots silently render to nowhere (reported by @renkun-ken for self-managed arf/tmux sessions). In register_hooks(), when the jgd backend is active, detect an existing jgd device, record its current plot, close it, and reopen jgd::jgd() so it binds to the current socket — replaying the recorded plot so it reappears after reload. No-ops when no jgd device is open. Bump sess to 3.0.1 so the attach script reinstalls the corrected package for sessions that already have 3.0.0.
1 parent ba7ea87 commit b904965

2 files changed

Lines changed: 22 additions & 1 deletion

File tree

sess/DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Package: sess
22
Type: Package
33
Title: Modern R IPC Server
4-
Version: 3.0.0
4+
Version: 3.0.1
55
Author: Gemini
66
Maintainer: Gemini <gemini@example.com>
77
Description: Implements a high-performance IPC client for R sessions using Unix domain sockets and Windows named pipes. Replaces legacy file-system watcher based workflows while keeping JSON-RPC communication semantics for IDE/editor integration.

sess/R/hooks.R

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,27 @@ register_hooks <- function(use_rstudioapi = TRUE, use_httpgd = TRUE, use_jgd = F
135135
options(device = function(...) {
136136
jgd::jgd()
137137
})
138+
139+
# On reattach (e.g. after a VS Code window reload) the renderer starts a new
140+
# socket, but any jgd device opened before the reload is still bound to the
141+
# old, now-dead socket. jgd::jgd() only reads JGD_SOCKET at device-creation
142+
# time, so the stale device never reconnects and plots silently go nowhere.
143+
# Reopen it against the new socket, replaying the current plot if possible.
144+
reconnect_jgd_device <- function() {
145+
devs <- grDevices::dev.list()
146+
if (is.null(devs) || !"jgd" %in% names(devs)) {
147+
return(invisible(FALSE))
148+
}
149+
grDevices::dev.set(devs[names(devs) == "jgd"][[1]])
150+
recorded <- tryCatch(grDevices::recordPlot(), error = function(e) NULL)
151+
tryCatch(grDevices::dev.off(), error = function(e) NULL)
152+
tryCatch(jgd::jgd(), error = function(e) NULL)
153+
if (!is.null(recorded)) {
154+
tryCatch(grDevices::replayPlot(recorded), error = function(e) NULL)
155+
}
156+
invisible(TRUE)
157+
}
158+
reconnect_jgd_device()
138159
} else if (use_httpgd && requireNamespace("httpgd", quietly = TRUE)) {
139160
options(device = function(...) {
140161
httpgd::hgd(silent = TRUE)

0 commit comments

Comments
 (0)