diff --git a/extensions/positron-r/package.json b/extensions/positron-r/package.json index 7f4489d7c46..f623f625dc9 100644 --- a/extensions/positron-r/package.json +++ b/extensions/positron-r/package.json @@ -27,6 +27,42 @@ "title": "%r.command.createNewFile.title%", "shortTitle": "%r.menu.createNewFile.title%" }, + { + "command": "r.packageLoad", + "category": "R", + "title": "%r.command.packageLoad.title%", + "shortTitle": "%r.menu.packageLoad.title%" + }, + { + "command": "r.packageBuild", + "category": "R", + "title": "%r.command.packageBuild.title%", + "shortTitle": "%r.menu.packageBuild.title%" + }, + { + "command": "r.packageInstall", + "category": "R", + "title": "%r.command.packageInstall.title%", + "shortTitle": "%r.menu.packageInstall.title%" + }, + { + "command": "r.packageTest", + "category": "R", + "title": "%r.command.packageTest.title%", + "shortTitle": "%r.menu.packageTest.title%" + }, + { + "command": "r.packageCheck", + "category": "R", + "title": "%r.command.packageCheck.title%", + "shortTitle": "%r.menu.packageCheck.title%" + }, + { + "command": "r.packageDocument", + "category": "R", + "title": "%r.command.packageDocument.title%", + "shortTitle": "%r.menu.packageDocument.title%" + }, { "command": "r.sourceCurrentFile", "category": "R", @@ -104,6 +140,38 @@ "path": "./syntaxes/r.tmGrammar.gen.json" } ], + "keybindings" : [ + { + "command": "r.packageLoad", + "key": "ctrl+shift+l", + "mac": "cmd+shift+l", + "when": "isRPackage" + }, + { + "command": "r.packageBuild", + "key": "ctrl+shift+b", + "mac": "cmd+shift+b", + "when": "isRPackage" + }, + { + "command": "r.packageTest", + "key": "ctrl+shift+t", + "mac": "cmd+shift+t", + "when": "isRPackage" + }, + { + "command": "r.packageCheck", + "key": "ctrl+shift+e", + "mac": "cmd+shift+e", + "when": "isRPackage" + }, + { + "command": "r.packageDocument", + "key": "ctrl+shift+d", + "mac": "cmd+shift+d", + "when": "isRPackage" + } + ], "menus": { "commandPalette": [ { @@ -112,6 +180,26 @@ "icon": "$(play)", "title": "%r.command.sourceCurrentFile.title%", "when": "editorLangId == r" + }, + { + "category": "R", + "command": "r.packageLoad", + "when": "isRPackage" + }, + { + "category": "R", + "command": "r.packageBuild", + "when": "isRPackage" + }, + { + "category": "R", + "command": "r.packageTest", + "when": "isRPackage" + }, + { + "category": "R", + "command": "r.packageCheck", + "when": "isRPackage" } ], "file/newFile": [ @@ -138,25 +226,7 @@ "when": "resourceLangId == r && !isInDiffEditor" } ] - }, - "taskDefinitions": [ - { - "type": "rPackageBuild", - "when": "isRPackage" - }, - { - "type": "rPackageLoad", - "when": "isRPackage" - }, - { - "type": "rPackageTest", - "when": "isRPackage" - }, - { - "type": "rPackageCheck", - "when": "isRPackage" - } - ] + } }, "scripts": { "vscode:prepublish": "yarn run compile", diff --git a/extensions/positron-r/package.nls.json b/extensions/positron-r/package.nls.json index 40e395fd72c..1388b7ace9c 100644 --- a/extensions/positron-r/package.nls.json +++ b/extensions/positron-r/package.nls.json @@ -4,6 +4,12 @@ "r.command.sourceCurrentFile.title": "Source R File", "r.command.setKernelPath.title": "Set Kernel Path", "r.command.createNewFile.title": "New R File", + "r.command.packageLoad.title": "Load R Package", + "r.command.packageBuild.title": "Build R Package", + "r.command.packageInstall.title": "Install R Package", + "r.command.packageTest.title": "Test R Package", + "r.command.packageCheck.title": "Check R Package", + "r.command.packageDocument.title": "Document R Package", "r.menu.createNewFile.title": "R File", "r.configuration.title": "Positron R Language Pack", "r.configuration.kernelPath.description": "Path on disk to the ARK kernel executable; use this to override the default (embedded) kernel.", diff --git a/extensions/positron-r/src/commands.ts b/extensions/positron-r/src/commands.ts index 52798627f40..080268a5fdb 100644 --- a/extensions/positron-r/src/commands.ts +++ b/extensions/positron-r/src/commands.ts @@ -7,7 +7,11 @@ import * as positron from 'positron'; import { adaptJupyterKernel } from './kernel'; -export function registerCommands(context: vscode.ExtensionContext) { +export async function registerCommands(context: vscode.ExtensionContext) { + + const isRPackage = await detectRPackage(); + vscode.commands.executeCommand('setContext', 'isRPackage', isRPackage); + context.subscriptions.push( // Command used to register the ARK kernel with the Jupyter Adapter // extension. Typically run only once to set up the kernel. @@ -43,6 +47,31 @@ export function registerCommands(context: vscode.ExtensionContext) { }); }), + // Commands for package development tooling + vscode.commands.registerCommand('r.packageLoad', () => { + positron.runtime.executeCode('r', 'devtools::load_all()', true); + }), + + vscode.commands.registerCommand('r.packageBuild', () => { + positron.runtime.executeCode('r', 'devtools::build()', true); + }), + + vscode.commands.registerCommand('r.packageInstall', () => { + positron.runtime.executeCode('r', 'devtools::install()', true); + }), + + vscode.commands.registerCommand('r.packageTest', () => { + positron.runtime.executeCode('r', 'devtools::test()', true); + }), + + vscode.commands.registerCommand('r.packageCheck', () => { + positron.runtime.executeCode('r', 'devtools::check()', true); + }), + + vscode.commands.registerCommand('r.packageDocument', () => { + positron.runtime.executeCode('r', 'devtools::document()', true); + }), + // Command used to source the current file vscode.commands.registerCommand('r.sourceCurrentFile', async () => { // Get the active text editor @@ -84,3 +113,20 @@ export function registerCommands(context: vscode.ExtensionContext) { }), ); } + +async function detectRPackage(): Promise { + if (vscode.workspace.workspaceFolders !== undefined) { + const folderUri = vscode.workspace.workspaceFolders[0].uri; + const fileUri = vscode.Uri.joinPath(folderUri, 'DESCRIPTION'); + try { + const bytes = await vscode.workspace.fs.readFile(fileUri); + const descriptionText = Buffer.from(bytes).toString('utf8'); + const descriptionLines = descriptionText.split(/(\r?\n)/); + const descStartsWithPackage = descriptionLines[0].startsWith('Package:'); + const typeLines = descriptionLines.filter(line => line.startsWith('Type:')); + const typeIsPackage = typeLines.length === 0 || typeLines[0].includes('Package'); + return descStartsWithPackage && typeIsPackage; + } catch { } + } + return false; +} diff --git a/extensions/positron-r/src/extension.ts b/extensions/positron-r/src/extension.ts index 82c59bef5b3..a1fa35fa805 100644 --- a/extensions/positron-r/src/extension.ts +++ b/extensions/positron-r/src/extension.ts @@ -7,7 +7,6 @@ import * as vscode from 'vscode'; import { registerCommands } from './commands'; import { adaptJupyterKernel } from './kernel'; import { initializeLogging, trace, traceOutputChannel } from './logging'; -import { providePackageTasks } from './tasks'; function activateKernel(context: vscode.ExtensionContext) { @@ -60,8 +59,5 @@ export function activate(context: vscode.ExtensionContext) { // Register commands. registerCommands(context); - // Provide tasks. - providePackageTasks(context); - } diff --git a/extensions/positron-r/src/tasks.ts b/extensions/positron-r/src/tasks.ts deleted file mode 100644 index b7f8863a036..00000000000 --- a/extensions/positron-r/src/tasks.ts +++ /dev/null @@ -1,70 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (C) 2023 Posit Software, PBC. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -import * as vscode from 'vscode'; - -export async function providePackageTasks(_context: vscode.ExtensionContext): Promise { - - const isRPackage = await detectRPackage(); - vscode.commands.executeCommand('setContext', 'isRPackage', isRPackage); - - const allPackageTasks: PackageTask[] = [ - { 'type': 'rPackageLoad', 'name': 'Load package', 'shellExecution': 'R -e "devtools::load_all()"' }, - { 'type': 'rPackageBuild', 'name': 'Build package', 'shellExecution': 'R -e "devtools::build()"' }, - { 'type': 'rPackageTest', 'name': 'Test package', 'shellExecution': 'R -e "devtools::test()"' }, - { 'type': 'rPackageCheck', 'name': 'Check package', 'shellExecution': 'R -e "devtools::check()"' }, - ]; - - for (const packageTask of allPackageTasks) { - registerRPackageTaskProvider(packageTask); - } - -} - -async function detectRPackage(): Promise { - if (vscode.workspace.workspaceFolders !== undefined) { - const folderUri = vscode.workspace.workspaceFolders[0].uri; - const fileUri = vscode.Uri.joinPath(folderUri, 'DESCRIPTION'); - try { - const bytes = await vscode.workspace.fs.readFile(fileUri); - const descriptionText = Buffer.from(bytes).toString('utf8'); - const descriptionLines = descriptionText.split(/(\r?\n)/); - const descStartsWithPackage = descriptionLines[0].startsWith('Package:'); - const typeLines = descriptionLines.filter(line => line.startsWith('Type:')); - const typeIsPackage = typeLines.length === 0 || typeLines[0].includes('Package'); - return descStartsWithPackage && typeIsPackage; - } catch { } - } - return false; -} - -function registerRPackageTaskProvider(packageTask: PackageTask): vscode.Disposable { - const task = rPackageTask(packageTask); - const taskProvider = vscode.tasks.registerTaskProvider(packageTask.type, { - provideTasks: () => { - return [task]; - }, - resolveTask(_task: vscode.Task): vscode.Task | undefined { - return undefined; - } - }); - return (taskProvider); -} - -function rPackageTask(packageTask: PackageTask): vscode.Task { - return new vscode.Task( - { type: packageTask.type }, - vscode.TaskScope.Workspace, - packageTask.name, - 'R', - new vscode.ShellExecution(packageTask.shellExecution), - [] - ); -} - -type PackageTask = { - type: string; - name: string; - shellExecution: string; -};