Skip to content

Commit 9374907

Browse files
Merge pull request #100 from ManuelHentschel/debugConfig
Improve debug config handling
2 parents 1d804ed + 5d0a5fa commit 9374907

File tree

13 files changed

+198
-152
lines changed

13 files changed

+198
-152
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ R/test*
99
!.vscode/tasks.json
1010
!.vscode/launch.json
1111

12+
test/R/*
13+
!test/R/.vscode/launch.json
14+
!test/R/objects.R
15+
1216
*.temp
1317
*.tmp
1418
tmp.*

package.json

Lines changed: 49 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
"onLanguage:rmd",
3636
"onCommand:rdebugger.updateRPackage",
3737
"workspaceContains:*.{rproj,Rproj,r,R,rd,Rd,rmd,Rmd}",
38+
"onDebugDynamicConfigurations:R-Debugger",
3839
"onDebug"
3940
],
4041
"keywords": [
@@ -72,6 +73,7 @@
7273
"debuggers": [
7374
{
7475
"type": "R-Debugger",
76+
"languages": ["r"],
7577
"label": "R Debugger",
7678
"program": "./out/debugAdapter.js",
7779
"runtime": "node",
@@ -245,39 +247,51 @@
245247
}
246248
}
247249
},
248-
"initialConfigurations": [
250+
"configurationSnippets": [
249251
{
250-
"type": "R-Debugger",
251-
"request": "launch",
252-
"name": "Launch Workspace",
253-
"debugMode": "workspace",
254-
"workingDirectory": "${workspaceFolder}",
255-
"allowGlobalDebugging": true
252+
"label": "R: Launch Workspace",
253+
"body": {
254+
"type": "R-Debugger",
255+
"request": "launch",
256+
"name": "Launch Workspace",
257+
"debugMode": "workspace",
258+
"workingDirectory": "${workspaceFolder}",
259+
"allowGlobalDebugging": true
260+
}
256261
},
257262
{
258-
"type": "R-Debugger",
259-
"request": "launch",
260-
"name": "Debug R-File",
261-
"debugMode": "file",
262-
"workingDirectory": "${workspaceFolder}",
263-
"file": "${file}",
264-
"allowGlobalDebugging": true
263+
"label": "R: Debug File",
264+
"body": {
265+
"type": "R-Debugger",
266+
"request": "launch",
267+
"name": "Debug R-File",
268+
"debugMode": "file",
269+
"workingDirectory": "${workspaceFolder}",
270+
"file": "${file}",
271+
"allowGlobalDebugging": true
272+
}
265273
},
266274
{
267-
"type": "R-Debugger",
268-
"request": "launch",
269-
"name": "Debug R-Function",
270-
"debugMode": "function",
271-
"workingDirectory": "${fileDirname}",
272-
"file": "${file}",
273-
"mainFunction": "main",
274-
"allowGlobalDebugging": false
275+
"label": "R: Debug Function",
276+
"body": {
277+
"type": "R-Debugger",
278+
"request": "launch",
279+
"name": "Debug R-Function",
280+
"debugMode": "function",
281+
"workingDirectory": "${workspaceFolder}",
282+
"file": "${file}",
283+
"mainFunction": "main",
284+
"allowGlobalDebugging": false
285+
}
275286
},
276287
{
277-
"type": "R-Debugger",
278-
"request": "attach",
279-
"name": "Attach to R process",
280-
"splitOverwrittenOutput": true
288+
"label": "R: Attach to process",
289+
"body": {
290+
"type": "R-Debugger",
291+
"request": "attach",
292+
"name": "Attach to R process",
293+
"splitOverwrittenOutput": true
294+
}
281295
}
282296
]
283297
}
@@ -301,6 +315,14 @@
301315
"default": "",
302316
"description": "R path for Linux. If empty, the PATH is searched for an R executable."
303317
},
318+
"rdebugger.rterm.args": {
319+
"type": "array",
320+
"items": {
321+
"type": "string"
322+
},
323+
"default": [],
324+
"description": "Additional command line arguments used when launching R."
325+
},
304326
"rdebugger.timeouts.startup": {
305327
"type": "number",
306328
"default": 2000,
@@ -328,7 +350,7 @@
328350
},
329351
"rdebugger.trackTerminals": {
330352
"type": "boolean",
331-
"default": true,
353+
"default": false,
332354
"description": "Whether to track terminals opened while using the extension. Recommended for debugging in attached mode on windows."
333355
}
334356
}

src/debugRuntime.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,10 +168,11 @@ export class DebugRuntime extends EventEmitter {
168168
} else {
169169
const rPath = rStartupArguments.path;
170170
const message = 'R path not working:\n' + rPath + '\n(Can be changed in setting rdebugger.rterm.XXX)';
171-
await this.abortInitializeRequest(response, message);
171+
const abortPromise = this.abortInitializeRequest(response, message);
172172
this.writeOutput('R not responding within ' + this.startupTimeout + 'ms!', true, true);
173173
this.writeOutput('R path:\n' + rPath, true, true);
174-
this.writeOutput('If R is installed but in a different path, please adjust the setting rdebugger.rterm.windows/mac/linux.');
174+
this.writeOutput('If R is installed but in a different path, please adjust the setting rdebugger.rterm.windows/mac/linux.\n');
175+
await abortPromise;
175176
return false;
176177
}
177178

src/extension.ts

Lines changed: 115 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
// The module 'vscode' contains the VS Code extensibility API
22
// Import the module and reference it with the alias vscode in your code below
33
import * as vscode from 'vscode';
4-
import { WorkspaceFolder, ProviderResult, CancellationToken } from 'vscode';
4+
import { WorkspaceFolder, ProviderResult, CancellationToken, DebugConfigurationProviderTriggerKind } from 'vscode';
55
import { DebugSession } from './debugSession';
66
import {
7-
DebugConfiguration, DebugMode, FunctionDebugConfiguration,
7+
DebugMode, FunctionDebugConfiguration,
88
FileDebugConfiguration, WorkspaceDebugConfiguration,
99
StrictDebugConfiguration,
1010
AttachConfiguration
@@ -20,9 +20,19 @@ export async function activate(context: vscode.ExtensionContext) {
2020
terminalHandler = new TerminalHandler();
2121
const port = await terminalHandler.portPromise;
2222

23-
// register a configuration provider
24-
const provider = new DebugConfigurationProvider(port);
25-
context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider('R-Debugger', provider));
23+
console.log('activate');
24+
25+
// register configuration resolver
26+
const resolver = new DebugConfigurationResolver(port);
27+
context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider('R-Debugger', resolver));
28+
29+
// register dynamic configuration provider
30+
const dynamicProvider = new DynamicDebugConfigurationProvider();
31+
context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider('R-Debugger', dynamicProvider, DebugConfigurationProviderTriggerKind.Dynamic));
32+
33+
// register initial configuration provider
34+
const initialProvider = new InitialDebugConfigurationProvider();
35+
context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider('R-Debugger', initialProvider, DebugConfigurationProviderTriggerKind.Initial));
2636

2737
// register the debug adapter descriptor provider
2838
const factory = new DebugAdapterDescriptorFactory();
@@ -48,8 +58,100 @@ export function deactivate() {
4858
}
4959
}
5060

61+
class InitialDebugConfigurationProvider implements vscode.DebugConfigurationProvider {
62+
provideDebugConfigurations(folder: WorkspaceFolder | undefined): ProviderResult<StrictDebugConfiguration[]>{
63+
return [
64+
{
65+
type: "R-Debugger",
66+
request: "launch",
67+
name: "Launch Workspace",
68+
debugMode: "workspace",
69+
workingDirectory: "${workspaceFolder}",
70+
allowGlobalDebugging: true
71+
},
72+
{
73+
type: "R-Debugger",
74+
request: "launch",
75+
name: "Debug R-File",
76+
debugMode: "file",
77+
workingDirectory: "${workspaceFolder}",
78+
file: "${file}",
79+
allowGlobalDebugging: true
80+
},
81+
{
82+
type: "R-Debugger",
83+
request: "launch",
84+
name: "Debug R-Function",
85+
debugMode: "function",
86+
workingDirectory: "${workspaceFolder}",
87+
file: "${file}",
88+
mainFunction: "main",
89+
allowGlobalDebugging: false
90+
},
91+
{
92+
type: "R-Debugger",
93+
request: "attach",
94+
name: "Attach to R process",
95+
splitOverwrittenOutput: true
96+
}
97+
];
98+
}
99+
}
51100

52-
class DebugConfigurationProvider implements vscode.DebugConfigurationProvider {
101+
class DynamicDebugConfigurationProvider implements vscode.DebugConfigurationProvider {
102+
103+
provideDebugConfigurations(folder: WorkspaceFolder | undefined): ProviderResult<StrictDebugConfiguration[]>{
104+
105+
const doc = vscode.window.activeTextEditor;
106+
const docValid = doc && doc.document.uri.scheme === 'file';
107+
const wd = (folder ? '${workspaceFolder}' : (docValid ? '${fileDirname}' : '.'));
108+
109+
let configs: StrictDebugConfiguration[] = [];
110+
111+
configs.push({
112+
type: "R-Debugger",
113+
request: "launch",
114+
name: "Launch Workspace",
115+
debugMode: "workspace",
116+
workingDirectory: wd,
117+
allowGlobalDebugging: true
118+
});
119+
120+
if(docValid){
121+
configs.push({
122+
type: "R-Debugger",
123+
request: "launch",
124+
name: "Debug R-File",
125+
debugMode: "file",
126+
workingDirectory: wd,
127+
file: "${file}",
128+
allowGlobalDebugging: true
129+
});
130+
131+
configs.push({
132+
type: "R-Debugger",
133+
request: "launch",
134+
name: "Debug R-Function",
135+
debugMode: "function",
136+
workingDirectory: wd,
137+
file: "${file}",
138+
mainFunction: "main",
139+
allowGlobalDebugging: false
140+
});
141+
};
142+
143+
configs.push({
144+
type: "R-Debugger",
145+
request: "attach",
146+
name: "Attach to R process",
147+
splitOverwrittenOutput: true
148+
});
149+
150+
return configs;
151+
}
152+
}
153+
154+
class DebugConfigurationResolver implements vscode.DebugConfigurationProvider {
53155

54156
readonly customPort: number;
55157
readonly customHost: string;
@@ -63,11 +165,13 @@ class DebugConfigurationProvider implements vscode.DebugConfigurationProvider {
63165

64166
let strictConfig: StrictDebugConfiguration|null = null;
65167

66-
// if launch.json is missing or empty
168+
// if the debugger was launched without config
67169
if (!config.type && !config.request && !config.name) {
170+
68171
const doc = vscode.window.activeTextEditor;
69-
const wd = (folder ? '{$workspaceFolder}' : (doc ? '${fileDirname}' : '~'));
70-
if(doc){
172+
const docValid = doc && doc.document.uri.scheme === 'file';
173+
const wd = (folder ? '${workspaceFolder}' : (docValid ? '${fileDirname}' : '.'));
174+
if(docValid){
71175
// if file is open, debug file
72176
config = {
73177
type: "R-Debugger",
@@ -77,22 +181,15 @@ class DebugConfigurationProvider implements vscode.DebugConfigurationProvider {
77181
file: "${file}",
78182
workingDirectory: wd
79183
};
80-
} else if(wd){
184+
} else{
81185
// if folder but no file is open, launch workspace
82186
config = {
83187
type: "R-Debugger",
84188
name: "Launch R Debugger",
85189
request: "launch",
86-
debugMode: "file",
190+
debugMode: "workspace",
87191
workingDirectory: wd
88192
};
89-
} else{
90-
// if no file/folder open, attach
91-
config = {
92-
type: 'R-Debugger',
93-
name: 'Launch',
94-
request: 'attach'
95-
};
96193
}
97194
}
98195

src/installRPackage.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ export async function updateRPackage(packageName:string = 'vscDebugger') {
2525
terminal.show();
2626
terminal.sendText(
2727
rPath +
28-
" --no-save" +
28+
" --vanilla" +
29+
" --silent" +
2930
" -e \"install.packages('" + url + "', repos=NULL)\"" +
3031
" -e \"install.packages('jsonlite', repos='http://cran.r-project.org')\"" +
3132
" -e \"install.packages('R6', repos='http://cran.r-project.org')\""

src/rSession.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@ export class RSession {
125125
text = text.replace(/\r/g,''); //keep only \n as linebreak
126126
text = (this.restOfLine[from] || "") + text; // append to rest of line from previouse call
127127
const lines = text.split(/\n/); // split into lines
128+
129+
logger.debug(`data from ${from}: ${text}`);
128130

129131
for(let i = 0; i<lines.length; i++){
130132
// abort output handling if ignoreOutput has been set to true

src/terminals.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ async function writeToStdin(args: WriteToStdinArgs){
151151
terminal.sendText(args.text, args.addNewLine);
152152
return true;
153153
} else{
154-
logger.debug('No terminal found.')
154+
logger.debug('No terminal found.');
155155
return false;
156156
}
157157
}

src/utils.ts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,20 +82,31 @@ export async function getRStartupArguments(): Promise<RStartupArguments> {
8282

8383
if (rpath === "") {
8484
rpath = getRfromEnvPath(platform);
85-
rArgs = ['--ess', '--quiet', '--interactive', '--no-save'];
8685
}
86+
87+
// enclose path in quotes if it contains spaces (and isn't quoted yet)
88+
if(rpath.match(/^[^"'].* .*[^"']$/)){
89+
rpath = `"${rpath}"`;
90+
}
91+
// replace single quotes with double quotes on windows
92+
if(platform === "win32" && rpath.match(/^'.* .*'$/)){
93+
rpath = rpath.replace(/^'(.*)'$/, '"$1"');
94+
}
95+
96+
// add user specified args
97+
const customArgs = config().get<Array<string>>("rterm.args");
98+
rArgs = rArgs.concat(customArgs);
99+
87100
const ret: RStartupArguments = {
88101
path: rpath,
89102
args: rArgs,
90103
cwd: undefined
91104
};
92105

93-
if (rpath !== "") {
94-
return ret;
95-
} else{
106+
if(rpath === ""){
96107
window.showErrorMessage(`${process.platform} can't find R`);
97-
return ret;
98108
}
109+
return ret;
99110
}
100111

101112

0 commit comments

Comments
 (0)