Skip to content

Commit b3908e4

Browse files
committed
repl: moving the logic to internal modules
1 parent 5710523 commit b3908e4

File tree

3 files changed

+112
-100
lines changed

3 files changed

+112
-100
lines changed

lib/internal/readline/utils.js

Lines changed: 1 addition & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -439,44 +439,11 @@ function* emitKeys(stream) {
439439
}
440440
}
441441

442-
function appendPreview(result, cursorTo, clearScreenDown) {
443-
this.previewResult = `\u001b[90m // ${result}\u001b[39m`;
444-
const line = `${this._prompt}${this.line} //${result}`;
445-
const columns = this.output.columns;
446-
const hasColors = this.output.hasColors ? this.output.hasColors() : false;
447-
const s = hasColors ?
448-
`${this._prompt}${this.line}${this.previewResult}` : line;
449-
450-
// Cursor to left edge.
451-
cursorTo(this.output, 0);
452-
clearScreenDown(this.output);
453-
454-
if (columns !== undefined) {
455-
this.output.write(line.length < columns ?
456-
s : `${s.slice(0, columns - 3)
457-
.replace(/\r?\n|\r/g, '')}...\u001b[39m`);
458-
} else {
459-
this.output.write(s);
460-
}
461-
462-
// Move back the cursor to the original position
463-
cursorTo(this.output, this.cursor + this._prompt.length);
464-
}
465-
466-
function clearPreview() {
467-
if (this.previewResult !== '') {
468-
this._refreshLine();
469-
this.previewResult = '';
470-
}
471-
}
472-
473442
module.exports = {
474443
emitKeys,
475444
getStringWidth,
476445
isFullWidthCodePoint,
477446
kUTF16SurrogateThreshold,
478447
stripVTControlCharacters,
479-
CSI,
480-
appendPreview,
481-
clearPreview
448+
CSI
482449
};

lib/internal/repl/utils.js

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ const numericSeparator =
1010
const staticClassFeatures =
1111
require('internal/deps/acorn-plugins/acorn-static-class-features/index');
1212
const { tokTypes: tt, Parser: AcornParser } = acorn;
13+
const util = require('util');
14+
const debug = require('internal/util/debuglog').debuglog('repl');
1315

1416
// If the error is that we've unexpectedly ended the input,
1517
// then let the user try to recover by adding more input.
@@ -87,7 +89,98 @@ function isRecoverableError(e, code) {
8789
}
8890
}
8991

92+
// Appends the preview of the result
93+
// to the tty.
94+
function appendPreview(repl, result, cursorTo, clearScreenDown) {
95+
repl.previewResult = `\u001b[90m // ${result}\u001b[39m`;
96+
const line = `${repl._prompt}${repl.line} //${result}`;
97+
const columns = repl.output.columns;
98+
const hasColors = repl.output.hasColors ? repl.output.hasColors() : false;
99+
const s = hasColors ?
100+
`${repl._prompt}${repl.line}${repl.previewResult}` : line;
101+
102+
// Cursor to left edge.
103+
cursorTo(repl.output, 0);
104+
clearScreenDown(repl.output);
105+
106+
if (columns !== undefined) {
107+
repl.output.write(line.length < columns ?
108+
s : `${s.slice(0, columns - 3)
109+
.replace(/\r?\n|\r/g, '')}...\u001b[39m`);
110+
} else {
111+
repl.output.write(s);
112+
}
113+
114+
// Move back the cursor to the original position
115+
cursorTo(repl.output, repl.cursor + repl._prompt.length);
116+
}
117+
118+
function clearPreview(repl) {
119+
if (repl.previewResult !== '') {
120+
repl._refreshLine();
121+
repl.previewResult = '';
122+
}
123+
}
124+
125+
// Called whenever a line changes
126+
// in repl and the eager eval will be
127+
// executed against the line using v8 session
128+
let readline;
129+
function makePreview(repl, eagerSession, eagerEvalContextId, line) {
130+
const lazyReadline = () => {
131+
if (!readline) readline = require('readline');
132+
return readline;
133+
};
134+
135+
const { cursorTo, clearScreenDown } = lazyReadline();
136+
137+
clearPreview(repl);
138+
139+
eagerSession.post('Runtime.evaluate', {
140+
expression: line.toString(),
141+
generatePreview: true,
142+
throwOnSideEffect: true,
143+
timeout: 500,
144+
executionContextId: eagerEvalContextId
145+
}, (error, previewResult) => {
146+
147+
if (error) {
148+
debug(`Error while generating preview ${error}`);
149+
return;
150+
}
151+
152+
if (undefined !== previewResult.result.value) {
153+
const value = util.inspect(previewResult.result.value);
154+
appendPreview(repl, value, cursorTo, clearScreenDown);
155+
return;
156+
}
157+
158+
159+
// If there is no exception and we got
160+
// objectId in the result, stringify it
161+
// using inspect via Runtime.callFunctionOn
162+
if (!previewResult.exceptionDetails && previewResult.result.objectId) {
163+
eagerSession.post('Runtime.callFunctionOn', {
164+
functionDeclaration:
165+
'function(arg) { return util.inspect(arg) }',
166+
arguments: [previewResult.result],
167+
executionContextId: eagerEvalContextId,
168+
returnByValue: true,
169+
}, (err, result) => {
170+
if (!err) {
171+
appendPreview(repl, result.result.value,
172+
cursorTo, clearScreenDown);
173+
} else {
174+
debug('eager eval error', err);
175+
}
176+
});
177+
}
178+
});
179+
}
180+
181+
90182
module.exports = {
91183
isRecoverableError,
92-
kStandaloneREPL: Symbol('kStandaloneREPL')
184+
kStandaloneREPL: Symbol('kStandaloneREPL'),
185+
makePreview
93186
};

lib/repl.js

Lines changed: 17 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ const Stream = require('stream');
7474
const vm = require('vm');
7575
const path = require('path');
7676
const fs = require('fs');
77-
const { Interface, cursorTo, clearScreenDown } = require('readline');
77+
const { Interface } = require('readline');
7878
const { Console } = require('console');
7979
const CJSModule = require('internal/modules/cjs/loader').Module;
8080
const domain = require('domain');
@@ -90,13 +90,13 @@ const {
9090
overrideStackTrace,
9191
} = require('internal/errors');
9292
const { sendInspectorCommand } = require('internal/util/inspector');
93-
const { appendPreview, clearPreview } = require('internal/readline/utils');
9493
const experimentalREPLAwait = require('internal/options').getOptionValue(
9594
'--experimental-repl-await'
9695
);
9796
const {
9897
isRecoverableError,
99-
kStandaloneREPL
98+
kStandaloneREPL,
99+
makePreview
100100
} = require('internal/repl/utils');
101101
const {
102102
getOwnNonIndexProperties,
@@ -113,8 +113,6 @@ const {
113113
const history = require('internal/repl/history');
114114
const { setImmediate } = require('timers');
115115
const inspector = require('inspector');
116-
const kPreviewResults = Symbol('preview-result-fn');
117-
const util = require('util');
118116

119117
// Lazy-loaded.
120118
let processTopLevelAwait;
@@ -227,6 +225,20 @@ function REPLServer(prompt,
227225
throw new ERR_INVALID_REPL_EVAL_CONFIG();
228226
}
229227

228+
const eagerSession = new inspector.Session();
229+
eagerSession.connect();
230+
eagerSession.once('Runtime.executionContextCreated',
231+
({ params: { context } }) => {
232+
this.on('buffer', (line) => {
233+
// No need of preview for a multiline statement.
234+
if (this[kBufferedCommandSymbol] !== '')
235+
return;
236+
makePreview(self, eagerSession, context.id, line);
237+
});
238+
eagerSession.post('Runtime.disable');
239+
});
240+
eagerSession.post('Runtime.enable');
241+
230242
// Add this listener only once and use a WeakSet that contains the REPLs
231243
// domains. Otherwise we'd have to add a single listener to each REPL instance
232244
// and that could trigger the `MaxListenersExceededWarning`.
@@ -269,66 +281,6 @@ function REPLServer(prompt,
269281

270282
const self = this;
271283

272-
self[kPreviewResults] = (eagerSession, eagerEvalContextId) => {
273-
this.on('buffer', (line) => {
274-
clearPreview.call(this);
275-
276-
// No need of preview for a multiline statement
277-
if (this[kBufferedCommandSymbol] !== '')
278-
return;
279-
280-
eagerSession.post('Runtime.evaluate', {
281-
expression: line.toString(),
282-
generatePreview: true,
283-
throwOnSideEffect: true,
284-
timeout: 500,
285-
executionContextId: eagerEvalContextId
286-
}, (error, previewResult) => {
287-
288-
if (error) {
289-
debug(`Error while generating preview ${error}`);
290-
return;
291-
}
292-
293-
if (undefined !== previewResult.result.value) {
294-
const value = util.inspect(previewResult.result.value);
295-
appendPreview.call(this, value, cursorTo, clearScreenDown);
296-
return;
297-
}
298-
299-
300-
// If no exception and we have objectId
301-
// Run the expression via callFunctionOn
302-
// And return it from util inspect.
303-
if (!previewResult.exceptionDetails && previewResult.result.objectId) {
304-
eagerSession.post('Runtime.callFunctionOn', {
305-
functionDeclaration:
306-
'function(arg) { return util.inspect(arg) }',
307-
arguments: [previewResult.result],
308-
executionContextId: eagerEvalContextId,
309-
returnByValue: true,
310-
}, (err, result) => {
311-
if (!err) {
312-
appendPreview.call(this, result.result.value,
313-
cursorTo, clearScreenDown);
314-
}
315-
});
316-
}
317-
});
318-
});
319-
};
320-
321-
322-
// Set up session for eager evaluation
323-
const eagerSession = new inspector.Session();
324-
eagerSession.connect();
325-
// eslint-disable-next-line
326-
eagerSession.once('Runtime.executionContextCreated', ({ params: { context } }) => {
327-
self[kPreviewResults](eagerSession, context.id);
328-
eagerSession.post('Runtime.disable');
329-
});
330-
eagerSession.post('Runtime.enable');
331-
332284
// Pause taking in new input, and store the keys in a buffer.
333285
const pausedBuffer = [];
334286
let paused = false;

0 commit comments

Comments
 (0)