repl: fix terminal default setting
This makes sure that the described default behavior for the `terminal` option is actually always used and not only when running the REPL as standalone program. The options code is now logically combined instead of being spread out in the big REPL constructor. PR-URL: https://github.com/nodejs/node/pull/26518 Reviewed-By: Lance Ball <lball@redhat.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
parent
96204c3c71
commit
97737fd5fb
@ -671,7 +671,7 @@ added: v0.1.32
|
|||||||
added: v0.3.0
|
added: v0.3.0
|
||||||
-->
|
-->
|
||||||
|
|
||||||
When set to `1` colors will not be used in the REPL.
|
When set, colors will not be used in the REPL.
|
||||||
|
|
||||||
### `NODE_EXTRA_CA_CERTS=file`
|
### `NODE_EXTRA_CA_CERTS=file`
|
||||||
<!-- YAML
|
<!-- YAML
|
||||||
|
@ -479,6 +479,10 @@ with REPL instances programmatically.
|
|||||||
<!-- YAML
|
<!-- YAML
|
||||||
added: v0.1.91
|
added: v0.1.91
|
||||||
changes:
|
changes:
|
||||||
|
- version: REPLACEME
|
||||||
|
pr-url: https://github.com/nodejs/node/pull/REPLACEME
|
||||||
|
description: The `terminal` option now follows the default description in
|
||||||
|
all cases and `useColors` checks `hasColors()` if available.
|
||||||
- version: v10.0.0
|
- version: v10.0.0
|
||||||
pr-url: https://github.com/nodejs/node/pull/19187
|
pr-url: https://github.com/nodejs/node/pull/19187
|
||||||
description: The `REPL_MAGIC_MODE` `replMode` was removed.
|
description: The `REPL_MAGIC_MODE` `replMode` was removed.
|
||||||
@ -495,7 +499,7 @@ changes:
|
|||||||
* `output` {stream.Writable} The `Writable` stream to which REPL output will
|
* `output` {stream.Writable} The `Writable` stream to which REPL output will
|
||||||
be written. **Default:** `process.stdout`.
|
be written. **Default:** `process.stdout`.
|
||||||
* `terminal` {boolean} If `true`, specifies that the `output` should be
|
* `terminal` {boolean} If `true`, specifies that the `output` should be
|
||||||
treated as a TTY terminal, and have ANSI/VT100 escape codes written to it.
|
treated as a TTY terminal.
|
||||||
**Default:** checking the value of the `isTTY` property on the `output`
|
**Default:** checking the value of the `isTTY` property on the `output`
|
||||||
stream upon instantiation.
|
stream upon instantiation.
|
||||||
* `eval` {Function} The function to be used when evaluating each given line
|
* `eval` {Function} The function to be used when evaluating each given line
|
||||||
@ -504,8 +508,9 @@ changes:
|
|||||||
the input was incomplete and prompt for additional lines.
|
the input was incomplete and prompt for additional lines.
|
||||||
* `useColors` {boolean} If `true`, specifies that the default `writer`
|
* `useColors` {boolean} If `true`, specifies that the default `writer`
|
||||||
function should include ANSI color styling to REPL output. If a custom
|
function should include ANSI color styling to REPL output. If a custom
|
||||||
`writer` function is provided then this has no effect. **Default:** the
|
`writer` function is provided then this has no effect. **Default:** checking
|
||||||
REPL instances `terminal` value.
|
color support on the `output` stream if the REPL instance's `terminal` value
|
||||||
|
is `true`.
|
||||||
* `useGlobal` {boolean} If `true`, specifies that the default evaluation
|
* `useGlobal` {boolean} If `true`, specifies that the default evaluation
|
||||||
function will use the JavaScript `global` as the context as opposed to
|
function will use the JavaScript `global` as the context as opposed to
|
||||||
creating a new separate context for the REPL instance. The node CLI REPL
|
creating a new separate context for the REPL instance. The node CLI REPL
|
||||||
|
@ -14,7 +14,6 @@ function createRepl(env, opts, cb) {
|
|||||||
opts = {
|
opts = {
|
||||||
[kStandaloneREPL]: true,
|
[kStandaloneREPL]: true,
|
||||||
ignoreUndefined: false,
|
ignoreUndefined: false,
|
||||||
terminal: process.stdout.isTTY,
|
|
||||||
useGlobal: true,
|
useGlobal: true,
|
||||||
breakEvalOnSigint: true,
|
breakEvalOnSigint: true,
|
||||||
...opts
|
...opts
|
||||||
@ -23,17 +22,13 @@ function createRepl(env, opts, cb) {
|
|||||||
if (parseInt(env.NODE_NO_READLINE)) {
|
if (parseInt(env.NODE_NO_READLINE)) {
|
||||||
opts.terminal = false;
|
opts.terminal = false;
|
||||||
}
|
}
|
||||||
// The "dumb" special terminal, as defined by terminfo, doesn't support
|
|
||||||
// ANSI color control codes.
|
|
||||||
// see http://invisible-island.net/ncurses/terminfo.ti.html#toc-_Specials
|
|
||||||
if (parseInt(env.NODE_DISABLE_COLORS) || env.TERM === 'dumb') {
|
|
||||||
opts.useColors = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (env.NODE_REPL_MODE) {
|
||||||
opts.replMode = {
|
opts.replMode = {
|
||||||
'strict': REPL.REPL_MODE_STRICT,
|
'strict': REPL.REPL_MODE_STRICT,
|
||||||
'sloppy': REPL.REPL_MODE_SLOPPY
|
'sloppy': REPL.REPL_MODE_SLOPPY
|
||||||
}[String(env.NODE_REPL_MODE).toLowerCase().trim()];
|
}[env.NODE_REPL_MODE.toLowerCase().trim()];
|
||||||
|
}
|
||||||
|
|
||||||
if (opts.replMode === undefined) {
|
if (opts.replMode === undefined) {
|
||||||
opts.replMode = REPL.REPL_MODE_SLOPPY;
|
opts.replMode = REPL.REPL_MODE_SLOPPY;
|
||||||
@ -47,5 +42,6 @@ function createRepl(env, opts, cb) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const repl = REPL.start(opts);
|
const repl = REPL.start(opts);
|
||||||
repl.setupHistory(opts.terminal ? env.NODE_REPL_HISTORY : '', cb);
|
const term = 'terminal' in opts ? opts.terminal : process.stdout.isTTY;
|
||||||
|
repl.setupHistory(term ? env.NODE_REPL_HISTORY : '', cb);
|
||||||
}
|
}
|
||||||
|
@ -114,6 +114,9 @@ function getColorDepth(env = process.env) {
|
|||||||
if (env.NODE_DISABLE_COLORS !== undefined ||
|
if (env.NODE_DISABLE_COLORS !== undefined ||
|
||||||
// See https://no-color.org/
|
// See https://no-color.org/
|
||||||
env.NO_COLOR !== undefined ||
|
env.NO_COLOR !== undefined ||
|
||||||
|
// The "dumb" special terminal, as defined by terminfo, doesn't support
|
||||||
|
// ANSI color control codes.
|
||||||
|
// See http://invisible-island.net/ncurses/terminfo.ti.html#toc-_Specials
|
||||||
env.TERM === 'dumb') {
|
env.TERM === 'dumb') {
|
||||||
return COLORS_2;
|
return COLORS_2;
|
||||||
}
|
}
|
||||||
|
97
lib/repl.js
97
lib/repl.js
@ -140,47 +140,70 @@ function REPLServer(prompt,
|
|||||||
replMode);
|
replMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
var options, input, output, dom, breakEvalOnSigint;
|
let options;
|
||||||
if (prompt !== null && typeof prompt === 'object') {
|
if (prompt !== null && typeof prompt === 'object') {
|
||||||
// an options object was given
|
// An options object was given.
|
||||||
options = prompt;
|
options = { ...prompt };
|
||||||
stream = options.stream || options.socket;
|
stream = options.stream || options.socket;
|
||||||
input = options.input;
|
|
||||||
output = options.output;
|
|
||||||
eval_ = options.eval;
|
eval_ = options.eval;
|
||||||
useGlobal = options.useGlobal;
|
useGlobal = options.useGlobal;
|
||||||
ignoreUndefined = options.ignoreUndefined;
|
ignoreUndefined = options.ignoreUndefined;
|
||||||
prompt = options.prompt;
|
prompt = options.prompt;
|
||||||
dom = options.domain;
|
|
||||||
replMode = options.replMode;
|
replMode = options.replMode;
|
||||||
breakEvalOnSigint = options.breakEvalOnSigint;
|
|
||||||
} else {
|
} else {
|
||||||
options = {};
|
options = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (breakEvalOnSigint && eval_) {
|
if (!options.input && !options.output) {
|
||||||
|
// Legacy API, passing a 'stream'/'socket' option.
|
||||||
|
if (!stream) {
|
||||||
|
// Use stdin and stdout as the default streams if none were given.
|
||||||
|
stream = process;
|
||||||
|
}
|
||||||
|
// We're given a duplex readable/writable Stream, like a `net.Socket`
|
||||||
|
// or a custom object with 2 streams, or the `process` object.
|
||||||
|
options.input = stream.stdin || stream;
|
||||||
|
options.output = stream.stdout || stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.terminal === undefined) {
|
||||||
|
options.terminal = options.output.isTTY;
|
||||||
|
}
|
||||||
|
options.terminal = !!options.terminal;
|
||||||
|
|
||||||
|
if (options.terminal && options.useColors === undefined) {
|
||||||
|
// If possible, check if stdout supports colors or not.
|
||||||
|
if (options.output.hasColors) {
|
||||||
|
options.useColors = options.output.hasColors();
|
||||||
|
} else if (process.env.NODE_DISABLE_COLORS === undefined) {
|
||||||
|
options.useColors = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.inputStream = options.input;
|
||||||
|
this.outputStream = options.output;
|
||||||
|
this.useColors = !!options.useColors;
|
||||||
|
this._domain = options.domain || domain.create();
|
||||||
|
this.useGlobal = !!useGlobal;
|
||||||
|
this.ignoreUndefined = !!ignoreUndefined;
|
||||||
|
this.replMode = replMode || exports.REPL_MODE_SLOPPY;
|
||||||
|
this.underscoreAssigned = false;
|
||||||
|
this.last = undefined;
|
||||||
|
this.underscoreErrAssigned = false;
|
||||||
|
this.lastError = undefined;
|
||||||
|
this.breakEvalOnSigint = !!options.breakEvalOnSigint;
|
||||||
|
this.editorMode = false;
|
||||||
|
// Context id for use with the inspector protocol.
|
||||||
|
this[kContextId] = undefined;
|
||||||
|
|
||||||
|
if (this.breakEvalOnSigint && eval_) {
|
||||||
// Allowing this would not reflect user expectations.
|
// Allowing this would not reflect user expectations.
|
||||||
// breakEvalOnSigint affects only the behavior of the default eval().
|
// breakEvalOnSigint affects only the behavior of the default eval().
|
||||||
throw new ERR_INVALID_REPL_EVAL_CONFIG();
|
throw new ERR_INVALID_REPL_EVAL_CONFIG();
|
||||||
}
|
}
|
||||||
|
|
||||||
var self = this;
|
let rli = this;
|
||||||
|
Object.defineProperty(this, 'rli', {
|
||||||
self._domain = dom || domain.create();
|
|
||||||
self.useGlobal = !!useGlobal;
|
|
||||||
self.ignoreUndefined = !!ignoreUndefined;
|
|
||||||
self.replMode = replMode || exports.REPL_MODE_SLOPPY;
|
|
||||||
self.underscoreAssigned = false;
|
|
||||||
self.last = undefined;
|
|
||||||
self.underscoreErrAssigned = false;
|
|
||||||
self.lastError = undefined;
|
|
||||||
self.breakEvalOnSigint = !!breakEvalOnSigint;
|
|
||||||
self.editorMode = false;
|
|
||||||
// Context id for use with the inspector protocol.
|
|
||||||
self[kContextId] = undefined;
|
|
||||||
|
|
||||||
let rli = self;
|
|
||||||
Object.defineProperty(self, 'rli', {
|
|
||||||
get: util.deprecate(() => rli,
|
get: util.deprecate(() => rli,
|
||||||
'REPLServer.rli is deprecated', 'DEP0124'),
|
'REPLServer.rli is deprecated', 'DEP0124'),
|
||||||
set: util.deprecate((val) => rli = val,
|
set: util.deprecate((val) => rli = val,
|
||||||
@ -197,6 +220,8 @@ function REPLServer(prompt,
|
|||||||
|
|
||||||
eval_ = eval_ || defaultEval;
|
eval_ = eval_ || defaultEval;
|
||||||
|
|
||||||
|
const self = this;
|
||||||
|
|
||||||
// Pause taking in new input, and store the keys in a buffer.
|
// Pause taking in new input, and store the keys in a buffer.
|
||||||
const pausedBuffer = [];
|
const pausedBuffer = [];
|
||||||
let paused = false;
|
let paused = false;
|
||||||
@ -452,21 +477,6 @@ function REPLServer(prompt,
|
|||||||
top.displayPrompt();
|
top.displayPrompt();
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!input && !output) {
|
|
||||||
// legacy API, passing a 'stream'/'socket' option
|
|
||||||
if (!stream) {
|
|
||||||
// Use stdin and stdout as the default streams if none were given
|
|
||||||
stream = process;
|
|
||||||
}
|
|
||||||
// We're given a duplex readable/writable Stream, like a `net.Socket`
|
|
||||||
// or a custom object with 2 streams, or the `process` object
|
|
||||||
input = stream.stdin || stream;
|
|
||||||
output = stream.stdout || stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.inputStream = input;
|
|
||||||
self.outputStream = output;
|
|
||||||
|
|
||||||
self.resetContext();
|
self.resetContext();
|
||||||
self.lines.level = [];
|
self.lines.level = [];
|
||||||
|
|
||||||
@ -503,13 +513,6 @@ function REPLServer(prompt,
|
|||||||
// Figure out which "writer" function to use
|
// Figure out which "writer" function to use
|
||||||
self.writer = options.writer || exports.writer;
|
self.writer = options.writer || exports.writer;
|
||||||
|
|
||||||
if (options.useColors === undefined) {
|
|
||||||
options.useColors = self.terminal && (
|
|
||||||
typeof self.outputStream.getColorDepth === 'function' ?
|
|
||||||
self.outputStream.getColorDepth() > 1 : true);
|
|
||||||
}
|
|
||||||
self.useColors = !!options.useColors;
|
|
||||||
|
|
||||||
if (self.writer === writer) {
|
if (self.writer === writer) {
|
||||||
// Conditionally turn on ANSI coloring.
|
// Conditionally turn on ANSI coloring.
|
||||||
writer.options.colors = self.useColors;
|
writer.options.colors = self.useColors;
|
||||||
|
@ -19,6 +19,8 @@ inout._write = function(s, _, cb) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const repl = new REPLServer({ input: inout, output: inout, useColors: true });
|
const repl = new REPLServer({ input: inout, output: inout, useColors: true });
|
||||||
|
inout.isTTY = true;
|
||||||
|
const repl2 = new REPLServer({ input: inout, output: inout });
|
||||||
|
|
||||||
process.on('exit', function() {
|
process.on('exit', function() {
|
||||||
// https://github.com/nodejs/node/pull/16485#issuecomment-350428638
|
// https://github.com/nodejs/node/pull/16485#issuecomment-350428638
|
||||||
@ -28,4 +30,5 @@ process.on('exit', function() {
|
|||||||
strictEqual(output.includes(`'\u001b[32m\\'string\\'\u001b[39m'`), false);
|
strictEqual(output.includes(`'\u001b[32m\\'string\\'\u001b[39m'`), false);
|
||||||
strictEqual(inspect.defaultOptions.colors, false);
|
strictEqual(inspect.defaultOptions.colors, false);
|
||||||
strictEqual(repl.writer.options.colors, true);
|
strictEqual(repl.writer.options.colors, true);
|
||||||
|
strictEqual(repl2.writer.options.colors, true);
|
||||||
});
|
});
|
||||||
|
@ -38,19 +38,25 @@ const tests = [
|
|||||||
function run(test) {
|
function run(test) {
|
||||||
const env = test.env;
|
const env = test.env;
|
||||||
const expected = test.expected;
|
const expected = test.expected;
|
||||||
|
|
||||||
const opts = {
|
const opts = {
|
||||||
terminal: true,
|
terminal: true,
|
||||||
input: new stream.Readable({ read() {} }),
|
input: new stream.Readable({ read() {} }),
|
||||||
output: new stream.Writable({ write() {} })
|
output: new stream.Writable({ write() {} })
|
||||||
};
|
};
|
||||||
|
|
||||||
REPL.createInternalRepl(env, opts, function(err, repl) {
|
Object.assign(process.env, env);
|
||||||
|
|
||||||
|
REPL.createInternalRepl(process.env, opts, function(err, repl) {
|
||||||
assert.ifError(err);
|
assert.ifError(err);
|
||||||
|
|
||||||
assert.strictEqual(repl.terminal, expected.terminal,
|
assert.strictEqual(repl.terminal, expected.terminal,
|
||||||
`Expected ${inspect(expected)} with ${inspect(env)}`);
|
`Expected ${inspect(expected)} with ${inspect(env)}`);
|
||||||
assert.strictEqual(repl.useColors, expected.useColors,
|
assert.strictEqual(repl.useColors, expected.useColors,
|
||||||
`Expected ${inspect(expected)} with ${inspect(env)}`);
|
`Expected ${inspect(expected)} with ${inspect(env)}`);
|
||||||
|
for (const key of Object.keys(env)) {
|
||||||
|
delete process.env[key];
|
||||||
|
}
|
||||||
repl.close();
|
repl.close();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user