summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnna Henningsen <anna@addaleax.net>2018-03-15 14:09:17 +0100
committerAnna Henningsen <anna@addaleax.net>2018-04-12 23:23:56 +0200
commit57e8793c4393aa3fafd87f289b19078b1918c166 (patch)
treea1076b73991a97ed829cf0da0e5747d611ccec78
parentce58df58d0360779d16d60ce3bb0e9979ec5fdf4 (diff)
downloadandroid-node-v8-57e8793c4393aa3fafd87f289b19078b1918c166.tar.gz
android-node-v8-57e8793c4393aa3fafd87f289b19078b1918c166.tar.bz2
android-node-v8-57e8793c4393aa3fafd87f289b19078b1918c166.zip
console: add color support
Add a way to tell `Console` instances to either always use, never use or auto-detect color support and inspect objects accordingly. PR-URL: https://github.com/nodejs/node/pull/19372 Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
-rw-r--r--doc/api/console.md8
-rw-r--r--doc/api/util.md4
-rw-r--r--lib/console.js63
-rw-r--r--test/parallel/test-console-tty-colors.js46
-rw-r--r--test/parallel/test-console.js2
5 files changed, 106 insertions, 17 deletions
diff --git a/doc/api/console.md b/doc/api/console.md
index 99c31df242..cce2a4eb6e 100644
--- a/doc/api/console.md
+++ b/doc/api/console.md
@@ -87,7 +87,8 @@ changes:
description: The `ignoreErrors` option was introduced.
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/19372
- description: The `Console` constructor now supports an `options` argument.
+ description: The `Console` constructor now supports an `options` argument,
+ and the `colorMode` option was introduced.
-->
* `options` {Object}
@@ -95,6 +96,11 @@ changes:
* `stderr` {stream.Writable}
* `ignoreErrors` {boolean} Ignore errors when writing to the underlying
streams. **Default:** `true`.
+ * `colorMode` {boolean|string} Set color support for this `Console` instance.
+ Setting to `true` enables coloring while inspecting values, setting to
+ `'auto'` will make color support depend on the value of the `isTTY` property
+ and the value returned by `getColorDepth()` on the respective stream.
+ **Default:** `false`
Creates a new `Console` with one or two writable stream instances. `stdout` is a
writable stream to print log or info output. `stderr` is used for warning or
diff --git a/doc/api/util.md b/doc/api/util.md
index 23a1774a1f..e8f97397d3 100644
--- a/doc/api/util.md
+++ b/doc/api/util.md
@@ -268,8 +268,8 @@ an `inspectOptions` argument which specifies options that are passed along to
```js
util.formatWithOptions({ colors: true }, 'See object %O', { foo: 42 });
- // Returns 'See object { foo: 42 }', where `42` is colored as a number
- // when printed to a terminal.
+// Returns 'See object { foo: 42 }', where `42` is colored as a number
+// when printed to a terminal.
```
## util.getSystemErrorName(err)
diff --git a/lib/console.js b/lib/console.js
index 9557b27fbc..2c35e98223 100644
--- a/lib/console.js
+++ b/lib/console.js
@@ -26,6 +26,7 @@ const {
codes: {
ERR_CONSOLE_WRITABLE_STREAM,
ERR_INVALID_ARG_TYPE,
+ ERR_INVALID_ARG_VALUE,
},
} = require('internal/errors');
const { previewMapIterator, previewSetIterator } = require('internal/v8');
@@ -49,24 +50,32 @@ const {
} = Array;
// Track amount of indentation required via `console.group()`.
-const kGroupIndent = Symbol('groupIndent');
+const kGroupIndent = Symbol('kGroupIndent');
+
+const kFormatForStderr = Symbol('kFormatForStderr');
+const kFormatForStdout = Symbol('kFormatForStdout');
+const kGetInspectOptions = Symbol('kGetInspectOptions');
+const kColorMode = Symbol('kColorMode');
function Console(options /* or: stdout, stderr, ignoreErrors = true */) {
if (!(this instanceof Console)) {
return new Console(...arguments);
}
- let stdout, stderr, ignoreErrors;
+ let stdout, stderr, ignoreErrors, colorMode;
if (options && typeof options.write !== 'function') {
({
stdout,
stderr = stdout,
- ignoreErrors = true
+ ignoreErrors = true,
+ colorMode = false
} = options);
} else {
- stdout = options;
- stderr = arguments[1];
- ignoreErrors = arguments[2] === undefined ? true : arguments[2];
+ return new Console({
+ stdout: options,
+ stderr: arguments[1],
+ ignoreErrors: arguments[2]
+ });
}
if (!stdout || typeof stdout.write !== 'function') {
@@ -94,7 +103,11 @@ function Console(options /* or: stdout, stderr, ignoreErrors = true */) {
prop.value = createWriteErrorHandler(stderr);
Object.defineProperty(this, '_stderrErrorHandler', prop);
+ if (typeof colorMode !== 'boolean' && colorMode !== 'auto')
+ throw new ERR_INVALID_ARG_VALUE('colorMode', colorMode);
+
this[kCounts] = new Map();
+ this[kColorMode] = colorMode;
Object.defineProperty(this, kGroupIndent, { writable: true });
this[kGroupIndent] = '';
@@ -156,13 +169,33 @@ function write(ignoreErrors, stream, string, errorhandler, groupIndent) {
}
}
+const kColorInspectOptions = { colors: true };
+const kNoColorInspectOptions = {};
+Console.prototype[kGetInspectOptions] = function(stream) {
+ let color = this[kColorMode];
+ if (color === 'auto') {
+ color = stream.isTTY && (
+ typeof stream.getColorDepth === 'function' ?
+ stream.getColorDepth() > 2 : true);
+ }
+
+ return color ? kColorInspectOptions : kNoColorInspectOptions;
+};
+
+Console.prototype[kFormatForStdout] = function(args) {
+ const opts = this[kGetInspectOptions](this._stdout);
+ return util.formatWithOptions(opts, ...args);
+};
+
+Console.prototype[kFormatForStderr] = function(args) {
+ const opts = this[kGetInspectOptions](this._stderr);
+ return util.formatWithOptions(opts, ...args);
+};
+
Console.prototype.log = function log(...args) {
write(this._ignoreErrors,
this._stdout,
- // The performance of .apply and the spread operator seems on par in V8
- // 6.3 but the spread operator, unlike .apply(), pushes the elements
- // onto the stack. That is, it makes stack overflows more likely.
- util.format.apply(null, args),
+ this[kFormatForStdout](args),
this._stdoutErrorHandler,
this[kGroupIndent]);
};
@@ -173,14 +206,16 @@ Console.prototype.dirxml = Console.prototype.log;
Console.prototype.warn = function warn(...args) {
write(this._ignoreErrors,
this._stderr,
- util.format.apply(null, args),
+ this[kFormatForStderr](args),
this._stderrErrorHandler,
this[kGroupIndent]);
};
Console.prototype.error = Console.prototype.warn;
Console.prototype.dir = function dir(object, options) {
- options = Object.assign({ customInspect: false }, options);
+ options = Object.assign({
+ customInspect: false
+ }, this[kGetInspectOptions](this._stdout), options);
write(this._ignoreErrors,
this._stdout,
util.inspect(object, options),
@@ -211,7 +246,7 @@ Console.prototype.timeEnd = function timeEnd(label = 'default') {
Console.prototype.trace = function trace(...args) {
const err = {
name: 'Trace',
- message: util.format.apply(null, args)
+ message: this[kFormatForStderr](args)
};
Error.captureStackTrace(err, trace);
this.error(err.stack);
@@ -220,7 +255,7 @@ Console.prototype.trace = function trace(...args) {
Console.prototype.assert = function assert(expression, ...args) {
if (!expression) {
args[0] = `Assertion failed${args.length === 0 ? '' : `: ${args[0]}`}`;
- this.warn(util.format.apply(null, args));
+ this.warn(this[kFormatForStderr](args));
}
};
diff --git a/test/parallel/test-console-tty-colors.js b/test/parallel/test-console-tty-colors.js
new file mode 100644
index 0000000000..945c21f28a
--- /dev/null
+++ b/test/parallel/test-console-tty-colors.js
@@ -0,0 +1,46 @@
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const util = require('util');
+const { Writable } = require('stream');
+const { Console } = require('console');
+
+function check(isTTY, colorMode, expectedColorMode) {
+ const items = [
+ 1,
+ { a: 2 },
+ [ 'foo' ],
+ { '\\a': '\\bar' }
+ ];
+
+ let i = 0;
+ const stream = new Writable({
+ write: common.mustCall((chunk, enc, cb) => {
+ assert.strictEqual(chunk.trim(),
+ util.inspect(items[i++], {
+ colors: expectedColorMode
+ }));
+ cb();
+ }, items.length),
+ decodeStrings: false
+ });
+ stream.isTTY = isTTY;
+
+ // Set ignoreErrors to `false` here so that we see assertion failures
+ // from the `write()` call happen.
+ const testConsole = new Console({
+ stdout: stream,
+ ignoreErrors: false,
+ colorMode
+ });
+ for (const item of items) {
+ testConsole.log(item);
+ }
+}
+
+check(true, 'auto', true);
+check(false, 'auto', false);
+check(true, true, true);
+check(false, true, true);
+check(true, false, false);
+check(false, false, false);
diff --git a/test/parallel/test-console.js b/test/parallel/test-console.js
index 4bde18d888..4bac35c65d 100644
--- a/test/parallel/test-console.js
+++ b/test/parallel/test-console.js
@@ -51,9 +51,11 @@ const custom_inspect = { foo: 'bar', inspect: () => 'inspect' };
const strings = [];
const errStrings = [];
+process.stdout.isTTY = false;
common.hijackStdout(function(data) {
strings.push(data);
});
+process.stderr.isTTY = false;
common.hijackStderr(function(data) {
errStrings.push(data);
});