From 82b335e27545e804b7fd806db00477a6eb49951d Mon Sep 17 00:00:00 2001 From: Jonathan Date: Mon, 8 Jul 2024 14:49:25 -0700 Subject: [PATCH] Supply RSTUDIO_PANDOC to packaging tasks, including R Markdown render (#3856) Several beta users have already reported trouble rendering documents with Positron because the render tasks can't find Pandoc, even though it ships with Positron. This change supplies the`RSTUDIO_PANDOC` environment variable when running packaging tasks and R Markdown rendering jobs. It's done using the same logic we use to supply `RSTUDIO_PANDOC` to the main R session. Addresses #3776. ### QA Notes The embedded Pandoc is only used when there's no other Pandoc on the `$PATH`. To test this, uninstall all your Pandocies (make sure `which pandoc` returns nothing) first so that only the bundled Pandoc is available. This also touches the code that injects Pandoc into the main R session, so make sure e.g. `rmarkdown::pandoc_version()` still works there. --- extensions/positron-r/src/pandoc.ts | 23 +++++++++++++++++++++++ extensions/positron-r/src/session.ts | 9 +++------ extensions/positron-r/src/tasks.ts | 13 ++++++++++++- 3 files changed, 38 insertions(+), 7 deletions(-) create mode 100644 extensions/positron-r/src/pandoc.ts diff --git a/extensions/positron-r/src/pandoc.ts b/extensions/positron-r/src/pandoc.ts new file mode 100644 index 00000000000..607d30c937b --- /dev/null +++ b/extensions/positron-r/src/pandoc.ts @@ -0,0 +1,23 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { existsSync } from 'fs'; +import * as path from 'path'; + +/** + * Discovers the path to the pandoc executable that ships with Positron. + * + * @returns The path to the pandoc executable, if it exists. + */ +export function getPandocPath(): string | undefined { + const pandocPath = path.join(vscode.env.appRoot, + process.platform === 'darwin' ? + path.join('bin', 'pandoc') : + path.join('..', '..', 'bin', 'pandoc')); + if (existsSync(pandocPath)) { + return pandocPath; + } +} diff --git a/extensions/positron-r/src/session.ts b/extensions/positron-r/src/session.ts index 53eabb4d9be..d831c80a884 100644 --- a/extensions/positron-r/src/session.ts +++ b/extensions/positron-r/src/session.ts @@ -18,7 +18,7 @@ import { randomUUID } from 'crypto'; import { handleRCode } from './hyperlink'; import { RSessionManager } from './session-manager'; import { EXTENSION_ROOT_DIR } from './constants'; -import { existsSync } from 'fs'; +import { getPandocPath } from './pandoc'; interface RPackageInstallation { packageName: string; @@ -704,11 +704,8 @@ export function createJupyterKernelSpec( // // On MacOS, the binary path lives alongside the app bundle; on other // platforms, it's a couple of directories up from the app root. - const pandocPath = path.join(vscode.env.appRoot, - process.platform === 'darwin' ? - path.join('bin', 'pandoc') : - path.join('..', '..', 'bin', 'pandoc')); - if (existsSync(pandocPath)) { + const pandocPath = getPandocPath(); + if (pandocPath) { env['RSTUDIO_PANDOC'] = pandocPath; } diff --git a/extensions/positron-r/src/tasks.ts b/extensions/positron-r/src/tasks.ts index 672f563cea0..91b0afb8fb9 100644 --- a/extensions/positron-r/src/tasks.ts +++ b/extensions/positron-r/src/tasks.ts @@ -6,6 +6,7 @@ import * as vscode from 'vscode'; import { RSessionManager } from './session-manager'; import { getEditorFilePathForCommand } from './commands'; +import { getPandocPath } from './pandoc'; export class RPackageTaskProvider implements vscode.TaskProvider { @@ -57,6 +58,15 @@ export async function getRPackageTasks(editorFilePath?: string): Promise new vscode.Task( { type: 'rPackageTask', task: data.task, pkg: data.package }, @@ -65,7 +75,8 @@ export async function getRPackageTasks(editorFilePath?: string): Promise