Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion R/profile.R
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@ local({
})

if (requireNamespace("sess", quietly = TRUE)) {
plot_backend <- Sys.getenv("SESS_PLOT_BACKEND", "auto")
sess::connect(
use_rstudioapi = as.logical(Sys.getenv("SESS_RSTUDIOAPI", "TRUE")),
use_httpgd = as.logical(Sys.getenv("SESS_USE_HTTPGD", "TRUE"))
use_httpgd = (plot_backend %in% c("auto", "httpgd")),
use_jgd = (plot_backend %in% c("auto", "jgd"))
)
}
39 changes: 38 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1841,7 +1841,44 @@
"r.plot.useHttpgd": {
"type": "boolean",
"default": false,
"markdownDescription": "Use the httpgd-based plot viewer instead of the base VSCode-R plot viewer.\n\nRequires the `httpgd` R package version 1.2.0 or later."
"markdownDescription": "Use the httpgd-based plot viewer instead of the base VSCode-R plot viewer.\n\nRequires the `httpgd` R package version 1.2.0 or later.\n\n**Deprecated:** Use `#r.plot.backend#` instead. When `#r.plot.backend#` is `auto`, setting this to `true` forces httpgd."
},
"r.plot.backend": {
"type": "string",
"default": "auto",
"enum": [
"auto",
"standard",
"httpgd",
"jgd"
],
"markdownEnumDescriptions": [
"Automatic: tries JGD first (if installed), then httpgd, then standard. Respects `#r.plot.useHttpgd#` if set.",
"Standard static plot viewer (PNG/SVG)",
"httpgd-based interactive plot viewer (requires `httpgd` R package)",
"JGD-based interactive plot viewer (requires `jgd` R package)"
],
"markdownDescription": "Select the plot backend.\n\nWhen set to `auto`, the best available backend is used (JGD if installed, then httpgd, then standard). Setting `#r.plot.useHttpgd#` to `true` forces httpgd."
},
"r.plot.jgd.historyLimit": {
"type": "number",
"default": 50,
"description": "Maximum number of plots retained in JGD history per session."
},
"r.plot.jgd.exportWidth": {
"type": "number",
"default": 7,
"description": "Default export width in inches for JGD plots."
},
"r.plot.jgd.exportHeight": {
"type": "number",
"default": 7,
"description": "Default export height in inches for JGD plots."
},
"r.plot.jgd.exportDpi": {
"type": "number",
"default": 150,
"description": "Default export DPI for JGD plots."
},
"r.plot.format": {
"type": "string",
Expand Down
1 change: 1 addition & 0 deletions sess/DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@ Imports:
rstudioapi,
svglite
Suggests:
jgd,
testthat (>= 3.0.0)
Config/roxygen2/version: 8.0.0
11 changes: 8 additions & 3 deletions sess/R/hooks.R
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
#'
#' @param use_rstudioapi Logical. Enable rstudioapi emulation.
#' @param use_httpgd Logical. Enable httpgd plot device if available.
#' @param use_jgd Logical. Enable jgd plot device if available.
#' @export
register_hooks <- function(use_rstudioapi = TRUE, use_httpgd = TRUE) {
register_hooks <- function(use_rstudioapi = TRUE, use_httpgd = TRUE, use_jgd = FALSE) {
# 1. Override View() to serve table data via paged RPC.
show_dataview <- function(x, title = deparse(substitute(x))) {
# make sure title is computed.
Expand Down Expand Up @@ -112,8 +113,12 @@ register_hooks <- function(use_rstudioapi = TRUE, use_httpgd = TRUE) {
invisible(x)
}

# 4. httpgd or Static Plot Hook
if (use_httpgd && requireNamespace("httpgd", quietly = TRUE)) {
# 4. Plot device: JGD > httpgd > Standard
if (use_jgd && nzchar(Sys.getenv("JGD_SOCKET")) && requireNamespace("jgd", quietly = TRUE)) {
options(device = function(...) {
jgd::jgd()
})
} else if (use_httpgd && requireNamespace("httpgd", quietly = TRUE)) {
options(device = function(...) {
httpgd::hgd(silent = TRUE)
notify_client("httpgd", list(url = httpgd::hgd_url()))
Expand Down
6 changes: 4 additions & 2 deletions sess/R/server.R
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
#' session JSON file written by the extension.
#' @param use_rstudioapi Logical. Enable rstudioapi emulation. Defaults to TRUE.
#' @param use_httpgd Logical. Use httpgd for plotting if available. Defaults to TRUE.
#' @param use_jgd Logical. Use jgd for plotting if available. Defaults to FALSE.
#' @export
connect <- function(pipe_path = NULL, use_rstudioapi = TRUE, use_httpgd = TRUE) {
connect <- function(pipe_path = NULL, use_rstudioapi = TRUE, use_httpgd = TRUE, use_jgd = FALSE) {
.sess_env$con <- NULL
.sess_env$pending_responses <- list()
.sess_env$read_buffer <- ""
Expand Down Expand Up @@ -90,7 +91,8 @@ connect <- function(pipe_path = NULL, use_rstudioapi = TRUE, use_httpgd = TRUE)

if (is.na(use_rstudioapi)) use_rstudioapi <- TRUE
if (is.na(use_httpgd)) use_httpgd <- TRUE
register_hooks(use_rstudioapi = use_rstudioapi, use_httpgd = use_httpgd)
if (is.na(use_jgd)) use_jgd <- FALSE
register_hooks(use_rstudioapi = use_rstudioapi, use_httpgd = use_httpgd, use_jgd = use_jgd)

invisible(NULL)
}
Expand Down
9 changes: 8 additions & 1 deletion sess/man/connect.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions sess/man/dispatch_message.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions sess/man/ipc_write.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion sess/man/notify_client.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions sess/man/poll_connection.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion sess/man/register_hooks.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions sess/man/rpc_reply.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion sess/man/rpc_send.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,14 @@ export async function activate(context: vscode.ExtensionContext): Promise<apiImp
// initialize plot manager
globalPlotManager = plotViewer.initializePlotManager();

// Set JGD_SOCKET env var for R child processes when JGD server is running
if (plotViewer.resolveBackend() === 'jgd' || plotViewer.resolveBackend() === 'auto') {
const jgdVars = (globalPlotManager as plotViewer.CommonPlotManager).getJgdEnvVars();
for (const [key, value] of Object.entries(jgdVars)) {
context.environmentVariableCollection.replace(key, value);
}
}

// initialize the package/help related functions
globalRHelp = await rHelp.initializeHelp(context, rExtension);

Expand Down Expand Up @@ -252,5 +260,6 @@ export async function activate(context: vscode.ExtensionContext): Promise<apiImp
}

export async function deactivate(): Promise<void> {
(globalPlotManager as plotViewer.CommonPlotManager)?.dispose();
await session.shutdownSessionWatcher();
}
35 changes: 35 additions & 0 deletions src/plotViewer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,16 @@ import { PlotViewer, PlotManager } from './types';
import { HttpgdManager, HttpgdViewer } from './httpgdViewer';
export { HttpgdManager };
import { StandardPlotViewer } from './standardViewer';
import { JgdManager } from './jgdViewer';
import { extensionContext } from '../extension';
import { config } from '../util';

export function resolveBackend(): 'auto' | 'standard' | 'httpgd' | 'jgd' {
const explicit = config().get<string>('plot.backend', 'auto');
if (explicit !== 'auto') return explicit as 'standard' | 'httpgd' | 'jgd';
if (config().get<boolean>('plot.useHttpgd', false)) return 'httpgd';
return 'auto';
}

const commands = [
'showViewers',
Expand All @@ -29,23 +38,33 @@ const commands = [
export class CommonPlotManager implements PlotManager {
public httpgdManager: HttpgdManager;
public standardPlotViewer: StandardPlotViewer;
public jgdManager: JgdManager;

constructor() {
this.httpgdManager = new HttpgdManager();
this.standardPlotViewer = new StandardPlotViewer();
this.jgdManager = new JgdManager();
}

get viewers(): PlotViewer[] {
const viewers: PlotViewer[] = [...this.httpgdManager.viewers];
const jgdViewer = this.jgdManager.getViewer();
if (jgdViewer) viewers.push(jgdViewer);
viewers.push(this.standardPlotViewer);
return viewers;
}

get activeViewer(): PlotViewer | undefined {
const backend = resolveBackend();
if (backend === 'jgd' || backend === 'auto') {
return this.jgdManager.getViewer() || this.httpgdManager.getRecentViewer() || this.standardPlotViewer;
}
return this.httpgdManager.getRecentViewer() || this.standardPlotViewer;
}

public initialize(): void {
this.jgdManager.initialize(extensionContext.extensionUri);

for (const cmd of commands) {
const fullCommand = `r.plot.${cmd}`;
extensionContext.subscriptions.push(
Expand All @@ -54,6 +73,8 @@ export class CommonPlotManager implements PlotManager {
})
);
}

void vscode.commands.executeCommand('setContext', 'r.plot.backend', resolveBackend());
}

public async showStandardPlot(): Promise<void> {
Expand All @@ -64,6 +85,14 @@ export class CommonPlotManager implements PlotManager {
await this.httpgdManager.showViewer(url);
}

public getJgdEnvVars(): Record<string, string> {
return this.jgdManager.getEnvVars();
}

public dispose(): void {
this.jgdManager.stop();
}

private async handleCommand(command: string, hostOrWebviewUri?: string | vscode.Uri, ...args: unknown[]): Promise<void> {
if (command === 'showViewers') {
for (const viewer of this.viewers) {
Expand Down Expand Up @@ -97,5 +126,11 @@ export class CommonPlotManager implements PlotManager {
export function initializePlotManager(): PlotManager {
const manager = new CommonPlotManager();
manager.initialize();

const backend = resolveBackend();
if (backend === 'jgd' || backend === 'auto') {
manager.jgdManager.start();
}

return manager;
}
Loading