Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
Comment thread
renkun-ken marked this conversation as resolved.
Outdated
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 { 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';

Check warning on line 13 in src/plotViewer/index.ts

View workflow job for this annotation

GitHub Actions / lint

Expected { after 'if' condition
if (config().get<boolean>('plot.useHttpgd', false)) return 'httpgd';

Check warning on line 14 in src/plotViewer/index.ts

View workflow job for this annotation

GitHub Actions / lint

Expected { after 'if' condition
return 'auto';
}

const commands = [
'showViewers',
Expand All @@ -29,23 +38,33 @@
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);

Check warning on line 52 in src/plotViewer/index.ts

View workflow job for this annotation

GitHub Actions / lint

Expected { after 'if' condition
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 @@
})
);
}

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

public async showStandardPlot(): Promise<void> {
Expand All @@ -64,6 +85,14 @@
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 function initializePlotManager(): PlotManager {
const manager = new CommonPlotManager();
manager.initialize();

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

return manager;
}
Loading
Loading