From 9abd10428a9ef3c52bdc412c116126b140df10b1 Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Sat, 19 Jan 2019 15:34:00 +0100 Subject: [PATCH 1/2] repl: add replDefaults to customize the writer 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. --- doc/api/repl.md | 31 +++++++++++++++---- lib/internal/repl.js | 2 ++ .../repl/{recoverable.js => utils.js} | 3 +- lib/repl.js | 28 ++++++++++++++--- node.gyp | 2 +- test/parallel/test-repl-inspect-defaults.js | 29 +++++++++++++++++ 6 files changed, 82 insertions(+), 13 deletions(-) rename lib/internal/repl/{recoverable.js => utils.js} (97%) create mode 100644 test/parallel/test-repl-inspect-defaults.js diff --git a/doc/api/repl.md b/doc/api/repl.md index 324b15f3852288..b89ded7c9eaab8 100644 --- a/doc/api/repl.md +++ b/doc/api/repl.md @@ -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 REPLs +`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 +REPLs [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'); diff --git a/lib/internal/repl.js b/lib/internal/repl.js index 321f4ab29eba59..d84031fc77ce6c 100644 --- a/lib/internal/repl.js +++ b/lib/internal/repl.js @@ -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; @@ -11,6 +12,7 @@ function createRepl(env, opts, cb) { opts = null; } opts = { + [kStandaloneREPL]: true, ignoreUndefined: false, terminal: process.stdout.isTTY, useGlobal: true, diff --git a/lib/internal/repl/recoverable.js b/lib/internal/repl/utils.js similarity index 97% rename from lib/internal/repl/recoverable.js rename to lib/internal/repl/utils.js index 9d4fb11fa87733..6830ebb08065e5 100644 --- a/lib/internal/repl/recoverable.js +++ b/lib/internal/repl/utils.js @@ -70,5 +70,6 @@ function isRecoverableError(e, code) { } module.exports = { - isRecoverableError + isRecoverableError, + kStandaloneREPL: Symbol('kStandaloneREPL') }; diff --git a/lib/repl.js b/lib/repl.js index c9004fdda041eb..c200e0e8ebd16a 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -72,7 +72,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: { @@ -505,10 +508,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) { diff --git a/node.gyp b/node.gyp index d0a715b91e1dbe..9e8965aea93baf 100644 --- a/node.gyp +++ b/node.gyp @@ -173,7 +173,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', diff --git a/test/parallel/test-repl-inspect-defaults.js b/test/parallel/test-repl-inspect-defaults.js new file mode 100644 index 00000000000000..a73bc792fea8ab --- /dev/null +++ b/test/parallel/test-repl-inspect-defaults.js @@ -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(); From 96a6093ca4a7b996b4457473f2dac5a9a9b4e537 Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Wed, 6 Mar 2019 20:57:30 +0100 Subject: [PATCH 2/2] fixup: address comments --- doc/api/repl.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/api/repl.md b/doc/api/repl.md index b89ded7c9eaab8..4ea2e8c9063d0a 100644 --- a/doc/api/repl.md +++ b/doc/api/repl.md @@ -257,15 +257,15 @@ 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 `showProxy` inspection option is set -to true by default and the `colors` option is set to true depending on the REPLs -`useColors` option. +to true by default and the `colors` option is set to true depending on the +REPL's `useColors` option. 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 -REPLs [inspection defaults][`util.inspect()`] from inside the REPL by using the +REPL's [inspection defaults][`util.inspect()`] from inside the REPL by using the `inspect.replDefaults` property which mirrors the `defaultOptions` from [`util.inspect()`][].