Skip to content

Commit 5459d50

Browse files
committed
WIP windows support
1 parent d015c54 commit 5459d50

File tree

4 files changed

+44
-26
lines changed

4 files changed

+44
-26
lines changed

src/executables/index.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,11 @@ export class RExecutableManager implements vscode.Disposable {
112112
* @returns boolean
113113
*/
114114
export function validateRExecutablePath(execPath: string): boolean {
115-
const basename = process.platform === 'win32' ? 'R.exe' : 'R';
116-
return fs.existsSync(execPath) && (path.basename(execPath) === basename);
115+
try {
116+
const basename = process.platform === 'win32' ? 'R.exe' : 'R';
117+
fs.accessSync(execPath, fs.constants.X_OK);
118+
return (path.basename(execPath) === basename);
119+
} catch (error) {
120+
return false;
121+
}
117122
}

src/executables/service/locator/shared.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
import { execSync } from 'child_process';
1+
import { spawnSync } from 'child_process';
22
import * as fs from 'fs-extra';
33
import * as vscode from 'vscode';
44
import { normaliseRPathString } from '../../../util';
55

6-
export function getRDetailsFromPath(rPath: string): {version: string, arch: string} {
6+
export function getRDetailsFromPath(rPath: string): { version: string, arch: string } {
77
try {
88
const path = normaliseRPathString(rPath);
9-
const child = execSync(`${path} --version`)?.toString();
10-
const versionRegex = /(?<=R version\s)[0-9.]*/g;
9+
const child = spawnSync(path, [`--version`]).output.join('\n');
10+
const versionRegex = /(?<=R\sversion\s)[0-9.]*/g;
1111
const archRegex = /[0-9]*-bit/g;
1212
const out = {
1313
version: child.match(versionRegex)?.[0] ?? '',

src/executables/service/locator/windows.ts

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,15 @@ import * as vscode from 'vscode';
33
import path = require('path');
44
import winreg = require('winreg');
55
import { getUniquePaths, AbstractLocatorService } from './shared';
6+
import { validateRExecutablePath } from '../..';
7+
8+
const WindowsKnownPaths = [
9+
path.join(process.env.ProgramFiles, 'R'),
10+
path.join(process.env['ProgramFiles(x86)'], 'R'),
11+
path.join(process.env.ProgramFiles, 'Microsoft', 'R Open'),
12+
path.join(process.env.ProgramFiles, 'Microsoft', 'R Open'),
13+
];
14+
615

716
export class WindowsExecLocator extends AbstractLocatorService {
817
constructor() {
@@ -62,22 +71,19 @@ export class WindowsExecLocator extends AbstractLocatorService {
6271

6372
private getHomeFromDirs(): string[] {
6473
const dirBins: string[] = [];
65-
const potential_bin_paths: string[] = [
66-
'%ProgramFiles%\\R\\',
67-
'%ProgramFiles(x86)%\\R\\'
68-
];
69-
for (const bin of potential_bin_paths) {
70-
const resolvedBin = path.resolve(bin);
71-
if (fs.existsSync(resolvedBin)) {
72-
const i386 = `${resolvedBin}\\i386\\`;
73-
const x64 = `${resolvedBin}\\x64\\`;
74-
75-
if (fs.existsSync(i386)) {
76-
dirBins.push(i386);
77-
}
74+
for (const bin of WindowsKnownPaths) {
75+
if (fs.existsSync(bin)) {
76+
const dirs = fs.readdirSync(bin);
77+
for (const dir of dirs) {
78+
const i386 = `${bin}\\${dir}\\bin\\i386\\R.exe`;
79+
const x64 = `${bin}\\${dir}\\bin\\x64\\R.exe`;
80+
if (validateRExecutablePath(i386)) {
81+
dirBins.push(i386);
82+
}
7883

79-
if (fs.existsSync(x64)) {
80-
dirBins.push(x64);
84+
if (validateRExecutablePath(x64)) {
85+
dirBins.push(x64);
86+
}
8187
}
8288
}
8389
}
@@ -90,7 +96,7 @@ export class WindowsExecLocator extends AbstractLocatorService {
9096

9197
if (os_paths) {
9298
for (const os_path of os_paths) {
93-
const os_r_path: string = path.join(os_path, 'R' + '.exe');
99+
const os_r_path: string = path.join(os_path, '/R.exe');
94100
if (fs.existsSync(os_r_path)) {
95101
envBins.push(os_r_path);
96102
}

src/executables/ui/quickpick.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import path = require('path');
12
import * as vscode from 'vscode';
23

34
import { ExecutableNotifications } from '.';
@@ -64,6 +65,9 @@ export class ExecutableQuickPick implements vscode.Disposable {
6465
private setItems(): void {
6566
const qpItems: vscode.QuickPickItem[] = [];
6667
const configPath = config().get<string>(getRPathConfigEntry());
68+
const sortExecutables = (a: ExecutableType, b: ExecutableType) => {
69+
return -a.rVersion.localeCompare(b.rVersion, undefined, { numeric: true, sensitivity: 'base' });
70+
};
6771
qpItems.push(
6872
{
6973
label: PathQuickPickMenu.search,
@@ -101,7 +105,7 @@ export class ExecutableQuickPick implements vscode.Disposable {
101105
}
102106
];
103107

104-
[...this.service.executables].forEach((v) => {
108+
[...this.service.executables].sort(sortExecutables).forEach((v) => {
105109
const item = new ExecutableQuickPickItem(v, recommendPath(v, this.currentFolder, renvVersion));
106110
if (item.recommended) {
107111
recommendedItems.push(item);
@@ -118,6 +122,8 @@ export class ExecutableQuickPick implements vscode.Disposable {
118122
}
119123
}
120124
});
125+
126+
121127
this.quickpick.items = [...qpItems, ...recommendedItems, ...virtualItems, ...globalItems];
122128
for (const item of this.quickpick.items) {
123129
if (item.description === this.service.getWorkspaceExecutable(this.currentFolder?.uri?.fsPath)?.rBin) {
@@ -172,9 +178,10 @@ export class ExecutableQuickPick implements vscode.Disposable {
172178
canSelectMany: false,
173179
title: ' R executable file'
174180
};
175-
void vscode.window.showOpenDialog(opts).then((execPath) => {
176-
if (execPath?.[0].fsPath && validateRExecutablePath(execPath[0].fsPath)) {
177-
const rExec = this.service.executableFactory.create(execPath[0].fsPath);
181+
void vscode.window.showOpenDialog(opts).then((epath) => {
182+
const execPath = path.normalize(epath?.[0].fsPath);
183+
if (execPath && validateRExecutablePath(execPath)) {
184+
const rExec = this.service.executableFactory.create(execPath);
178185
this.service.setWorkspaceExecutable(this.currentFolder?.uri?.fsPath, rExec);
179186
} else {
180187
void vscode.window.showErrorMessage(ExecutableNotifications.badFolder);

0 commit comments

Comments
 (0)