Skip to content

Commit a1d85ad

Browse files
committed
allows output tables
1 parent 0f2de64 commit a1d85ad

File tree

2 files changed

+84
-48
lines changed

2 files changed

+84
-48
lines changed

R/notebook.R

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ r$run(function() {
5454
res <- tryCatch({
5555
expr <- parse(text = expr)
5656
out <- withVisible(eval(expr, globalenv()))
57-
text <- utils::capture.output(print(out$value, view = TRUE))
5857
if (check_null_dev()) {
5958
record <- recordPlot()
6059
plot_file <- tempfile(fileext = ".svg")
@@ -79,6 +78,12 @@ r$run(function() {
7978
result = browser_url
8079
)
8180
} else if (out$visible) {
81+
if (inherits(out$value, "data.frame")) {
82+
text <- utils::capture.output(knitr::kable(out$value, format = "html"))
83+
} else {
84+
text <- utils::capture.output(print(out$value, view = TRUE))
85+
}
86+
8287
list(
8388
id = id,
8489
type = "text",

src/notebook.ts

Lines changed: 78 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ class RKernel {
6060

6161
server.listen(0, '127.0.0.1', () => {
6262
this.port = (server.address() as net.AddressInfo).port;
63+
// FIXME: grab R path from settings
6364
const childProcess = spawn('R', ['--quiet', '--slave', '-f', this.kernelScript, '--args', `port=${this.port}`],
6465
{ cwd: this.cwd, env: env });
6566
childProcess.stderr.on('data', (chunk: Buffer) => {
@@ -301,6 +302,80 @@ export class RNotebookProvider implements vscode.NotebookContentProvider, vscode
301302
await vscode.workspace.fs.writeFile(targetResource, Buffer.from(content));
302303
}
303304

305+
async renderPlotOutput(response) {
306+
const content = (await vscode.workspace.fs.readFile(vscode.Uri.parse(response.result))).toString();
307+
308+
return {
309+
outputKind: vscode.CellOutputKind.Rich,
310+
data: {
311+
'image/svg+xml': content,
312+
},
313+
};
314+
}
315+
316+
async renderTextOutput(response) {
317+
// Text may contain html, so render as such.
318+
const isXml = response.result.match(/^<.+>$/gms) != null
319+
320+
if (isXml) {
321+
return {
322+
outputKind: vscode.CellOutputKind.Rich,
323+
data: {
324+
'text/html': response.result
325+
}
326+
}
327+
} else {
328+
return {
329+
outputKind: vscode.CellOutputKind.Text,
330+
text: response.result,
331+
}
332+
}
333+
}
334+
335+
async renderOutput(cell, response) {
336+
337+
switch (response.type) {
338+
case 'text': {
339+
cell.outputs = [await this.renderTextOutput(response)];
340+
break;
341+
}
342+
case 'plot': {
343+
cell.outputs = [await this.renderPlotOutput(response)]
344+
break;
345+
}
346+
case 'viewer': {
347+
cell.outputs = [{
348+
outputKind: vscode.CellOutputKind.Rich,
349+
data: {
350+
// 'text/html': `<ifravscode-webview-resource://${response.result}`,
351+
'text/html': `<a href="vscode-webview-resource:${response.result}">Here</a>`,
352+
// <iframe src="vscode-webview-resource:${response.result}"></iframe>`,
353+
},
354+
}];
355+
break;
356+
}
357+
case 'browser': {
358+
cell.outputs = [{
359+
outputKind: vscode.CellOutputKind.Rich,
360+
data: {
361+
'text/plain': response.result,
362+
},
363+
}];
364+
break;
365+
}
366+
case 'error': {
367+
cell.metadata.runState = vscode.NotebookCellRunState.Error;
368+
cell.outputs = [{
369+
outputKind: vscode.CellOutputKind.Error,
370+
evalue: response.result,
371+
ename: 'Error',
372+
traceback: [],
373+
}];
374+
break;
375+
}
376+
}
377+
}
378+
304379
onDidChangeNotebook = new vscode.EventEmitter<vscode.NotebookDocumentEditEvent>().event;
305380

306381
async resolveNotebook(): Promise<void> { }
@@ -347,54 +422,10 @@ export class RNotebookProvider implements vscode.NotebookContentProvider, vscode
347422
const response = await notebook.eval(cell);
348423
cell.metadata.runState = vscode.NotebookCellRunState.Success;
349424
cell.metadata.lastRunDuration = +new Date() - cell.metadata.runStartTime;
425+
350426
console.log(`uri: ${cell.uri}, id: ${response.id}, type: ${response.type}, result: ${response.result}`);
351-
switch (response.type) {
352-
case 'text': {
353-
cell.outputs = [{
354-
outputKind: vscode.CellOutputKind.Text,
355-
text: response.result,
356-
}];
357-
break;
358-
}
359-
case 'plot': {
360-
const content = (await vscode.workspace.fs.readFile(vscode.Uri.parse(response.result))).toString();
361-
cell.outputs = [{
362-
outputKind: vscode.CellOutputKind.Rich,
363-
data: {
364-
'image/svg+xml': content,
365-
},
366-
}];
367-
break;
368-
}
369-
case 'viewer': {
370-
cell.outputs = [{
371-
outputKind: vscode.CellOutputKind.Rich,
372-
data: {
373-
'text/plain': response.result,
374-
},
375-
}];
376-
break;
377-
}
378-
case 'browser': {
379-
cell.outputs = [{
380-
outputKind: vscode.CellOutputKind.Rich,
381-
data: {
382-
'text/plain': response.result,
383-
},
384-
}];
385-
break;
386-
}
387-
case 'error': {
388-
cell.metadata.runState = vscode.NotebookCellRunState.Error;
389-
cell.outputs = [{
390-
outputKind: vscode.CellOutputKind.Error,
391-
evalue: response.result,
392-
ename: 'Error',
393-
traceback: [],
394-
}];
395-
break;
396-
}
397-
}
427+
428+
await this.renderOutput(cell, response)
398429
} catch (e) {
399430
cell.outputs = [{
400431
outputKind: vscode.CellOutputKind.Error,

0 commit comments

Comments
 (0)