Skip to content

Commit

Permalink
repl: add replDefaults to customize the writer
Browse files Browse the repository at this point in the history
So far it was not possible to modify the inspection defaults used by
the REPL from the running instance itself. This introduces a new
property on `util.inspect` which is only used inside the REPL and which
allows to modify the used inspection defaults at any point of time.

PR-URL: #26375
Reviewed-By: James M Snell <jasnell@gmail.com>
  • Loading branch information
BridgeAR committed Mar 14, 2019
1 parent 203fa63 commit a0b1191
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 13 deletions.
31 changes: 25 additions & 6 deletions doc/api/repl.md
Original file line number Diff line number Diff line change
Expand Up @@ -256,13 +256,32 @@ function isRecoverableError(error) {

By default, [`repl.REPLServer`][] instances format output using the
[`util.inspect()`][] method before writing the output to the provided `Writable`
stream (`process.stdout` by default). The `useColors` boolean option can be
specified at construction to instruct the default writer to use ANSI style
codes to colorize the output from the `util.inspect()` method.
stream (`process.stdout` by default). The `showProxy` inspection option is set
to true by default and the `colors` option is set to true depending on the
REPL's `useColors` option.

It is possible to fully customize the output of a [`repl.REPLServer`][] instance
by passing a new function in using the `writer` option on construction. The
following example, for instance, simply converts any input text to upper case:
The `useColors` boolean option can be specified at construction to instruct the
default writer to use ANSI style codes to colorize the output from the
`util.inspect()` method.

If the REPL is run as standalone program, it is also possible to change the
REPL's [inspection defaults][`util.inspect()`] from inside the REPL by using the
`inspect.replDefaults` property which mirrors the `defaultOptions` from
[`util.inspect()`][].

```console
> util.inspect.replDefaults.compact = false;
false
> [1]
[
1
]
>
```

To fully customize the output of a [`repl.REPLServer`][] instance pass in a new
function for the `writer` option on construction. The following example, for
instance, simply converts any input text to upper case:

```js
const repl = require('repl');
Expand Down
2 changes: 2 additions & 0 deletions lib/internal/repl.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict';

const REPL = require('repl');
const { kStandaloneREPL } = require('internal/repl/utils');

module.exports = Object.create(REPL);
module.exports.createInternalRepl = createRepl;
Expand All @@ -11,6 +12,7 @@ function createRepl(env, opts, cb) {
opts = null;
}
opts = {
[kStandaloneREPL]: true,
ignoreUndefined: false,
terminal: process.stdout.isTTY,
useGlobal: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,5 +70,6 @@ function isRecoverableError(e, code) {
}

module.exports = {
isRecoverableError
isRecoverableError,
kStandaloneREPL: Symbol('kStandaloneREPL')
};
28 changes: 23 additions & 5 deletions lib/repl.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,10 @@ const { sendInspectorCommand } = require('internal/util/inspector');
const experimentalREPLAwait = require('internal/options').getOptionValue(
'--experimental-repl-await'
);
const { isRecoverableError } = require('internal/repl/recoverable');
const {
isRecoverableError,
kStandaloneREPL
} = require('internal/repl/utils');
const {
getOwnNonIndexProperties,
propertyFilter: {
Expand Down Expand Up @@ -499,10 +502,25 @@ function REPLServer(prompt,
}
self.useColors = !!options.useColors;

if (self.useColors && self.writer === writer) {
// Turn on ANSI coloring.
self.writer = (obj) => util.inspect(obj, self.writer.options);
self.writer.options = { ...writer.options, colors: true };
if (self.writer === writer) {
// Conditionally turn on ANSI coloring.
writer.options.colors = self.useColors;

if (options[kStandaloneREPL]) {
Object.defineProperty(util.inspect, 'replDefaults', {
get() {
return writer.options;
},
set(options) {
if (options === null || typeof options !== 'object') {
throw new ERR_INVALID_ARG_TYPE('options', 'Object', options);
}
return Object.assign(writer.options, options);
},
enumerable: true,
configurable: true
});
}
}

function filterInternalStackFrames(structuredStack) {
Expand Down
2 changes: 1 addition & 1 deletion node.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@
'lib/internal/repl.js',
'lib/internal/repl/await.js',
'lib/internal/repl/history.js',
'lib/internal/repl/recoverable.js',
'lib/internal/repl/utils.js',
'lib/internal/socket_list.js',
'lib/internal/test/binding.js',
'lib/internal/test/heap.js',
Expand Down
29 changes: 29 additions & 0 deletions test/parallel/test-repl-inspect-defaults.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const cp = require('child_process');
const child = cp.spawn(process.execPath, ['-i']);
let output = '';

child.stdout.setEncoding('utf8');
child.stdout.on('data', (data) => {
output += data;
});

child.on('exit', common.mustCall(() => {
const results = output.replace(/^> /mg, '').split('\n');
assert.deepStrictEqual(
results,
[
'[ 42, 23 ]',
'1',
'[ 42, ... 1 more item ]',
''
]
);
}));

child.stdin.write('[ 42, 23 ]\n');
child.stdin.write('util.inspect.replDefaults.maxArrayLength = 1\n');
child.stdin.write('[ 42, 23 ]\n');
child.stdin.end();

0 comments on commit a0b1191

Please sign in to comment.