Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
* feat: check sess package version and prompt for update
* feat(session): implement file-based reconnection and suppress verbose logs
* feat(plot): new `r.plot.backend` enum setting for finer-grained control of the preferred plotting backend, including integration with the lightweight `jgd` graphics device (default if installed). `r.plot.useHttpgd` is deprecated in favor of `r.plot.backend`; it remains supported for compatibility with existing configurations but will be removed in a future release.
* feat(term): new `r.rterm.preferredConsoles` enum setting enables for string-based R console selection (`"R"` (default), `"arf"`, and/or `"radian"`), automatically resolved against the user's `PATH`. `r.term.<os>` is still respected (and prioritized) if provided.
* feat(r-path): add `r.executablePath` as the canonical setting for vanilla R used by background processes and `r.consolePath` for the interactive R console. Both accept an absolute or substituted path, or a bare executable name available on `PATH`; for example, `r.executablePath` can be the bare vanilla executable name `R`, while `r.consolePath` can be `arf` (or `radian`). Path settings are resolved against the relevant workspace resource when one is available. When `r.consolePath` and the legacy `r.rterm.<platform>` setting are unset, an explicitly configured `r.executablePath` is also used for the console. The legacy `r.rpath.<platform>` settings never affect console selection. The legacy `r.rpath.<platform>` and `r.rterm.<platform>` settings are deprecated in favor of the canonical settings, remain supported for backward compatibility, and may be removed in a future release.
* feat(dataview): keep one viewer per data name, refreshing the existing viewer on repeated `View()` calls
* feat(dataview): load data rows on demand while scrolling, with support for Arrow and Polars DataFrames
* feat(workspace): support recursive expansion of nested lists, environments, pairlists, S4 objects, and data frames
Expand All @@ -29,6 +29,7 @@

* Remove the unused `r.workspaceViewer.showObjectSize` setting and obsolete object-size tooltip support
* Remove obsolete `r.session.objectLengthLimit`, `r.session.objectTimeout`, and `r.session.levelOfObjectDetail` settings following the switch to on-demand workspace inspection
* Remove `r.helpPanel.rpath`, which was previously deprecated and no longer used by the extension

### Styling

Expand Down
53 changes: 30 additions & 23 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1281,35 +1281,59 @@
"type": "object",
"title": "R",
"properties": {
"r.executablePath": {
"type": "string",
"default": "",
"scope": "machine-overridable",
"markdownDescription": "Absolute or substituted path to the vanilla R executable used for background processes, or an executable name available on `PATH`. Do not use alternative consoles such as arf or radian. The supported substitutions are `${userHome}`, `${workspaceFolder}`, `${fileWorkspaceFolder}`, and `${fileDirname}`."
},
"r.consolePath": {
"type": "string",
"default": "",
"scope": "machine-overridable",
"markdownDescription": "Absolute or substituted path to the executable used to launch the interactive R console, or an executable name available on `PATH`. Alternative consoles such as arf (or radian) are supported. The supported substitutions are `${userHome}`, `${workspaceFolder}`, `${fileWorkspaceFolder}`, and `${fileDirname}`."
},
"r.rpath.windows": {
"type": "string",
"default": "",
"markdownDescription": "Path to an R executable to launch R background processes (Windows). Must be \"vanilla\" R, not radian etc.! Some variables defined in <https://code.visualstudio.com/docs/editor/variables-reference> such as `${userHome}`, `${workspaceFolder}`, `${fileWorkspaceFolder}`, and `${fileDirname}` are supported."
"markdownDescription": "Path to an R executable to launch R background processes (Windows). Must be \"vanilla\" R, not radian etc.! Some variables defined in <https://code.visualstudio.com/docs/editor/variables-reference> such as `${userHome}`, `${workspaceFolder}`, `${fileWorkspaceFolder}`, and `${fileDirname}` are supported.",
"markdownDeprecationMessage": "Deprecated. Use `#r.executablePath#` instead.",
"deprecationMessage": "Deprecated. Use r.executablePath instead."
},
"r.rpath.mac": {
"type": "string",
"default": "",
"markdownDescription": "Path to an R executable to launch R background processes (macOS). Must be \"vanilla\" R, not radian etc.! Some variables defined in <https://code.visualstudio.com/docs/editor/variables-reference> such as `${userHome}`, `${workspaceFolder}`, `${fileWorkspaceFolder}`, and `${fileDirname}` are supported."
"markdownDescription": "Path to an R executable to launch R background processes (macOS). Must be \"vanilla\" R, not radian etc.! Some variables defined in <https://code.visualstudio.com/docs/editor/variables-reference> such as `${userHome}`, `${workspaceFolder}`, `${fileWorkspaceFolder}`, and `${fileDirname}` are supported.",
"markdownDeprecationMessage": "Deprecated. Use `#r.executablePath#` instead.",
"deprecationMessage": "Deprecated. Use r.executablePath instead."
},
"r.rpath.linux": {
"type": "string",
"default": "",
"markdownDescription": "Path to an R executable to launch R background processes (Linux). Must be \"vanilla\" R, not radian etc.! Some variables defined in <https://code.visualstudio.com/docs/editor/variables-reference> such as `${userHome}`, `${workspaceFolder}`, `${fileWorkspaceFolder}`, and `${fileDirname}` are supported."
"markdownDescription": "Path to an R executable to launch R background processes (Linux). Must be \"vanilla\" R, not radian etc.! Some variables defined in <https://code.visualstudio.com/docs/editor/variables-reference> such as `${userHome}`, `${workspaceFolder}`, `${fileWorkspaceFolder}`, and `${fileDirname}` are supported.",
"markdownDeprecationMessage": "Deprecated. Use `#r.executablePath#` instead.",
"deprecationMessage": "Deprecated. Use r.executablePath instead."
},
"r.rterm.windows": {
"type": "string",
"default": "",
"markdownDescription": "R path for interactive terminals (Windows). Can also be radian etc. Some variables defined in <https://code.visualstudio.com/docs/editor/variables-reference> such as `${userHome}`, `${workspaceFolder}`, `${fileWorkspaceFolder}`, and `${fileDirname}` are supported."
"markdownDescription": "R path for interactive terminals (Windows). Can also be arf or radian. Some variables defined in <https://code.visualstudio.com/docs/editor/variables-reference> such as `${userHome}`, `${workspaceFolder}`, `${fileWorkspaceFolder}`, and `${fileDirname}` are supported.",
"markdownDeprecationMessage": "Deprecated. Use `#r.consolePath#` instead.",
"deprecationMessage": "Deprecated. Use r.consolePath instead."
},
"r.rterm.mac": {
"type": "string",
"default": "",
"markdownDescription": "R path for interactive terminals (macOS). Can also be radian etc. Some variables defined in <https://code.visualstudio.com/docs/editor/variables-reference> such as `${userHome}`, `${workspaceFolder}`, `${fileWorkspaceFolder}`, and `${fileDirname}` are supported."
"markdownDescription": "R path for interactive terminals (macOS). Can also be arf or radian. Some variables defined in <https://code.visualstudio.com/docs/editor/variables-reference> such as `${userHome}`, `${workspaceFolder}`, `${fileWorkspaceFolder}`, and `${fileDirname}` are supported.",
"markdownDeprecationMessage": "Deprecated. Use `#r.consolePath#` instead.",
"deprecationMessage": "Deprecated. Use r.consolePath instead."
},
"r.rterm.linux": {
"type": "string",
"default": "",
"markdownDescription": "R path for interactive terminals (Linux). Can also be radian etc. Some variables defined in <https://code.visualstudio.com/docs/editor/variables-reference> such as `${userHome}`, `${workspaceFolder}`, `${fileWorkspaceFolder}`, and `${fileDirname}` are supported."
"markdownDescription": "R path for interactive terminals (Linux). Can also be arf or radian. Some variables defined in <https://code.visualstudio.com/docs/editor/variables-reference> such as `${userHome}`, `${workspaceFolder}`, `${fileWorkspaceFolder}`, and `${fileDirname}` are supported.",
"markdownDeprecationMessage": "Deprecated. Use `#r.consolePath#` instead.",
"deprecationMessage": "Deprecated. Use r.consolePath instead."
},
"r.rterm.option": {
"type": "array",
Expand All @@ -1322,16 +1346,6 @@
"type": "string"
}
},
"r.rterm.preferredConsoles": {
"type": "array",
"default": [
"R"
],
"markdownDescription": "Ordered list of R console executable names to search for on `PATH` when no explicit terminal path is set (e.g. `r.rterm.linux`). The first entry found on `PATH` will be used. Examples: `arf`, `radian`, `R`.",
"items": {
"type": "string"
}
},
"r.libPaths": {
"type": "array",
"items": {
Expand Down Expand Up @@ -1497,13 +1511,6 @@
],
"markdownDescription": "Which local directories to try for local help pages previewer. Set to `[]` to disable."
},
"r.helpPanel.rpath": {
"type": "string",
"default": "",
"markdownDescription": "DEPRECATED! Path to an R executable. Must be \"vanilla\" R, not radian etc.! Will be read from registry or path if not set.",
"markdownDeprecationMessage": "Will be deprecated. Use `#r.rpath.windows#`, `#r.rpath.mac#`, or `#r.rpath.linux#` instead.",
"deprecationMessage": "Will be deprecated. Use r.rpath.windows, r.rpath.mac, or r.rpath.linux instead."
},
"r.helpPanel.enableHoverLinks": {
"type": "boolean",
"default": true,
Expand Down
4 changes: 2 additions & 2 deletions src/cppProperties.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import * as fs from 'fs';
import * as path from 'path';
import { window } from 'vscode';
import { Uri, window } from 'vscode';
import { getRpath, getCurrentWorkspaceFolder, executeRCommand, createTempDir } from './util';
import { execSync } from 'child_process';
import { extensionContext } from './extension';
Expand Down Expand Up @@ -36,7 +36,7 @@ function platformChoose<A, B, C>(win32: A, darwin: B, other: C): A | B | C {

// See: https://code.visualstudio.com/docs/cpp/c-cpp-properties-schema-reference
async function generateCppPropertiesProc(workspaceFolder: string) {
const rPath = await getRpath();
const rPath = await getRpath(false, undefined, Uri.file(workspaceFolder));
if (!rPath) {
return;
}
Expand Down
8 changes: 8 additions & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import * as plotViewer from './plotViewer';
import { PlotManager } from './plotViewer/types';
import * as languageService from './languageService';
import { RTaskProvider } from './tasks';
import { showRDebuggerCompatibilityWarningOnce } from './rDebuggerCompatibility';


// global objects used in other files
Expand All @@ -39,6 +40,13 @@ export let sessionStatusBarItem: vscode.StatusBarItem | undefined = undefined;

// Called (once) when the extension is activated
export async function activate(context: vscode.ExtensionContext): Promise<apiImplementation.RExtensionImplementation> {
const rDebugger = vscode.extensions.getExtension('RDebugger.r-debugger');
if (rDebugger) {
void showRDebuggerCompatibilityWarningOnce(context.globalState, rDebugger.packageJSON, message =>
vscode.window.showWarningMessage(message)
);
}

if (vscode.extensions.getExtension('mikhail-arkhipov.r')) {
void vscode.window.showInformationMessage('The R Tools (Mikhail-Arkhipov.r) extension is enabled and will have conflicts with vscode-R. To use vscode-R, please disable or uninstall the extension.');
void vscode.commands.executeCommand('workbench.extensions.search', '@installed R Tools');
Expand Down
3 changes: 1 addition & 2 deletions src/helpViewer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {
getRpath,
doWithProgress,
DummyMemento,
getRPathConfigEntry,
escapeHtml,
makeWebviewCommandUriString,
uniqueEntries,
Expand Down Expand Up @@ -532,7 +531,7 @@ export class RHelp implements api.HelpPanel, vscode.WebviewPanelSerializer<strin
);
if (!aliases) {
void vscode.window.showErrorMessage(
`Failed to get list of R functions. Make sure that \`jsonlite\` is installed and r.${getRPathConfigEntry()} points to a valid R executable.`,
'Failed to get list of R functions. Make sure that `jsonlite` is installed and r.executablePath points to a valid R executable.',
);
return undefined;
}
Expand Down
20 changes: 11 additions & 9 deletions src/languageService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { URL } from 'url';
import * as fs from 'fs';
import { LanguageClient, LanguageClientOptions, StreamInfo, DocumentFilter, ErrorAction, CloseAction, RevealOutputChannelOn } from 'vscode-languageclient/node';
import { Disposable, workspace, Uri, TextDocument, WorkspaceConfiguration, OutputChannel, window, WorkspaceFolder } from 'vscode';
import { DisposableProcess, getRLibPaths, getRpath, promptToInstallRPackage, spawn, substituteVariables } from './util';
import { config, DisposableProcess, getRLibPaths, getRpath, promptToInstallRPackage, spawn, substituteVariables } from './util';
import { extensionContext } from './extension';
import { CommonOptions } from 'child_process';

Expand Down Expand Up @@ -57,13 +57,15 @@ export class LanguageService implements Disposable {
}

private async createClient(selector: DocumentFilter[],
cwd: string, workspaceFolder: WorkspaceFolder | undefined, outputChannel: OutputChannel): Promise<LanguageClient> {
cwd: string, workspaceFolder: WorkspaceFolder | undefined, outputChannel: OutputChannel,
resource?: Uri): Promise<LanguageClient> {

let client: LanguageClient;

const resourceConfig = config(resource);
const debug = this.config.get<boolean>('lsp.debug');
const useRenvLibPath = this.config.get<boolean>('useRenvLibPath') ?? false;
const rPath = await getRpath() || ''; // TODO: Abort gracefully
const rPath = await getRpath(false, undefined, resource) || ''; // TODO: Abort gracefully
if (debug) {
console.log(`R path: ${rPath}`);
}
Expand All @@ -87,7 +89,7 @@ export class LanguageService implements Disposable {

const rScriptPath = extensionContext.asAbsolutePath('R/languageServer.R');
const options = { cwd: cwd, env: env };
const args = (this.config.get<string[]>('lsp.args')?.map(substituteVariables) ?? []).concat(
const args = (resourceConfig.get<string[]>('lsp.args')?.map(value => substituteVariables(value, resource)) ?? []).concat(
'--silent',
'--no-echo',
'--no-save',
Expand Down Expand Up @@ -227,7 +229,7 @@ export class LanguageService implements Disposable {
{ scheme: 'vscode-notebook-cell', language: 'r', pattern: `${document.uri.fsPath}` },
];
const client = await this.createClient(documentSelector,
dirname(document.uri.fsPath), folder, this.outputChannel);
dirname(document.uri.fsPath), folder, this.outputChannel, folder?.uri ?? document.uri);
this.clients.set(key, client);
this.initSet.delete(key);
}
Expand All @@ -245,7 +247,7 @@ export class LanguageService implements Disposable {
{ scheme: 'file', language: 'r', pattern: pattern },
{ scheme: 'file', language: 'rmd', pattern: pattern },
];
const client = await this.createClient(documentSelector, folder.uri.fsPath, folder, this.outputChannel);
const client = await this.createClient(documentSelector, folder.uri.fsPath, folder, this.outputChannel, folder.uri);
this.clients.set(key, client);
this.initSet.delete(key);
}
Expand All @@ -261,7 +263,7 @@ export class LanguageService implements Disposable {
{ scheme: 'untitled', language: 'r' },
{ scheme: 'untitled', language: 'rmd' },
];
const client = await this.createClient(documentSelector, os.homedir(), undefined, this.outputChannel);
const client = await this.createClient(documentSelector, os.homedir(), undefined, this.outputChannel, document.uri);
this.clients.set(key, client);
this.initSet.delete(key);
}
Expand All @@ -277,7 +279,7 @@ export class LanguageService implements Disposable {
{ scheme: 'file', pattern: document.uri.fsPath },
];
const client = await this.createClient(documentSelector,
dirname(document.uri.fsPath), undefined, this.outputChannel);
dirname(document.uri.fsPath), undefined, this.outputChannel, document.uri);
this.clients.set(key, client);
this.initSet.delete(key);
}
Expand Down Expand Up @@ -351,7 +353,7 @@ export class LanguageService implements Disposable {

const workspaceFolder = workspace.workspaceFolders?.[0];
const cwd = workspaceFolder ? workspaceFolder.uri.fsPath : os.homedir();
const client = await this.createClient(documentSelector, cwd, undefined, this.outputChannel);
const client = await this.createClient(documentSelector, cwd, undefined, this.outputChannel, workspaceFolder?.uri);
this.clients.set('global', client);
}
}
Expand Down
44 changes: 44 additions & 0 deletions src/rDebuggerCompatibility.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import * as vscode from 'vscode';

export const rDebuggerCompatibilityWarningKey = 'rDebuggerLegacyRPathCompatibilityWarning.v1';

const legacyRPathSettings = [
'r.rpath.windows',
'r.rpath.mac',
'r.rpath.linux',
];

const warningMessage = 'R Debugger still registers the legacy `r.rpath.<platform>` setting. Until it is updated, keep that setting and keep it in sync with `r.executablePath` so both extensions use the same R installation.';

function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === 'object' && value !== null && !Array.isArray(value);
}

export function registersLegacyRPathSetting(packageJSON: unknown): boolean {
if (!isRecord(packageJSON) || !isRecord(packageJSON.contributes)) {
return false;
}

const configuration = packageJSON.contributes.configuration;
const entries = Array.isArray(configuration) ? configuration : [configuration];
return entries.some(entry => {
const properties = isRecord(entry) ? entry.properties : undefined;
return isRecord(properties) && legacyRPathSettings.some(setting =>
Object.prototype.hasOwnProperty.call(properties, setting)
);
});
}

export async function showRDebuggerCompatibilityWarningOnce(
globalState: vscode.Memento,
packageJSON: unknown,
showWarning: (message: string) => unknown
): Promise<boolean> {
if (!registersLegacyRPathSetting(packageJSON) || globalState.get<boolean>(rDebuggerCompatibilityWarningKey)) {
return false;
}

await globalState.update(rDebuggerCompatibilityWarningKey, true);
void showWarning(warningMessage);
return true;
}
Loading
Loading