Skip to content

Commit 9121091

Browse files
Merge pull request #54 from ManuelHentschel/develop
Develop
2 parents 7ead3a0 + 0212e47 commit 9121091

File tree

15 files changed

+718
-466
lines changed

15 files changed

+718
-466
lines changed

images/features.png

110 KB
Loading

package-lock.json

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 19 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -118,51 +118,29 @@
118118
{
119119
"type": "R-Debugger",
120120
"request": "launch",
121-
"name": "R Debug File",
122-
"workingDirectory": "${fileDirname}",
123-
"file": "${file}",
124-
"debugMode": "file",
121+
"name": "Launch Workspace",
122+
"debugMode": "workspace",
123+
"workingDirectory": "${workspaceFolder}",
125124
"allowGlobalDebugging": true
126-
}
127-
],
128-
"configurationSnippets": [
129-
{
130-
"label": "R Debug: Launch Global Workspace",
131-
"description": "Start a Global R Workspace",
132-
"body": {
133-
"type": "R-Debugger",
134-
"request": "launch",
135-
"name": "R Debug Only Workspace",
136-
"debugMode": "workspace",
137-
"workingDirectory": "${workspaceFolder}",
138-
"allowGlobalDebugging": true
139-
}
140125
},
141126
{
142-
"label": "R Debug: Debug a .R file",
143-
"description": "Start R do debug a .R file",
144-
"body": {
145-
"type": "R-Debugger",
146-
"request": "launch",
147-
"name": "R Debug Only Workspace",
148-
"debugMode": "workspace",
149-
"workingDirectory": "${workspaceFolder}",
150-
"allowGlobalDebugging": true
151-
}
127+
"type": "R-Debugger",
128+
"request": "launch",
129+
"name": "Debug R-File",
130+
"debugMode": "file",
131+
"workingDirectory": "${workspaceFolder}",
132+
"file": "${file}",
133+
"allowGlobalDebugging": true
152134
},
153135
{
154-
"label": "R Debug: Debug a single function",
155-
"description": "Start R to debug a single function call, then exit",
156-
"body": {
157-
"type": "R-Debugger",
158-
"request": "launch",
159-
"name": "R Debug Function",
160-
"debugMode": "function",
161-
"workingDirectory": "${fileDirname}",
162-
"file": "${file}",
163-
"mainFunction": "main",
164-
"allowGlobalDebugging": false
165-
}
136+
"type": "R-Debugger",
137+
"request": "launch",
138+
"name": "Debug R-Function",
139+
"debugMode": "function",
140+
"workingDirectory": "${fileDirname}",
141+
"file": "${file}",
142+
"mainFunction": "main",
143+
"allowGlobalDebugging": false
166144
}
167145
]
168146
}
@@ -232,6 +210,7 @@
232210
},
233211
"dependencies": {
234212
"await-notify": "^1.0.1",
213+
"net": "^1.0.2",
235214
"vscode-debugadapter": "^1.40.0",
236215
"winreg": "^1.2.4"
237216
}

readme.md

Lines changed: 41 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# R Debugger
22

33
This extension adds debugging capabilities for the R programming language to Visual Studio Code.
4+
This extension depends on the R package [vscDebugger](https://github.com/ManuelHentschel/vscDebugger).
5+
For further R support see e.g. [vscode-R](https://github.com/Ikuyadeu/vscode-R).
46

57
## Using the Debugger
68
* Install the **R Debugger** extension in VS Code.
@@ -16,10 +18,8 @@ in the callstack labelled 'Global Workspace' to see the variables in `.GlobalEnv
1618
*For Windows users: If your R installation is from [CRAN](http://cran.r-project.org/mirrors.html) with default installation settings, especially **Save version number in registry** is enabled, then there's no need to specify `rdebugger.rterm.windows`.*
1719

1820
## Installation
19-
The VS code extension can be run from source by opening the project repo's root directory in vscode and pressing F5.
20-
21-
Alternatively the VS Code extension can be installed form the .vsix-file found on https://github.com/ManuelHentschel/VSCode-R-Debugger/actions?query=workflow%3Amain.
22-
To download the correct file, filter the commits by branch (develop or master), click the latest commit,
21+
The VS Code extension can be installed from the .vsix-file found on https://github.com/ManuelHentschel/VSCode-R-Debugger/actions?query=workflow%3Amain.
22+
To download the correct file, filter the commits by branch (develop or master), select the latest commit,
2323
and download the file `r-debugger.vsix` under the caption "Artifacts".
2424

2525

@@ -29,21 +29,24 @@ devtools::install_github("ManuelHentschel/vscDebugger", ref = "develop")
2929
```
3030
To install from the master branch, omit the argument `ref`.
3131

32-
3332
**Warning:** Currently there is no proper versioning/dependency system in place, so make sure to download both packages/extensions from the same branch (Master/develop) and at the same time.
3433

3534

3635
## Features
37-
The debugger includes the following features:
38-
* Controlling the program flow using *step*, *step in*, *step out*, *continue*
39-
* Breakpoints
40-
* Information about the stack trace, scopes, variables, and watch expressions in each frame/scope
41-
* Exception handling (breaks on exception, access to stack info)
42-
* Evaluation of arbitrary R code in the selected stack frame
43-
* Overwriting `print()` and `cat()` with modified versions that also print the calling source file and line to the debug console
44-
* Overwriting `source()` with `.vsc.debugSource()` to allow recursive debugging (i.e. breakpoints in files that are `source()`d from within another file)
45-
* Supports VS Code's remote development extensions
4636

37+
![features.png](images/features.png)
38+
39+
The debugger includes the following features:
40+
1. Run and debug R Code, using one of three debug modes (details see below)
41+
2. View scopes and variables of the currently selected stack frame.
42+
The value of most variables can be modified in this view.
43+
3. Add watch expressions that are evaluated in the selected stack frame on each breakpoint/step.
44+
4. View and browse through the call stack when execution is pause.
45+
5. Set breakpoints and break on errors.
46+
6. Control the program flow using *step*, *step in*, *step out*, *continue*.
47+
7. Output generated by the program is printed to the debug console (filtering out text printed by the browser itself).
48+
8. Add a modified version of `print` and `cat` that also prints a link to the file and line where the text was printed.
49+
9. Allow the execution of arbitrary R code in the currently selected stack frame.
4750

4851
## How it works
4952
The debugger works as follows:
@@ -53,7 +56,7 @@ The debugger works as follows:
5356
* After each step, function call etc., the debugger calls functions from the package `vscDebugger` to get info about the stack/variables
5457

5558
The output of the R process is read and parsed as follows:
56-
* Information sent by functions from `vscDebugger` is encoded as json and surrounded by keywords (`<v\s\c>...</v\s\c>`).
59+
* Information sent by functions from `vscDebugger` is encoded as json and sent via a TCP socket.
5760
These lines are parsed by the VS Code extension and not shown to the user.
5861
* Information printed by the `browser()` function is parsed and used to update the source file/line highlighted inside VS Code.
5962
These lines are also hidden from the user.
@@ -67,15 +70,15 @@ The intended usecases for these modes are:
6770
* `"workspace"`: Starts an R process in the background and sends all input into the debug console to the R process (but indirectly, through `eval()` nested in some helper functions).
6871
R Files can be run by focussing a file and pressing `F5`.
6972
The stack view contains a single dummy frame.
70-
To view the variables in the global environment it is often necessary to click this frame and expand the variables view.
73+
To view the variables in the global environment it is often necessary to click this frame and expand the variables view!
7174
This method is 'abusing' the debug adapter protocol to some extent, since the protocol is apparently not designed for ongoing interactive programming in a global workspace.
72-
* `"file"`: Is pretty much equivalent to launching the debugger with `"workspace"` and then calling `.vsc.debugSource()` on a file.
75+
* `"file"`: Is pretty much equivalent to launching the debugger with `"workspace"` and immediately calling `.vsc.debugSource()` on a file.
7376
Is hopefully the behaviour expected by users coming from R Studio etc.
7477
* `"function"`: The above debug modes introduce significant overhead by passing all input through `eval()` etc.
7578
and use a custom version of `source()`, which makes changes to the R code in order to set breakpoints.
7679
To provide a somewhat 'cleaner' method of running code, this debug mode can be used.
77-
The call to `main()` is entered directly into R's `stdin`, hence there are no additional functions on the call stack (as is the case when entering `main()` into the debug console).
78-
Breakpoints are set by using R's `trace(..., tracer=browser)` function, which is more robust than the custom breakpoint mechanism.
80+
The specified file is executed using the default `source` command ad breakpoints are set by using R's `trace(..., tracer=browser)` function, which is more robust than the custom breakpoint mechanism.
81+
<!-- The call to `main()` is entered directly into R's `stdin`, hence there are no additional functions on the call stack (as is the case when entering `main()` into the debug console). -->
7982

8083
The remaining config entries are:
8184
* `"workingDirectory"`: An absolute path to the desired work directory. Defaults to the workspace folder.
@@ -84,25 +87,30 @@ The remaining config entries are:
8487
* `"allowGlobalDebugging"`: Whether to keep the R session running after debugging and evaluate expressions from the debug console.
8588
Essential for debug moge `"workspace"`, recommended for `"file"`, usually not sensible for `"function"`.
8689

87-
90+
## Debugging R Packages
91+
In principle R packages can also be debugged using this extension.
92+
For this to work, the proper source information must be retained during installation of the package
93+
(check `attr(attr(FUNCTION_NAME, 'srcref'), 'srcfile')`).
94+
I personally do not know a bullet proof way to achieve this, but the following things might help:
95+
* The package must be installed from source code (not CRAN or `.tar.gz`)
96+
* The flag `--with-keep.source` should be set
97+
* Extensions containing C code seem to cause problems sometimes
98+
99+
In order to use the modified `print` and `cat` functions,
100+
import the `vscDebugger` extension in your package,
101+
assign `print <- vscDebugger::.vsc.print` and `cat <- vscDebugger::.vsc.cat`,
102+
and deactivate the modified `print`/`cat` statements in the debugger settings.
103+
Don't forget to remove these assignments after debugging.
88104

89105
## Warning
90-
Since the approach of parsing text output meant for human users is rather error prone, there are probably some cases that are not implemented correctly yet.
91-
In case of unexpected results, use `browser()` statements and run the code directly from a terminal (or RStudio).
92-
93-
In the following cases the debugger might not work correctly:
106+
In the following cases the debugger might not work correctly/as expected:
94107
* Calls to `trace()`, `tracingstate()`:
95108
These are used to implement breakpoints, so usage might interfere with the debugger's breakpoints
96109
* Calls to `browser()` without `.doTrace()`:
97-
In normal code, these will be recognized as breakpoints,
98-
but inside watch-expressions they will cause the debugger to become unresponsive
110+
Usually, these will be recognized as breakpoints, but they might cause problems in some circumstances (e.g. watch expressions)
99111
* Custom `options(error=...)`: the debugger uses its own `options(error=...)` to show stack trace etc. on error
100-
* Any form of (interactive) user input in the terminal during runtime:
101-
The debugger passes all user input through `eval(...)`, no direct input to stdin is passed to the R process
102-
* Extensive usage of `cat()` without linebreaks:
103-
Output parsing relies on parsing complete lines, so any output produced by `cat()` will only be shown after a linebreak.
104-
Using the option to overwrite `cat()` will show output immediately, but produce a linebreak after each `cat()` call.
105-
* Output to stdout that looks like output from `browser()`, the input prompt, or text meant for the debugger (e.g. `<v\s\c>...</v\s\c>`)
112+
* Any form of (interactive) user input in the terminal during runtime (e.g. `readline(stdin())`), since
113+
the debugger passes all user input through `eval(...)`.
106114
* Code that contains calls to `sys.calls()`, `sys.frames()`, `attr(..., 'srcref')` etc.:
107115
Since pretty much all code is evaluated through calls to `eval(...)` these results might be wrong. <!-- This problem might be reduced by using the "functional" debug mode --> <!-- (set `debugFunction` to `true` and specify a `mainFunction` in the launch config) -->
108116
If required, input in the debug console can be sent directly to R's `stdin` by prepending it with `###stdin`.
@@ -113,25 +121,11 @@ It might be possible, however, that the gathering of information about the stack
113121
Especially watch-expressions must be safe to be evaluated in any frame,
114122
since these are passed to `eval()` in the currently viewed frame any time the debugger hits a breakpoint or steps through the code.
115123

116-
117-
118-
## Debugging R Packages
119-
In principle R packages can also be debugged using this extension.
120-
Some details need to be considered:
121-
* The package must be installed from code using `--with-keep.source`
122-
* The modified `print()` and `cat()` versions are not used by calls from within the package.
123-
In order to use these, import the `vscDebugger` extension in your package, assign `print <- vscDebugger::.vsc.print` and `cat <- vscDebugger::.vsc.cat`, and deactivate the modified `print`/`cat` statements in the debugger settings.
124-
Don't forget to remove these assignments after debugging.
125-
126-
127-
## To do
124+
## Known Issues
128125
The following topics could be improved/fixed in the future.
129126

130127
Variables/Stack view
131128
* Summarize large lists (min, max, mean, ...)
132-
* Row-wise display of data.frames, column-wise display of matrices
133-
* Load large workspaces/lists in chunks (currently hardcoded 1000 items maximum)
134-
* Enable copying from variables list
135129
* Refine display of variables (can be customized by `.vsc.addVarInfo`, default config is to be improved)
136130

137131
Breakpoints
@@ -147,7 +141,6 @@ General
147141
Give user more direct access to the R session:
148142
* Use (visible) integrated terminal instead of background process,
149143
use `sink(..., split=TRUE)` to simultaneously show stdout to user and the debugger
150-
* Return results from vscDebugger-Functions via a pipe etc. to keep stdout clean
151144
* Pipe a copy of stdout to a pseudo-terminal as info for the user
152145

153146
If you have problems, suggestions, bug fixes etc. feel free to open an issue at

src/debugProtocolModifications.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,22 @@ export enum DebugMode {
99
Workspace = "workspace"
1010
}
1111

12+
13+
export type DataSource = "stdout"|"stderr"|"jsonSocket"|"sinkSocket";
14+
export type OutputMode = "all"|"filtered"|"nothing";
15+
16+
export interface RStartupArguments {
17+
path: string;
18+
args: string[];
19+
logLevel?: number;
20+
logLevelCP?: number;
21+
useJsonServer?: boolean;
22+
useSinkServer?: boolean;
23+
jsonPort?: number;
24+
sinkPort?: number;
25+
}
26+
27+
1228
export interface DebugConfiguration extends VsCode.DebugConfiguration {
1329
// specify what to debug (required)
1430
debugMode: DebugMode;
@@ -63,6 +79,12 @@ export interface RStrings {
6379
export interface InitializeRequestArguments extends DebugProtocol.InitializeRequestArguments {
6480
rStrings?: RStrings;
6581
threadId?: number;
82+
useJsonServer?: boolean;
83+
jsonPort?: number;
84+
jsonHost?: string;
85+
useSinkServer?: boolean;
86+
sinkPort?: number;
87+
sinkHost?: string;
6688
}
6789

6890
export interface InitializeRequest extends DebugProtocol.InitializeRequest {
@@ -86,3 +108,19 @@ export interface SourceArguments extends DebugProtocol.SourceArguments {
86108
export interface ResponseWithBody extends DebugProtocol.Response {
87109
body?: { [key: string]: any; };
88110
}
111+
112+
export interface CustomEvent extends DebugProtocol.Event {
113+
event: "custom";
114+
body: {
115+
reason: string;
116+
}
117+
}
118+
119+
export interface ContinueOnBrowserPromptEvent extends CustomEvent {
120+
body: {
121+
reason: "continueOnBrowserPrompt";
122+
value: boolean;
123+
message?: string;
124+
repeatMessage?: boolean;
125+
}
126+
}

0 commit comments

Comments
 (0)