Skip to content

Commit 5e993b7

Browse files
committed
Basic support for user input using readline
1 parent 680d68c commit 5e993b7

File tree

9 files changed

+78
-7
lines changed

9 files changed

+78
-7
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## 2.0.3 (10 Sept 2021)
44
* Update samples to use `isomorphic-fetch` instead of `node-fetch` (and pre-requisite `npm` packages).
5+
* Basic support for user input in notebooks using [readline](https://nodejs.org/api/readline.html#readline_readline_createinterface_options)
56

67
## 2.0.2 (6 Sept 2021)
78
* Excellent support for [arquero](https://uwdata.github.io/arquero/) (rich HTML output)

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
* Excellent support for [arquero](https://uwdata.github.io/arquero/) (rich HTML output)
1010
* Run shell scripts within the notebook cell.
1111
* Quickly prototype and view HTML/JavaScript/CSS output
12+
* Basic support for user input using [readline](https://nodejs.org/api/readline.html#readline_readline_createinterface_options)
13+
1214

1315
Packages such [plotly](https://plotly.com/javascript/), [tfjs-vis](https://www.npmjs.com/package/@tensorflow/tfjs-vis) & [danfo.js](https://danfo.jsdata.org/) support rich visualzation only in the browser,
1416
wowever, this extension leverages the power of Notebooks to provide the same rich visualzations when targetting node.js.

package-lock.json

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

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,7 @@
370370
"shell-quote": "^1.7.2",
371371
"source-map": "^0.6.1",
372372
"tmp": "^0.2.1",
373-
"typescript": "^4.4.2",
373+
"typescript": "^4.4.3",
374374
"uuid": "^8.3.2",
375375
"ws": "^7.5.3",
376376
"xterm": "^4.13.0",

src/extension/kernel/jsKernel.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import * as WebSocket from 'ws';
1515
import { CellExecutionState } from './types';
1616
import * as path from 'path';
1717
import { ChildProcess, spawn } from 'child_process';
18-
import { createDeferred, Deferred, generateId } from '../coreUtils';
18+
import { createDeferred, Deferred, generateId, noop } from '../coreUtils';
1919
import { ServerLogger } from '../serverLogger';
2020
import { CellOutput as CellOutput } from './cellOutput';
2121
import { getNotebookCwd } from '../utils';
@@ -280,6 +280,12 @@ export class JavaScriptKernel implements IDisposable {
280280
void window.showErrorMessage('JavaScript/TypeScript Notebook Kernel was restarted');
281281
break;
282282
}
283+
case 'readlineRequest': {
284+
window.showInputBox({ ignoreFocusOut: true, prompt: message.question }).then((result) => {
285+
void this.sendMessage({ type: 'readlineResponse', answer: result, requestId: message.requestId });
286+
}, noop);
287+
break;
288+
}
283289
case 'tensorFlowVis': {
284290
if (
285291
getConfiguration().inlineTensorflowVisualizations &&

src/extension/server/codeExecution.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { noop } from '../coreUtils';
1515
import { createConsoleOutputCompletedMarker } from '../const';
1616
import { DanfoNodePlotter } from './extensions/danforPlotter';
1717
import { ArqueroFormatter } from './extensions/arqueroFormatter';
18+
import { ReadLineProxy } from './extensions/readLineProxy';
1819
// eslint-disable-next-line @typescript-eslint/no-var-requires
1920
const Module = require('module');
2021

@@ -304,6 +305,9 @@ Module._load = function (request: any, parent: any) {
304305

305306
// eslint-disable-next-line prefer-rest-params
306307
const result = originalLoad.apply(this, arguments);
308+
if (request === 'readline') {
309+
ReadLineProxy.initialize(result);
310+
}
307311
if (request === 'danfojs-node') {
308312
DanfoJsFormatter.initialize(result);
309313
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { addMessageHandler, removeMessageHandler, sendMessage } from '../comms';
2+
import { v4 as uuid } from 'uuid';
3+
import { ReadLineQuestionResponse } from '../types';
4+
5+
export class ReadLineProxy {
6+
static initialize(readLine: typeof import('readline')) {
7+
const originalCreateInterface = readLine.createInterface;
8+
readLine.createInterface = function () {
9+
const rlInterface = originalCreateInterface.apply(readLine, arguments as any);
10+
const originalQuesttion = rlInterface.question;
11+
rlInterface.question = function (query: string) {
12+
const questionArgs = Array.prototype.slice.call(arguments);
13+
const callback = questionArgs.find((item) => typeof item === 'function');
14+
if (callback) {
15+
const requestId = uuid();
16+
sendMessage({
17+
type: 'readlineRequest',
18+
question: query,
19+
requestId
20+
});
21+
function callbackHandler(message: ReadLineQuestionResponse) {
22+
if (message.requestId === requestId) {
23+
removeMessageHandler('readlineResponse', callbackHandler);
24+
callback(message.answer);
25+
}
26+
}
27+
addMessageHandler('readlineResponse', callbackHandler);
28+
}
29+
return originalQuesttion.apply(rlInterface, arguments as any);
30+
};
31+
32+
return rlInterface;
33+
};
34+
}
35+
}

src/extension/server/tsnode.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ import * as path from 'path';
44
const tsNodePath = path.join(__dirname, '..', '..', '..', 'resources', 'scripts', 'node_modules', 'ts-node');
55
export function register(context: vm.Context) {
66
vm.runInNewContext(`require('${tsNodePath.replace(/\\/g, '/')}').register()`, context, {
7-
displayErrors: true
7+
displayErrors: false
88
});
99
}

src/extension/server/types.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,13 @@ export type CodeObject = {
3838
friendlyName: string;
3939
sourceMapFilename: string;
4040
};
41-
export type RequestType = RunCellRequest | PingRequest | InitializeRequest | TensorFlowVisRequest | PlotGenerated;
41+
export type RequestType =
42+
| RunCellRequest
43+
| PingRequest
44+
| InitializeRequest
45+
| TensorFlowVisRequest
46+
| PlotGenerated
47+
| ReadLineQuestionResponse;
4248
export type RunCellRequest = BaseMessage<
4349
'cellExec',
4450
{
@@ -63,6 +69,22 @@ export type TensorFlowVisRequest = BaseMessage<
6369
| { request: 'heatmap'; requestId: string; success: boolean; error?: Error }
6470
>;
6571

72+
export type ReadLineQuestionRequest = BaseMessage<
73+
'readlineRequest',
74+
{
75+
question: string;
76+
requestId: string;
77+
}
78+
>;
79+
80+
export type ReadLineQuestionResponse = BaseMessage<
81+
'readlineResponse',
82+
{
83+
answer?: string;
84+
requestId: string;
85+
}
86+
>;
87+
6688
// Responses
6789
export type ResponseType =
6890
| RunCellResponse
@@ -72,6 +94,7 @@ export type ResponseType =
7294
| Initialized
7395
| OutputResponse
7496
| PlotGenerated
97+
| ReadLineQuestionRequest
7598
| TensorFlowVis;
7699
export type LogMessage = BaseMessage<
77100
'logMessage',

0 commit comments

Comments
 (0)