Skip to content

Commit a621bf8

Browse files
renkun-kengowerc
andauthored
Fix resolveTask (#994)
* Fix resolveTask * Update task definition * Use ProcessExecution instead * Remove comment * add in groups * added conditional tasks * added multi-workspace support; allowed r code execution * fixed minor bug * fixed 'install' being classed as a test * renamed variable * convert to use -e * added dynamic terminal + terminal args * Refine code * No need to specify options * Refine description Co-authored-by: gowerc <craiggower@gmail.com>
1 parent f5d857e commit a621bf8

File tree

2 files changed

+169
-92
lines changed

2 files changed

+169
-92
lines changed

package.json

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1673,7 +1673,45 @@
16731673
},
16741674
"taskDefinitions": [
16751675
{
1676-
"type": "R"
1676+
"type": "R",
1677+
"required": ["code"],
1678+
"properties": {
1679+
"code": {
1680+
"type": "array",
1681+
"items": {
1682+
"type": "string"
1683+
},
1684+
"default": [
1685+
"x <- 'Hello, World!'",
1686+
"print(x)"
1687+
],
1688+
"description": "R code to be executed"
1689+
},
1690+
"options": {
1691+
"type": "array",
1692+
"items": {
1693+
"type": "string"
1694+
},
1695+
"default": [
1696+
"--no-echo",
1697+
"--no-restore"
1698+
],
1699+
"description": "Command line options used to invoke R. (see R --help)"
1700+
},
1701+
"cwd": {
1702+
"type": "string",
1703+
"default": "${workspaceRoot}",
1704+
"description": "The current working directory of the executed program or shell. If omitted, the current workspace root will be used."
1705+
},
1706+
"env": {
1707+
"type": "object",
1708+
"additionalProperties": {
1709+
"type": "string"
1710+
},
1711+
"default": {},
1712+
"description": "The environment of the executed program or shell. If omitted, the current process environment will be used."
1713+
}
1714+
}
16771715
}
16781716
],
16791717
"problemMatchers": [

src/tasks.ts

Lines changed: 130 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,107 +1,146 @@
11
'use strict';
22

33
import * as vscode from 'vscode';
4+
import * as fs from 'fs';
5+
import * as path from 'path';
6+
import { getRpath } from './util';
47

5-
export class RTaskProvider implements vscode.TaskProvider {
6-
public readonly type = 'R';
78

8-
// `vscode.ShellQuoting.Strong` will treat the "value" as pure string
9-
// and quote them based on the shell used this can ensure it works for
10-
// different shells, e.g., zsh, PowerShell or cmd
11-
private readonly tasks = [
9+
const TYPE = 'R';
1210

13-
new vscode.Task(
14-
{ type: this.type },
15-
vscode.TaskScope.Workspace,
16-
'Build',
17-
'R',
18-
new vscode.ShellExecution(
19-
'Rscript',
20-
[
21-
'-e',
22-
{
23-
value: 'devtools::build()',
24-
quoting: vscode.ShellQuoting.Strong
25-
}
26-
]
27-
)
28-
),
11+
interface RTaskDefinition extends vscode.TaskDefinition {
12+
type: string,
13+
code: string[],
14+
options?: string[],
15+
cwd?: string,
16+
env?: { [key: string]: string }
17+
}
2918

30-
new vscode.Task(
31-
{ type: this.type },
32-
vscode.TaskScope.Workspace,
33-
'Check',
34-
'R',
35-
new vscode.ShellExecution(
36-
'Rscript',
37-
[
38-
'-e',
39-
{
40-
value: 'devtools::check()',
41-
quoting: vscode.ShellQuoting.Strong
42-
}
43-
]
44-
)
45-
),
19+
interface RTaskInfo {
20+
definition: RTaskDefinition,
21+
problemMatchers?: string | string[],
22+
name?: string,
23+
group?: vscode.TaskGroup
24+
}
4625

47-
new vscode.Task(
48-
{ type: this.type },
49-
vscode.TaskScope.Workspace,
50-
'Document',
51-
'R',
52-
new vscode.ShellExecution(
53-
'Rscript',
54-
[
55-
'-e',
56-
{
57-
value: 'devtools::document()',
58-
quoting: vscode.ShellQuoting.Strong
59-
}
60-
]
61-
)
62-
),
26+
function makeRArgs(options: string[], code: string[]) {
27+
const codeArgs: string[] = [];
28+
for (const line of code) {
29+
codeArgs.push('-e');
30+
codeArgs.push(line);
31+
}
32+
const args = options.concat(codeArgs);
33+
return args;
34+
}
35+
36+
const defaultOptions: string[] = ['--no-echo', '--no-restore'];
37+
const rtasks: RTaskInfo[] = [
38+
{
39+
definition: {
40+
type: TYPE,
41+
code: ['devtools::test()']
42+
},
43+
name: 'Test',
44+
group: vscode.TaskGroup.Test,
45+
problemMatchers: '$testthat'
46+
},
47+
48+
{
49+
definition: {
50+
type: TYPE,
51+
code: ['devtools::build()']
52+
},
53+
name: 'Build',
54+
group: vscode.TaskGroup.Build,
55+
problemMatchers: []
56+
},
57+
58+
{
59+
definition: {
60+
type: TYPE,
61+
code: ['devtools::check()']
62+
},
63+
name: 'Check',
64+
group: vscode.TaskGroup.Test,
65+
problemMatchers: []
66+
},
67+
68+
{
69+
definition: {
70+
type: TYPE,
71+
code: ['devtools::document()']
72+
},
73+
name: 'Document',
74+
group: vscode.TaskGroup.Build,
75+
problemMatchers: []
76+
},
77+
78+
{
79+
definition: {
80+
type: TYPE,
81+
code: ['devtools::install()']
82+
},
83+
name: 'Install',
84+
group: vscode.TaskGroup.Build,
85+
problemMatchers: []
86+
}
87+
];
6388

64-
new vscode.Task(
65-
{ type: this.type },
66-
vscode.TaskScope.Workspace,
67-
'Install',
68-
'R',
69-
new vscode.ShellExecution(
70-
'Rscript',
71-
[
72-
'-e',
73-
{
74-
value: 'devtools::install()',
75-
quoting: vscode.ShellQuoting.Strong
76-
}
77-
]
78-
)
89+
function asRTask(rPath: string, folder: vscode.WorkspaceFolder | vscode.TaskScope, info: RTaskInfo): vscode.Task {
90+
const args = makeRArgs(info.definition.options ?? defaultOptions, info.definition.code);
91+
const rtask: vscode.Task = new vscode.Task(
92+
info.definition,
93+
folder,
94+
info.name,
95+
info.definition.type,
96+
new vscode.ProcessExecution(
97+
rPath,
98+
args,
99+
{
100+
cwd: info.definition.cwd,
101+
env: info.definition.env
102+
}
79103
),
104+
info.problemMatchers
105+
);
106+
107+
rtask.group = info.group;
108+
return rtask;
109+
}
80110

81-
new vscode.Task(
82-
{ type: this.type },
83-
vscode.TaskScope.Workspace,
84-
'Test',
85-
'R',
86-
new vscode.ShellExecution(
87-
'Rscript',
88-
[
89-
'-e',
90-
{
91-
value: 'devtools::test()',
92-
quoting: vscode.ShellQuoting.Strong
93-
}
94-
]
95-
),
96-
'$testthat'
97-
)
98-
];
111+
export class RTaskProvider implements vscode.TaskProvider {
112+
113+
public type = TYPE;
99114

100-
public provideTasks(): vscode.Task[] {
101-
return this.tasks;
115+
public async provideTasks(): Promise<vscode.Task[]> {
116+
const folders = vscode.workspace.workspaceFolders;
117+
118+
if (!folders) {
119+
return [];
120+
}
121+
122+
const tasks: vscode.Task[] = [];
123+
const rPath = await getRpath(false);
124+
125+
for (const folder of folders) {
126+
const isRPackage = fs.existsSync(path.join(folder.uri.fsPath, 'DESCRIPTION'));
127+
if (isRPackage) {
128+
for (const rtask of rtasks) {
129+
const task = asRTask(rPath, folder, rtask);
130+
tasks.push(task);
131+
}
132+
}
133+
}
134+
return tasks;
102135
}
103136

104-
public resolveTask(task: vscode.Task): vscode.Task {
105-
return task;
137+
public async resolveTask(task: vscode.Task): Promise<vscode.Task> {
138+
const taskInfo: RTaskInfo = {
139+
definition: <RTaskDefinition>task.definition,
140+
group: task.group,
141+
name: task.name
142+
};
143+
const rPath = await getRpath(false);
144+
return asRTask(rPath, vscode.TaskScope.Workspace, taskInfo);
106145
}
107146
}

0 commit comments

Comments
 (0)