Skip to content

Commit

Permalink
(Start to) handle cli hyperlinks in the terminal used for pkg dev tasks
Browse files Browse the repository at this point in the history
  • Loading branch information
jennybc committed Oct 31, 2024
1 parent 946d121 commit a64b778
Show file tree
Hide file tree
Showing 8 changed files with 129 additions and 4 deletions.
13 changes: 11 additions & 2 deletions extensions/positron-r/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"displayName": "%displayName%",
"description": "%description%",
"version": "0.0.2",
"publisher": "vscode",
"publisher": "positron",
"engines": {
"vscode": "^1.65.0"
},
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -654,5 +660,8 @@
},
"minimumRVersion": "4.2.0",
"minimumRenvVersion": "1.0.9"
}
},
"enabledApiProposals": [
"terminalDataWriteEvent"
]
}
2 changes: 2 additions & 0 deletions extensions/positron-r/package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,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",
Expand All @@ -26,6 +27,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",
Expand Down
9 changes: 9 additions & 0 deletions extensions/positron-r/src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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()');
}),
Expand Down
73 changes: 73 additions & 0 deletions extensions/positron-r/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 });

Expand Down Expand Up @@ -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');
}
1 change: 1 addition & 0 deletions extensions/positron-r/src/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ interface EnvVar {
// locale to also be present here, such as LC_CTYPE or LC_TIME. These can vary by OS, so this
// interface doesn't attempt to enumerate them.
interface Locale {
// eslint-disable-next-line @typescript-eslint/naming-convention
LANG: string;
[key: string]: string;
}
Expand Down
32 changes: 31 additions & 1 deletion extensions/positron-r/src/tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,37 @@ export async function getRPackageTasks(editorFilePath?: string): Promise<vscode.
message: vscode.l10n.t('{taskName}', { taskName: 'Test R package' }),
rcode: 'devtools::test()',
package: 'devtools',
envVars: await getEnvVars(['TESTTHAT_MAX_FAILS'])
envVars: {
...await getEnvVars(['TESTTHAT_MAX_FAILS']),
// eslint-disable-next-line @typescript-eslint/naming-convention
R_CLI_HYPERLINKS: "TRUE",
// eslint-disable-next-line @typescript-eslint/naming-convention
R_CLI_HYPERLINK_RUN: "TRUE",
// eslint-disable-next-line @typescript-eslint/naming-convention
R_CLI_HYPERLINK_RUN_URL_FORMAT: 'positron://positron.positron-r/cli?command=x-r-run:{code}',
// eslint-disable-next-line @typescript-eslint/naming-convention
R_CLI_HYPERLINK_HELP: "TRUE",
// eslint-disable-next-line @typescript-eslint/naming-convention
R_CLI_HYPERLINK_VIGNETTE: "TRUE"
}
},
{
task: 'r.task.cliHyperlinks',
message: vscode.l10n.t('{taskName}', { taskName: 'Emit a cli run hyperlink' }),
rcode: 'cli::cli_text("{.run usethis::proj_sitrep()}")',
package: 'cli',
envVars: {
// eslint-disable-next-line @typescript-eslint/naming-convention
R_CLI_HYPERLINKS: "TRUE",
// eslint-disable-next-line @typescript-eslint/naming-convention
R_CLI_HYPERLINK_RUN: "TRUE",
// eslint-disable-next-line @typescript-eslint/naming-convention
R_CLI_HYPERLINK_RUN_URL_FORMAT: 'positron://positron.positron-r/cli?command=x-r-run:{code}',
// eslint-disable-next-line @typescript-eslint/naming-convention
R_CLI_HYPERLINK_HELP: "TRUE",
// eslint-disable-next-line @typescript-eslint/naming-convention
R_CLI_HYPERLINK_VIGNETTE: "TRUE"
}
},
{
task: 'r.task.rmarkdownRender',
Expand Down
1 change: 1 addition & 0 deletions extensions/positron-r/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,6 @@
"src/**/*",
"../../src/positron-dts/positron.d.ts",
"../../src/vscode-dts/vscode.d.ts",
"../../src/vscode-dts/vscode.proposed.terminalDataWriteEvent.d.ts"
]
}
2 changes: 1 addition & 1 deletion extensions/positron-reticulate/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
},
"extensionDependencies": [
"ms-python.python",
"vscode.positron-r",
"positron.positron-r",
"vscode.jupyter-adapter"
],
"devDependencies": {
Expand Down

0 comments on commit a64b778

Please sign in to comment.