vscode-R icon indicating copy to clipboard operation
vscode-R copied to clipboard

WIP: R Notebook

Open renkun-ken opened this issue 5 years ago • 23 comments

This is a very early, proof-of-concept demo of R Notebook using the VSCode Notebook API as suggested by #378.

The following tasks are initial steps to make the R notebook useful enough:

  • [x] Read R notebook from Rmd
  • [ ] Define R notebook format (#395)
  • [x] Language server support in notebook code cells (https://github.com/REditorSupport/vscode-r-lsp/pull/59)
  • [x] R kernel (based on socketConnection)
  • [x] Support executeCell (based on callr::r_session)
  • [x] Support executeAllCells
  • [x] Support cancelCellExecution (based on r_session$interrupt())
  • [ ] Support cancelAllCellsExecution
  • [x] Plot support (based on svglite)
  • [ ] Display htmlwidgets in cell output
  • [ ] Handle browser request
  • [ ] Handle View() request
  • [x] Display R error in cell output
  • [ ] Show R error traceback in cell error output traceback
  • [ ] Read/save full R notebook with cell outputs
  • [ ] Data frame and list viewer in cell output
  • [ ] Cross-platform check: R executable, etc.
  • [ ] Handle R kernel process crash

It seems there's ongoing API iteration recently and some adaptation is needed to fix the features already implemented.

Kapture 2020-08-29 at 0 25 35

Suggestions are welcome!

renkun-ken avatar Aug 12 '20 08:08 renkun-ken

Wow, this looks amazing!

I tried to run it in Windows but didn't have much luck so I'm posting the details.

Version without YAML header

Content of R Markdown document:

```{r}
print("hello")
```

I run command Notebook: Execute Notebook. Nothing changes in the notebook itself. Here is the output from the debug console:

R stderr (24952): Loading required namespace: jsonlite

extension.js:6336
R stdout (24952): Waiting

extension.js:6340
connected to server!
extension.js:6360
Send: {"time":1597228000521,"expr":""}

extension.js:6365
R stdout (24952): [1597228000521] 

extension.js:6340
{"type":"output","result":"NULL"}

extension.js:6374
disconnected from server
extension.js:6369
R stdout (24952): Waiting

Version with YAML header

Content of R Markdown document:

---
title: test
---

```{r}
print("hello")
```

When I do Notebook: Execute Notebook I get this output in the debug console:

R stderr (16720): Loading required namespace: jsonlite

extension.js:6336
R stdout (16720): Waiting

extension.js:6340
R stderr (16720): Error in socketConnection(host = "127.0.0.1", port = env$port, blocking = TRUE,  : 
  cannot open the connection
Calls: local ... eval.parent -> eval -> eval -> eval -> eval -> socketConnection
In addition: Warning message:

extension.js:6336
R stderr (16720): In socketConnection(host = "127.0.0.1", port = env$port, blocking = TRUE,  :
  problem in listening on this socket
Execution halted

extension.js:6336
R exited with code 1

The cell displays the message connect ECONNREFUSED 127.0.0.1:64110. Also the header shows 'title'.

header

Hope that helps, and let me know if it's because my setup is wrong or similar.

This is very exciting feature, I'm really looking forward to using it!

andycraig avatar Aug 12 '20 10:08 andycraig

The debug output for the version with the YAML header is probably because I was running it in the same session. If I run it in a fresh session, here's the debug console output I get:

R stderr (23076): Loading required namespace: jsonlite

extension.js:6336
R stdout (23076): Waiting

extension.js:6340
connected to server!
extension.js:6360
Send: {"time":1597229316281,"expr":"---\ntitle: test\n---"}

extension.js:6365
R stdout (23076): [1597229316281] ---
title: test
---

extension.js:6340
R stderr (23076): Error in parse(text = request$expr) : <text>:4:0: unexpected end of input
2: title: test
3: ---
  ^
Calls: local ... eval.parent -> eval -> eval -> eval -> eval -> parse
Execution halted

extension.js:6336
R exited with code 1

andycraig avatar Aug 12 '20 10:08 andycraig

The demo is probably too early for any meaningful test. Nothing works at the moment. 🤦

renkun-ken avatar Aug 12 '20 10:08 renkun-ken

Ah, okay! Still very exciting 😃

andycraig avatar Aug 12 '20 11:08 andycraig

Great works! It will be a connector with python users and R users.

Ikuyadeu avatar Aug 13 '20 06:08 Ikuyadeu

https://github.com/julia-vscode/julia-vscode/pull/980 has a good discussion of the API and implementation details we might also benefit from.

renkun-ken avatar Aug 26 '20 23:08 renkun-ken

@jrieken, I encounter another problem: When I delete any cell in the notebook, the language server receives a shutdown signal, and the language server is stopped. I'm wondering if it is intended behavior by sending shutdown request to language server on cell delete? Or am I missing something?

renkun-ken avatar Aug 28 '20 15:08 renkun-ken

I guess it is caused by https://github.com/REditorSupport/vscode-r-lsp/pull/59/files#diff-45327f86d4438556066de133327f4ca2R215-L183 where I want to stop the langauge server for single file outside workspace. A notebook is a collection of TextDocument. Removing a cell closes the TextDocment and then stops the language server.

renkun-ken avatar Aug 28 '20 16:08 renkun-ken

Fixed via https://github.com/REditorSupport/vscode-r-lsp/pull/59/commits/1a159d4c33c4c36231bfb7f642cef82e7cc52357.

renkun-ken avatar Aug 28 '20 16:08 renkun-ken

Yeah, whenever a cell is removed we emit a onDidCloseTextDocument-event. Your fix looks OK, tho it builds on the "internal" cell uri structure. We have also proposed TextDocument#notebook (see https://github.com/microsoft/vscode/issues/102091) which would allow you to check on the notebook of a document directly - assuming a document references a notebook. We should maybe also add NotebookDocument#isClosed which would then allow you to have document.notebook?.isClosed

jrieken avatar Aug 31 '20 07:08 jrieken

@jrieken Thanks!

renkun-ken avatar Aug 31 '20 08:08 renkun-ken

I re-implement the RKernel and notebook.R using callr::r_session to support cancelling execution of cells.

@jrieken I've got a few questions before I move on.

  1. Regarding cancelAllCellsExecution. It seems Notebook: Cancel Notebook Execution command does not call cancelAllCellsExecution. I'm not sure how I could get it called?
  2. Regarding Display htmlwidgets in cell output. An htmlwidget produced in R is an HTML file that uses a number of local js and css files with relative paths. The source code looks like:
image

which looks like the following in web browser

image

I'm wondering if it is already supported in Notebook to show such HTML content properly in cell output? I tried replacing the resource paths to something like vscode-webview-resource:// (https://github.com/microsoft/vscode/issues/106516) but it doesn't work.

renkun-ken avatar Sep 14 '20 15:09 renkun-ken

A note: R_BROWSER could be used to allow callr session to launch browser as discussed at https://github.com/r-lib/callr/issues/177.

renkun-ken avatar Dec 19 '20 00:12 renkun-ken

@renkun-ken I'm playing around a bit with your code. For starters I rebased it to master: https://github.com/markbaas/vscode-R/tree/notebook-mark, perhaps you want to merge that part already ;)

markbaas avatar Feb 03 '21 09:02 markbaas

@renkun-ken supports the view now. Did the trick with an iframe. html output is also supported. But i'm rewriting this. Any chance you can a have a look at my progress?

markbaas avatar Feb 05 '21 12:02 markbaas

Good to see you continue working on the notebook feature! I'll take a look when possible.

renkun-ken avatar Feb 05 '21 12:02 renkun-ken

@renkun-ken @jrieken

  • [x] proper implementation of table output with a custom renderer
  • [x] proper implementation of the viewer output through a custom renderer + iframe

prent prent also supports raw data prent

markbaas avatar Feb 09 '21 14:02 markbaas

julia-vscode/julia-vscode#980 has a good discussion of the API and implementation details we might also benefit from.

About saving output I see we have a few options.

  1. Like the html_notebook output saving output in a rendered html file. But this would divert from the vscode structure.
  2. Save output in a separate json file. Benefit here is that we can just put in the raw response that we get from the notebook kernel. Probably it would also be beneficial to keep an .Rdata file with the current workspace, so you can continue working where you left off.

@renkun-ken what approach would be preferred?

markbaas avatar Feb 09 '21 19:02 markbaas

Thanks for the work, @markbaas!

Save output in a separate json file. Benefit here is that we can just put in the raw response that we get from the notebook kernel. Probably it would also be beneficial to keep an .Rdata file with the current workspace, so you can continue working where you left off.

I think this makes good sense and might better fit more scenarios.

renkun-ken avatar Feb 10 '21 10:02 renkun-ken

@jrieken

why is the are the outputs and metadata properties deprecated for reading as well. I understand this is the case for writing, but for reading its a convenient way to get the metadata for the specific cell and I see no other way.

		outputs: CellOutput[];
		// readonly outputs2: NotebookCellOutput[];
		/** @deprecated use WorkspaceEdit.replaceCellMetadata */
		metadata: NotebookCellMetadata;

markbaas avatar Feb 10 '21 10:02 markbaas

@renkun-ken Added support for restoring saved cells... only that it doesn't work. I have no clue what the problem is. Perhaps a bug in the api.

markbaas avatar Feb 10 '21 20:02 markbaas

Looks awesome! Any update on this?

Tal500 avatar Jul 17 '23 17:07 Tal500

This is a great initiative. Have you thought about join forces with RStudio team to further develop their Quarto Notebook VScode extension? I think (hope) Quarto format is the future of notebooks.

GitHunter0 avatar Oct 30 '23 13:10 GitHunter0