From abc76afb844822850ac8ea6dfc9afff1a3cd6730 Mon Sep 17 00:00:00 2001 From: Jenny Bryan Date: Tue, 15 Oct 2024 14:19:16 -0700 Subject: [PATCH 1/9] (Start to) handle cli hyperlinks in the terminal used for pkg dev tasks --- extensions/positron-r/package.json | 13 +++- extensions/positron-r/package.nls.json | 2 + extensions/positron-r/src/commands.ts | 9 +++ extensions/positron-r/src/extension.ts | 73 +++++++++++++++++++++ extensions/positron-r/src/tasks.ts | 32 ++++++++- extensions/positron-r/tsconfig.json | 1 + extensions/positron-reticulate/package.json | 2 +- 7 files changed, 128 insertions(+), 4 deletions(-) diff --git a/extensions/positron-r/package.json b/extensions/positron-r/package.json index 6159286eb42..2304766fff6 100644 --- a/extensions/positron-r/package.json +++ b/extensions/positron-r/package.json @@ -3,7 +3,7 @@ "displayName": "%displayName%", "description": "%description%", "version": "0.0.2", - "publisher": "vscode", + "publisher": "positron", "engines": { "vscode": "^1.65.0" }, @@ -87,6 +87,12 @@ "title": "%r.command.packageTest.title%", "shortTitle": "%r.menu.packageTest.title%" }, + { + "command": "r.cliHyperlinks", + "category": "R", + "title": "%r.command.cliHyperlinks.title%", + "shortTitle": "%r.menu.cliHyperlinks.title%" + }, { "command": "r.useTestthat", "category": "R", @@ -674,5 +680,8 @@ }, "minimumRVersion": "4.2.0", "minimumRenvVersion": "1.0.9" - } + }, + "enabledApiProposals": [ + "terminalDataWriteEvent" + ] } diff --git a/extensions/positron-r/package.nls.json b/extensions/positron-r/package.nls.json index 3f5ee6eb8ab..2f58467073e 100644 --- a/extensions/positron-r/package.nls.json +++ b/extensions/positron-r/package.nls.json @@ -13,6 +13,7 @@ "r.command.packageBuild.title": "Build R Package", "r.command.packageInstall.title": "Install R Package and Restart R", "r.command.packageTest.title": "Test R Package", + "r.command.cliHyperlinks.title": "Emit cli hyperlinks", "r.command.useTestthat.title": "Configure testthat", "r.command.useTest.title": "Add (or visit) a test file", "r.command.packageCheck.title": "Check R Package", @@ -27,6 +28,7 @@ "r.menu.packageBuild.title": "Build R Package", "r.menu.packageInstall.title": "Install R Package and Restart R", "r.menu.packageTest.title": "Test R Package", + "r.menu.cliHyperlinks.title": "Emit cli hyperlinks", "r.menu.packageCheck.title": "Check R Package", "r.menu.packageDocument.title": "Document R Package", "r.menu.rmarkdownRender.title": "Render Document With R Markdown", diff --git a/extensions/positron-r/src/commands.ts b/extensions/positron-r/src/commands.ts index 2d6942c1f05..a50f4c2f2e5 100644 --- a/extensions/positron-r/src/commands.ts +++ b/extensions/positron-r/src/commands.ts @@ -118,6 +118,15 @@ export async function registerCommands(context: vscode.ExtensionContext) { } }), + vscode.commands.registerCommand('r.cliHyperlinks', async () => { + const tasks = await getRPackageTasks(); + const task = tasks.filter(task => task.definition.task === 'r.task.cliHyperlinks')[0]; + const isInstalled = await checkInstalled(task.definition.pkg); + if (isInstalled) { + vscode.tasks.executeTask(task); + } + }), + vscode.commands.registerCommand('r.useTestthat', async () => { executeCodeForCommand('usethis', 'usethis::use_testthat()'); }), diff --git a/extensions/positron-r/src/extension.ts b/extensions/positron-r/src/extension.ts index 7cb8aec93af..e8818b4b643 100644 --- a/extensions/positron-r/src/extension.ts +++ b/extensions/positron-r/src/extension.ts @@ -12,6 +12,7 @@ import { providePackageTasks } from './tasks'; import { setContexts } from './contexts'; import { setupTestExplorer, refreshTestExplorer } from './testing/testing'; import { RRuntimeManager } from './runtime-manager'; +import { RSessionManager } from './session-manager'; export const LOGGER = vscode.window.createOutputChannel('Positron R Extension', { log: true }); @@ -43,4 +44,76 @@ export function activate(context: vscode.ExtensionContext) { refreshTestExplorer(context); } }); + + // Listen for terminal output + const disposable = vscode.window.onDidWriteTerminalData(event => { + processTerminalOutput(event.data); + }); + context.subscriptions.push(disposable); + + context.subscriptions.push( + vscode.window.registerUriHandler({ + handleUri + }) + ); +} + +function processTerminalOutput(data: string) { + //console.log(`Full data string: ${data}`); + const regex = /\u001b]8;;x-r-run:(.*?)\u0007(.*?)\u001b]8;;\u0007/g; + let match; + while ((match = regex.exec(data)) !== null) { + const command = match[1]; + const text = match[2]; + console.log(`Detected OSC hyperlink - command: ${command}, text: ${text}`); + } +} + +function handleUri(uri: vscode.Uri): void { + LOGGER.info(`handleUri called with URI: ${uri.toString(true)}`); + //vscode.window.showInformationMessage(`handleUri called with URI: ${uri.toString(true)}`); + + if (uri.path !== '/cli') { + return; + } + + const queryParams = new URLSearchParams(uri.query); + const queryParamsObject: { [key: string]: string } = {}; + queryParams.forEach((value, key) => { + queryParamsObject[key] = value; + }); + + const uriDetails = { + scheme: uri.scheme, + authority: uri.authority, + path: uri.path, + query: uri.query, + queryParams: queryParamsObject, + fragment: uri.fragment, + fsPath: uri.fsPath + }; + + const uriDetailsJson = JSON.stringify(uriDetails, null, 2); + vscode.window.showInformationMessage(`URI Details:\n${uriDetailsJson}`); + + if (!queryParams.has('command')) { + return; + } + const command = queryParams.get('command'); + if (!command) { + return; + } + + const commandRegex = /^(x-r-(help|run|vignette)):(.+)$/; + if (!commandRegex.test(command)) { + return; + } + + const session = RSessionManager.instance.getConsoleSession(); + if (!session) { + return; + } + + session.openResource(command); + vscode.commands.executeCommand('workbench.panel.positronConsole.focus'); } diff --git a/extensions/positron-r/src/tasks.ts b/extensions/positron-r/src/tasks.ts index 8a49ae825ab..31f75cf7df8 100644 --- a/extensions/positron-r/src/tasks.ts +++ b/extensions/positron-r/src/tasks.ts @@ -53,7 +53,37 @@ export async function getRPackageTasks(editorFilePath?: string): Promise Date: Tue, 12 Nov 2024 08:22:38 -0800 Subject: [PATCH 2/9] Move URI handling into its own file --- extensions/positron-r/package.json | 5 +- extensions/positron-r/src/extension.ts | 77 ++---------------------- extensions/positron-r/src/uri-handler.ts | 62 +++++++++++++++++++ extensions/positron-r/tsconfig.json | 3 +- 4 files changed, 68 insertions(+), 79 deletions(-) create mode 100644 extensions/positron-r/src/uri-handler.ts diff --git a/extensions/positron-r/package.json b/extensions/positron-r/package.json index 2304766fff6..efde0500418 100644 --- a/extensions/positron-r/package.json +++ b/extensions/positron-r/package.json @@ -680,8 +680,5 @@ }, "minimumRVersion": "4.2.0", "minimumRenvVersion": "1.0.9" - }, - "enabledApiProposals": [ - "terminalDataWriteEvent" - ] + } } diff --git a/extensions/positron-r/src/extension.ts b/extensions/positron-r/src/extension.ts index e8818b4b643..26963c07caf 100644 --- a/extensions/positron-r/src/extension.ts +++ b/extensions/positron-r/src/extension.ts @@ -12,7 +12,7 @@ import { providePackageTasks } from './tasks'; import { setContexts } from './contexts'; import { setupTestExplorer, refreshTestExplorer } from './testing/testing'; import { RRuntimeManager } from './runtime-manager'; -import { RSessionManager } from './session-manager'; +import { registerUriHandler } from './uri-handler'; export const LOGGER = vscode.window.createOutputChannel('Positron R Extension', { log: true }); @@ -37,6 +37,9 @@ export function activate(context: vscode.ExtensionContext) { // Provide tasks. providePackageTasks(context); + // Prepare to handle cli-produced hyperlinks that target the positron-r extension. + registerUriHandler(); + // Setup testthat test explorer. setupTestExplorer(context); vscode.workspace.onDidChangeConfiguration(async event => { @@ -44,76 +47,4 @@ export function activate(context: vscode.ExtensionContext) { refreshTestExplorer(context); } }); - - // Listen for terminal output - const disposable = vscode.window.onDidWriteTerminalData(event => { - processTerminalOutput(event.data); - }); - context.subscriptions.push(disposable); - - context.subscriptions.push( - vscode.window.registerUriHandler({ - handleUri - }) - ); -} - -function processTerminalOutput(data: string) { - //console.log(`Full data string: ${data}`); - const regex = /\u001b]8;;x-r-run:(.*?)\u0007(.*?)\u001b]8;;\u0007/g; - let match; - while ((match = regex.exec(data)) !== null) { - const command = match[1]; - const text = match[2]; - console.log(`Detected OSC hyperlink - command: ${command}, text: ${text}`); - } -} - -function handleUri(uri: vscode.Uri): void { - LOGGER.info(`handleUri called with URI: ${uri.toString(true)}`); - //vscode.window.showInformationMessage(`handleUri called with URI: ${uri.toString(true)}`); - - if (uri.path !== '/cli') { - return; - } - - const queryParams = new URLSearchParams(uri.query); - const queryParamsObject: { [key: string]: string } = {}; - queryParams.forEach((value, key) => { - queryParamsObject[key] = value; - }); - - const uriDetails = { - scheme: uri.scheme, - authority: uri.authority, - path: uri.path, - query: uri.query, - queryParams: queryParamsObject, - fragment: uri.fragment, - fsPath: uri.fsPath - }; - - const uriDetailsJson = JSON.stringify(uriDetails, null, 2); - vscode.window.showInformationMessage(`URI Details:\n${uriDetailsJson}`); - - if (!queryParams.has('command')) { - return; - } - const command = queryParams.get('command'); - if (!command) { - return; - } - - const commandRegex = /^(x-r-(help|run|vignette)):(.+)$/; - if (!commandRegex.test(command)) { - return; - } - - const session = RSessionManager.instance.getConsoleSession(); - if (!session) { - return; - } - - session.openResource(command); - vscode.commands.executeCommand('workbench.panel.positronConsole.focus'); } diff --git a/extensions/positron-r/src/uri-handler.ts b/extensions/positron-r/src/uri-handler.ts new file mode 100644 index 00000000000..aa238376aa8 --- /dev/null +++ b/extensions/positron-r/src/uri-handler.ts @@ -0,0 +1,62 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (C) 2024 Posit Software, PBC. All rights reserved. + * Licensed under the Elastic License 2.0. See LICENSE.txt for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as vscode from 'vscode'; + +import { LOGGER } from './extension'; +import { RSessionManager } from './session-manager'; + +export async function registerUriHandler() { + vscode.window.registerUriHandler({ handleUri }); +} + +function handleUri(uri: vscode.Uri): void { + LOGGER.info(`handleUri called with URI: ${uri.toString(true)}`); + //vscode.window.showInformationMessage(`handleUri called with URI: ${uri.toString(true)}`); + + if (uri.path !== '/cli') { + return; + } + + const queryParams = new URLSearchParams(uri.query); + const queryParamsObject: { [key: string]: string } = {}; + queryParams.forEach((value, key) => { + queryParamsObject[key] = value; + }); + + const uriDetails = { + scheme: uri.scheme, + authority: uri.authority, + path: uri.path, + query: uri.query, + queryParams: queryParamsObject, + fragment: uri.fragment, + fsPath: uri.fsPath + }; + + const uriDetailsJson = JSON.stringify(uriDetails, null, 2); + vscode.window.showInformationMessage(`URI Details:\n${uriDetailsJson}`); + + if (!queryParams.has('command')) { + return; + } + const command = queryParams.get('command'); + if (!command) { + return; + } + + const commandRegex = /^(x-r-(help|run|vignette)):(.+)$/; + if (!commandRegex.test(command)) { + return; + } + + const session = RSessionManager.instance.getConsoleSession(); + if (!session) { + return; + } + + session.openResource(command); + vscode.commands.executeCommand('workbench.panel.positronConsole.focus'); +} diff --git a/extensions/positron-r/tsconfig.json b/extensions/positron-r/tsconfig.json index 510a1bf3cfb..ab092afd623 100644 --- a/extensions/positron-r/tsconfig.json +++ b/extensions/positron-r/tsconfig.json @@ -24,7 +24,6 @@ "include": [ "src/**/*", "../../src/positron-dts/positron.d.ts", - "../../src/vscode-dts/vscode.d.ts", - "../../src/vscode-dts/vscode.proposed.terminalDataWriteEvent.d.ts" + "../../src/vscode-dts/vscode.d.ts" ] } From 6c9d1e063907cc84f4c2a7e6403484974d0534ef Mon Sep 17 00:00:00 2001 From: Jenny Bryan Date: Tue, 12 Nov 2024 12:07:34 -0800 Subject: [PATCH 3/9] Remove chattiness that was useful in dev --- extensions/positron-r/src/uri-handler.ts | 44 ++++++++++-------------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/extensions/positron-r/src/uri-handler.ts b/extensions/positron-r/src/uri-handler.ts index aa238376aa8..86d2220895b 100644 --- a/extensions/positron-r/src/uri-handler.ts +++ b/extensions/positron-r/src/uri-handler.ts @@ -12,37 +12,29 @@ export async function registerUriHandler() { vscode.window.registerUriHandler({ handleUri }); } +// Example of a URI we expect to handle: +// positron://positron.positron-r/cli?command=x-r-run:testthat::snapshot_review('snap') +// +// How the example URI breaks down: +// { +// "scheme": "positron", +// "authority": "positron.positron-r", +// "path": "/cli", +// "query": "command=x-r-run:testthat::snapshot_review('zzz')", +// "fragment": "", +// "fsPath": "/cli" +// } function handleUri(uri: vscode.Uri): void { - LOGGER.info(`handleUri called with URI: ${uri.toString(true)}`); - //vscode.window.showInformationMessage(`handleUri called with URI: ${uri.toString(true)}`); - if (uri.path !== '/cli') { return; } - const queryParams = new URLSearchParams(uri.query); - const queryParamsObject: { [key: string]: string } = {}; - queryParams.forEach((value, key) => { - queryParamsObject[key] = value; - }); - - const uriDetails = { - scheme: uri.scheme, - authority: uri.authority, - path: uri.path, - query: uri.query, - queryParams: queryParamsObject, - fragment: uri.fragment, - fsPath: uri.fsPath - }; - - const uriDetailsJson = JSON.stringify(uriDetails, null, 2); - vscode.window.showInformationMessage(`URI Details:\n${uriDetailsJson}`); - - if (!queryParams.has('command')) { - return; - } - const command = queryParams.get('command'); + // Turns this query string + // "command=x-r-run:testthat::snapshot_review('zzz')" + // into this object + // { "command": "x-r-run:testthat::snapshot_review('zzz')" } + const query = new URLSearchParams(uri.query); + const command = query.get('command'); if (!command) { return; } From e8b9fdb525b50b02ba7a3132d954f4f916dfe1f9 Mon Sep 17 00:00:00 2001 From: Jenny Bryan Date: Mon, 18 Nov 2024 12:01:53 -0800 Subject: [PATCH 4/9] Handle the env vars more crisply --- extensions/positron-r/src/session.ts | 2 +- extensions/positron-r/src/tasks.ts | 29 ++++----------------- extensions/positron-r/src/uri-handler.ts | 33 ++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 25 deletions(-) diff --git a/extensions/positron-r/src/session.ts b/extensions/positron-r/src/session.ts index b6fa660496f..7fb50748838 100644 --- a/extensions/positron-r/src/session.ts +++ b/extensions/positron-r/src/session.ts @@ -27,7 +27,7 @@ interface RPackageInstallation { compatible: boolean; } -interface EnvVar { +export interface EnvVar { [key: string]: string; } diff --git a/extensions/positron-r/src/tasks.ts b/extensions/positron-r/src/tasks.ts index 31f75cf7df8..63e2d886155 100644 --- a/extensions/positron-r/src/tasks.ts +++ b/extensions/positron-r/src/tasks.ts @@ -8,6 +8,7 @@ import * as os from 'os'; import { RSessionManager } from './session-manager'; import { getPandocPath } from './pandoc'; import { getEnvVars } from './session'; +import { prepCliEnvVars } from './uri-handler'; export class RPackageTaskProvider implements vscode.TaskProvider { @@ -39,7 +40,7 @@ export async function getRPackageTasks(editorFilePath?: string): Promise { + session = session || RSessionManager.instance.getConsoleSession(); + if (!session) { + return {}; + } + + // cli 3.6.3.9001 gained support for configuring the URL format for hyperlinks. + const cliPkg = await session.packageVersion('cli', '3.6.3.9001'); + const cliSupportsHyperlinks = cliPkg?.compatible ?? false; + + if (!cliSupportsHyperlinks) { + // eslint-disable-next-line @typescript-eslint/naming-convention + return { R_CLI_HYPERLINKS: 'FALSE' }; + } + + return { + /* eslint-disable @typescript-eslint/naming-convention */ + R_CLI_HYPERLINKS: 'TRUE', + // TODO: I'd like to request POSIX compliant hyperlinks in the future, but currently + // cli's tests implicitly assume the default and there are more important changes to + // propose in cli, such as tweaks to file hyperlinks. Leave this alone for now. + // R_CLI_HYPERLINK_MODE: "posix", + R_CLI_HYPERLINK_RUN: 'TRUE', + R_CLI_HYPERLINK_RUN_URL_FORMAT: 'positron://positron.positron-r/cli?command=x-r-run:{code}', + R_CLI_HYPERLINK_HELP: 'TRUE', + R_CLI_HYPERLINK_HELP_URL_FORMAT: 'positron://positron.positron-r/cli?command=x-r-help:{topic}', + R_CLI_HYPERLINK_VIGNETTE: 'TRUE', + R_CLI_HYPERLINK_VIGNETTE_URL_FORMAT: 'positron://positron.positron-r/cli?command=x-r-vignette:{vignette}' + /* eslint-enable @typescript-eslint/naming-convention */ + }; +} From 2694a209575c1d690a2f31c711d9d8868f7e64ad Mon Sep 17 00:00:00 2001 From: Jenny Bryan Date: Mon, 18 Nov 2024 12:37:27 -0800 Subject: [PATCH 5/9] Temporarily emit all supported hyperlinks --- extensions/positron-r/src/tasks.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/positron-r/src/tasks.ts b/extensions/positron-r/src/tasks.ts index 63e2d886155..b1f66723d81 100644 --- a/extensions/positron-r/src/tasks.ts +++ b/extensions/positron-r/src/tasks.ts @@ -62,7 +62,7 @@ export async function getRPackageTasks(editorFilePath?: string): Promise Date: Mon, 18 Nov 2024 12:54:32 -0800 Subject: [PATCH 6/9] Remove temporary command/task to tickle help and vignette links --- extensions/positron-r/package.json | 6 ------ extensions/positron-r/package.nls.json | 2 -- extensions/positron-r/src/commands.ts | 9 --------- extensions/positron-r/src/tasks.ts | 7 ------- 4 files changed, 24 deletions(-) diff --git a/extensions/positron-r/package.json b/extensions/positron-r/package.json index efde0500418..7941b5b405b 100644 --- a/extensions/positron-r/package.json +++ b/extensions/positron-r/package.json @@ -87,12 +87,6 @@ "title": "%r.command.packageTest.title%", "shortTitle": "%r.menu.packageTest.title%" }, - { - "command": "r.cliHyperlinks", - "category": "R", - "title": "%r.command.cliHyperlinks.title%", - "shortTitle": "%r.menu.cliHyperlinks.title%" - }, { "command": "r.useTestthat", "category": "R", diff --git a/extensions/positron-r/package.nls.json b/extensions/positron-r/package.nls.json index 2f58467073e..3f5ee6eb8ab 100644 --- a/extensions/positron-r/package.nls.json +++ b/extensions/positron-r/package.nls.json @@ -13,7 +13,6 @@ "r.command.packageBuild.title": "Build R Package", "r.command.packageInstall.title": "Install R Package and Restart R", "r.command.packageTest.title": "Test R Package", - "r.command.cliHyperlinks.title": "Emit cli hyperlinks", "r.command.useTestthat.title": "Configure testthat", "r.command.useTest.title": "Add (or visit) a test file", "r.command.packageCheck.title": "Check R Package", @@ -28,7 +27,6 @@ "r.menu.packageBuild.title": "Build R Package", "r.menu.packageInstall.title": "Install R Package and Restart R", "r.menu.packageTest.title": "Test R Package", - "r.menu.cliHyperlinks.title": "Emit cli hyperlinks", "r.menu.packageCheck.title": "Check R Package", "r.menu.packageDocument.title": "Document R Package", "r.menu.rmarkdownRender.title": "Render Document With R Markdown", diff --git a/extensions/positron-r/src/commands.ts b/extensions/positron-r/src/commands.ts index a50f4c2f2e5..2d6942c1f05 100644 --- a/extensions/positron-r/src/commands.ts +++ b/extensions/positron-r/src/commands.ts @@ -118,15 +118,6 @@ export async function registerCommands(context: vscode.ExtensionContext) { } }), - vscode.commands.registerCommand('r.cliHyperlinks', async () => { - const tasks = await getRPackageTasks(); - const task = tasks.filter(task => task.definition.task === 'r.task.cliHyperlinks')[0]; - const isInstalled = await checkInstalled(task.definition.pkg); - if (isInstalled) { - vscode.tasks.executeTask(task); - } - }), - vscode.commands.registerCommand('r.useTestthat', async () => { executeCodeForCommand('usethis', 'usethis::use_testthat()'); }), diff --git a/extensions/positron-r/src/tasks.ts b/extensions/positron-r/src/tasks.ts index b1f66723d81..9f62b844479 100644 --- a/extensions/positron-r/src/tasks.ts +++ b/extensions/positron-r/src/tasks.ts @@ -59,13 +59,6 @@ export async function getRPackageTasks(editorFilePath?: string): Promise Date: Mon, 18 Nov 2024 13:24:29 -0800 Subject: [PATCH 7/9] Put this comma back, the way I found it --- extensions/positron-r/tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/positron-r/tsconfig.json b/extensions/positron-r/tsconfig.json index ab092afd623..694d59d3dc9 100644 --- a/extensions/positron-r/tsconfig.json +++ b/extensions/positron-r/tsconfig.json @@ -24,6 +24,6 @@ "include": [ "src/**/*", "../../src/positron-dts/positron.d.ts", - "../../src/vscode-dts/vscode.d.ts" + "../../src/vscode-dts/vscode.d.ts", ] } From ee4b35905bc7d0ec965637fa53721d93e68b150c Mon Sep 17 00:00:00 2001 From: Jenny Bryan Date: Mon, 18 Nov 2024 13:26:00 -0800 Subject: [PATCH 8/9] Update "publisher" in mentions of the extension --- .../positronNewProject/common/positronNewProjectService.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/services/positronNewProject/common/positronNewProjectService.ts b/src/vs/workbench/services/positronNewProject/common/positronNewProjectService.ts index c61d1fa49c0..20d13d2ebf8 100644 --- a/src/vs/workbench/services/positronNewProject/common/positronNewProjectService.ts +++ b/src/vs/workbench/services/positronNewProject/common/positronNewProjectService.ts @@ -283,7 +283,7 @@ export class PositronNewProjectService extends Disposable implements IPositronNe /** * Runs R Project specific tasks. - * Relies on extension vscode.positron-r + * Relies on extension positron.positron-r */ private async _runRTasks() { // no-op for now, since we haven't defined any pre-runtime startup R tasks @@ -305,7 +305,7 @@ export class PositronNewProjectService extends Disposable implements IPositronNe /** * Runs R Project specific post-initialization tasks. - * Relies on extension vscode.positron-r + * Relies on extension positron.positron-r */ private async _runRPostInitTasks() { // Create the R environment @@ -518,7 +518,7 @@ export class PositronNewProjectService extends Disposable implements IPositronNe /** * Creates the R environment. - * Relies on extension vscode.positron-r + * Relies on extension positron.positron-r */ private async _createREnvironment() { if (this._newProjectConfig?.useRenv) { From 01ab77a629e613908ea800ea2b272ce685cef41b Mon Sep 17 00:00:00 2001 From: Jenny Bryan Date: Sun, 24 Nov 2024 12:48:29 -0800 Subject: [PATCH 9/9] Put behind a feature flag --- extensions/positron-r/package.json | 6 ++++++ extensions/positron-r/package.nls.json | 3 ++- extensions/positron-r/src/uri-handler.ts | 16 ++++++++++++++-- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/extensions/positron-r/package.json b/extensions/positron-r/package.json index 7941b5b405b..82eb3c1d68a 100644 --- a/extensions/positron-r/package.json +++ b/extensions/positron-r/package.json @@ -281,6 +281,12 @@ }, "default": [], "description": "%r.configuration.extraArguments.description%" + }, + "positron.r.taskHyperlinks": { + "scope": "window", + "type": "boolean", + "default": false, + "description": "%r.configuration.taskHyperlinks.description%" } } } diff --git a/extensions/positron-r/package.nls.json b/extensions/positron-r/package.nls.json index 3f5ee6eb8ab..6a12749ba20 100644 --- a/extensions/positron-r/package.nls.json +++ b/extensions/positron-r/package.nls.json @@ -58,5 +58,6 @@ "r.configuration.pipe.magrittr.token": "%>%", "r.configuration.pipe.native.description": "Native pipe available in R >= 4.1", "r.configuration.pipe.magrittr.description": "Pipe operator from the magrittr package, re-exported by many other packages", - "r.configuration.diagnostics.enable.description": "Enable R diagnostics globally" + "r.configuration.diagnostics.enable.description": "Enable R diagnostics globally", + "r.configuration.taskHyperlinks.description": "Turn on experimental support for hyperlinks in package development tasks" } diff --git a/extensions/positron-r/src/uri-handler.ts b/extensions/positron-r/src/uri-handler.ts index 4cd893b69ed..3e85cb0c296 100644 --- a/extensions/positron-r/src/uri-handler.ts +++ b/extensions/positron-r/src/uri-handler.ts @@ -13,6 +13,18 @@ export async function registerUriHandler() { vscode.window.registerUriHandler({ handleUri }); } +// Temporary feature flag to finesse the fact that cli hyperlinks are either all ON or all OFF. +// cli 3.6.3.9001 gained support for configuring the URL format of run/help/vignette hyperlinks. +// But file hyperlinks are not yet configurable and will delegate to operating system. +// If the user still has RStudio as the app associated with .R files, it will open in RStudio. +// Flag will be removed once cli can be configured to emit positron://file/... hyperlinks. +function taskHyperlinksEnabled(): boolean { + const extConfig = vscode.workspace.getConfiguration('positron.r'); + const taskHyperlinksEnabled = extConfig.get('taskHyperlinks'); + + return taskHyperlinksEnabled === true; +} + // Example of a URI we expect to handle: // positron://positron.positron-r/cli?command=x-r-run:testthat::snapshot_review('snap') // @@ -60,11 +72,11 @@ export async function prepCliEnvVars(session?: RSession): Promise { return {}; } - // cli 3.6.3.9001 gained support for configuring the URL format for hyperlinks. + const taskHyperlinks = taskHyperlinksEnabled(); const cliPkg = await session.packageVersion('cli', '3.6.3.9001'); const cliSupportsHyperlinks = cliPkg?.compatible ?? false; - if (!cliSupportsHyperlinks) { + if (!taskHyperlinks || !cliSupportsHyperlinks) { // eslint-disable-next-line @typescript-eslint/naming-convention return { R_CLI_HYPERLINKS: 'FALSE' }; }