0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-02-14 17:47:35 -05:00

fix(runtime): output to stderr with colors if a tty and stdout is piped (#23813)

This also fixes a bug where Deno would output to stderr with colours
when piped and stdout was not piped.
This commit is contained in:
David Sherret 2024-05-14 17:32:09 -04:00 committed by Bartek Iwańczuk
parent 44cfb4f4b0
commit 0684ab3a2e
No known key found for this signature in database
GPG key ID: 0C6BCDDC3B3AD750
5 changed files with 61 additions and 33 deletions

View file

@ -601,7 +601,8 @@ impl CliMainWorkerFactory {
locale: deno_core::v8::icu::get_language_tag(), locale: deno_core::v8::icu::get_language_tag(),
location: shared.options.location.clone(), location: shared.options.location.clone(),
no_color: !colors::use_color(), no_color: !colors::use_color(),
is_tty: deno_terminal::is_stdout_tty(), is_stdout_tty: deno_terminal::is_stdout_tty(),
is_stderr_tty: deno_terminal::is_stderr_tty(),
unstable: shared.options.unstable, unstable: shared.options.unstable,
unstable_features, unstable_features,
user_agent: version::get_user_agent().to_string(), user_agent: version::get_user_agent().to_string(),
@ -811,7 +812,8 @@ fn create_web_worker_callback(
locale: deno_core::v8::icu::get_language_tag(), locale: deno_core::v8::icu::get_language_tag(),
location: Some(args.main_module.clone()), location: Some(args.main_module.clone()),
no_color: !colors::use_color(), no_color: !colors::use_color(),
is_tty: deno_terminal::is_stdout_tty(), is_stdout_tty: deno_terminal::is_stdout_tty(),
is_stderr_tty: deno_terminal::is_stderr_tty(),
unstable: shared.options.unstable, unstable: shared.options.unstable,
unstable_features, unstable_features,
user_agent: version::get_user_agent().to_string(), user_agent: version::get_user_agent().to_string(),

View file

@ -156,14 +156,20 @@ const {
Uint8Array, Uint8Array,
} = primordials; } = primordials;
let noColor = () => false; let noColorStdout = () => false;
let noColorStderr = () => false;
function setNoColorFn(fn) { function setNoColorFns(stdoutFn, stderrFn) {
noColor = fn; noColorStdout = stdoutFn;
noColorStderr = stderrFn;
} }
function getNoColor() { function getStdoutNoColor() {
return noColor(); return noColorStdout();
}
function getStderrNoColor() {
return noColorStderr();
} }
function assert(cond, msg = "Assertion failed.") { function assert(cond, msg = "Assertion failed.") {
@ -2927,6 +2933,7 @@ function cssToAnsi(css, prevCss = null) {
function inspectArgs(args, inspectOptions = {}) { function inspectArgs(args, inspectOptions = {}) {
const ctx = { const ctx = {
...getDefaultInspectOptions(), ...getDefaultInspectOptions(),
colors: inspectOptions.colors ?? !noColorStdout(),
...inspectOptions, ...inspectOptions,
}; };
if (inspectOptions.iterableLimit !== undefined) { if (inspectOptions.iterableLimit !== undefined) {
@ -2939,7 +2946,7 @@ function inspectArgs(args, inspectOptions = {}) {
if (ctx.maxArrayLength === null) ctx.maxArrayLength = Infinity; if (ctx.maxArrayLength === null) ctx.maxArrayLength = Infinity;
if (ctx.maxStringLength === null) ctx.maxStringLength = Infinity; if (ctx.maxStringLength === null) ctx.maxStringLength = Infinity;
const noColor = getNoColor(); const noColor = !ctx.colors;
const first = args[0]; const first = args[0];
let a = 0; let a = 0;
let string = ""; let string = "";
@ -3053,12 +3060,12 @@ const countMap = new SafeMap();
const timerMap = new SafeMap(); const timerMap = new SafeMap();
const isConsoleInstance = Symbol("isConsoleInstance"); const isConsoleInstance = Symbol("isConsoleInstance");
function getConsoleInspectOptions() { /** @param noColor {boolean} */
const color = !getNoColor(); function getConsoleInspectOptions(noColor) {
return { return {
...getDefaultInspectOptions(), ...getDefaultInspectOptions(),
colors: color, colors: !noColor,
stylize: color ? createStylizeWithColor(styles, colors) : stylizeNoColor, stylize: noColor ? stylizeNoColor : createStylizeWithColor(styles, colors),
}; };
} }
@ -3090,7 +3097,7 @@ class Console {
log = (...args) => { log = (...args) => {
this.#printFunc( this.#printFunc(
inspectArgs(args, { inspectArgs(args, {
...getConsoleInspectOptions(), ...getConsoleInspectOptions(noColorStdout()),
indentLevel: this.indentLevel, indentLevel: this.indentLevel,
}) + "\n", }) + "\n",
1, 1,
@ -3100,7 +3107,7 @@ class Console {
debug = (...args) => { debug = (...args) => {
this.#printFunc( this.#printFunc(
inspectArgs(args, { inspectArgs(args, {
...getConsoleInspectOptions(), ...getConsoleInspectOptions(noColorStdout()),
indentLevel: this.indentLevel, indentLevel: this.indentLevel,
}) + "\n", }) + "\n",
0, 0,
@ -3110,7 +3117,7 @@ class Console {
info = (...args) => { info = (...args) => {
this.#printFunc( this.#printFunc(
inspectArgs(args, { inspectArgs(args, {
...getConsoleInspectOptions(), ...getConsoleInspectOptions(noColorStdout()),
indentLevel: this.indentLevel, indentLevel: this.indentLevel,
}) + "\n", }) + "\n",
1, 1,
@ -3119,8 +3126,10 @@ class Console {
dir = (obj = undefined, options = {}) => { dir = (obj = undefined, options = {}) => {
this.#printFunc( this.#printFunc(
inspectArgs([obj], { ...getConsoleInspectOptions(), ...options }) + inspectArgs([obj], {
"\n", ...getConsoleInspectOptions(noColorStdout()),
...options,
}) + "\n",
1, 1,
); );
}; };
@ -3130,7 +3139,7 @@ class Console {
warn = (...args) => { warn = (...args) => {
this.#printFunc( this.#printFunc(
inspectArgs(args, { inspectArgs(args, {
...getConsoleInspectOptions(), ...getConsoleInspectOptions(noColorStderr()),
indentLevel: this.indentLevel, indentLevel: this.indentLevel,
}) + "\n", }) + "\n",
2, 2,
@ -3140,7 +3149,7 @@ class Console {
error = (...args) => { error = (...args) => {
this.#printFunc( this.#printFunc(
inspectArgs(args, { inspectArgs(args, {
...getConsoleInspectOptions(), ...getConsoleInspectOptions(noColorStderr()),
indentLevel: this.indentLevel, indentLevel: this.indentLevel,
}) + "\n", }) + "\n",
3, 3,
@ -3353,7 +3362,10 @@ class Console {
trace = (...args) => { trace = (...args) => {
const message = inspectArgs( const message = inspectArgs(
args, args,
{ ...getConsoleInspectOptions(), indentLevel: 0 }, {
...getConsoleInspectOptions(noColorStderr()),
indentLevel: 0,
},
); );
const err = { const err = {
name: "Trace", name: "Trace",
@ -3473,10 +3485,11 @@ export {
formatNumber, formatNumber,
formatValue, formatValue,
getDefaultInspectOptions, getDefaultInspectOptions,
getNoColor, getStderrNoColor,
getStdoutNoColor,
inspect, inspect,
inspectArgs, inspectArgs,
quoteString, quoteString,
setNoColorFn, setNoColorFns,
styles, styles,
}; };

View file

@ -8,7 +8,8 @@ import { core, internals, primordials } from "ext:core/mod.js";
const ops = core.ops; const ops = core.ops;
import { import {
op_bootstrap_args, op_bootstrap_args,
op_bootstrap_is_tty, op_bootstrap_is_stderr_tty,
op_bootstrap_is_stdout_tty,
op_bootstrap_no_color, op_bootstrap_no_color,
op_bootstrap_pid, op_bootstrap_pid,
op_main_module, op_main_module,
@ -62,10 +63,10 @@ import * as timers from "ext:deno_web/02_timers.js";
import { import {
customInspect, customInspect,
getDefaultInspectOptions, getDefaultInspectOptions,
getNoColor, getStderrNoColor,
inspectArgs, inspectArgs,
quoteString, quoteString,
setNoColorFn, setNoColorFns,
} from "ext:deno_console/01_console.js"; } from "ext:deno_console/01_console.js";
import * as performance from "ext:deno_web/15_performance.js"; import * as performance from "ext:deno_web/15_performance.js";
import * as url from "ext:deno_url/00_url.js"; import * as url from "ext:deno_url/00_url.js";
@ -379,7 +380,10 @@ function importScripts(...urls) {
const opArgs = memoizeLazy(() => op_bootstrap_args()); const opArgs = memoizeLazy(() => op_bootstrap_args());
const opPid = memoizeLazy(() => op_bootstrap_pid()); const opPid = memoizeLazy(() => op_bootstrap_pid());
setNoColorFn(() => op_bootstrap_no_color() || !op_bootstrap_is_tty()); setNoColorFns(
() => op_bootstrap_no_color() || !op_bootstrap_is_stdout_tty(),
() => op_bootstrap_no_color() || !op_bootstrap_is_stderr_tty(),
);
function formatException(error) { function formatException(error) {
if ( if (
@ -390,11 +394,11 @@ function formatException(error) {
} else if (typeof error == "string") { } else if (typeof error == "string") {
return `Uncaught ${ return `Uncaught ${
inspectArgs([quoteString(error, getDefaultInspectOptions())], { inspectArgs([quoteString(error, getDefaultInspectOptions())], {
colors: !getNoColor(), colors: !getStderrNoColor(),
}) })
}`; }`;
} else { } else {
return `Uncaught ${inspectArgs([error], { colors: !getNoColor() })}`; return `Uncaught ${inspectArgs([error], { colors: !getStderrNoColor() })}`;
} }
} }

View file

@ -16,7 +16,8 @@ deno_core::extension!(
op_bootstrap_language, op_bootstrap_language,
op_bootstrap_log_level, op_bootstrap_log_level,
op_bootstrap_no_color, op_bootstrap_no_color,
op_bootstrap_is_tty, op_bootstrap_is_stdout_tty,
op_bootstrap_is_stderr_tty,
op_bootstrap_unstable_args, op_bootstrap_unstable_args,
op_snapshot_options, op_snapshot_options,
], ],
@ -117,7 +118,13 @@ pub fn op_bootstrap_no_color(state: &mut OpState) -> bool {
} }
#[op2(fast)] #[op2(fast)]
pub fn op_bootstrap_is_tty(state: &mut OpState) -> bool { pub fn op_bootstrap_is_stdout_tty(state: &mut OpState) -> bool {
let options = state.borrow::<BootstrapOptions>(); let options = state.borrow::<BootstrapOptions>();
options.is_tty options.is_stdout_tty
}
#[op2(fast)]
pub fn op_bootstrap_is_stderr_tty(state: &mut OpState) -> bool {
let options = state.borrow::<BootstrapOptions>();
options.is_stderr_tty
} }

View file

@ -76,7 +76,8 @@ pub struct BootstrapOptions {
pub location: Option<ModuleSpecifier>, pub location: Option<ModuleSpecifier>,
/// Sets `Deno.noColor` in JS runtime. /// Sets `Deno.noColor` in JS runtime.
pub no_color: bool, pub no_color: bool,
pub is_tty: bool, pub is_stdout_tty: bool,
pub is_stderr_tty: bool,
// --unstable flag, deprecated // --unstable flag, deprecated
pub unstable: bool, pub unstable: bool,
// --unstable-* flags // --unstable-* flags
@ -109,7 +110,8 @@ impl Default for BootstrapOptions {
user_agent, user_agent,
cpu_count, cpu_count,
no_color: !colors::use_color(), no_color: !colors::use_color(),
is_tty: deno_terminal::is_stdout_tty(), is_stdout_tty: deno_terminal::is_stdout_tty(),
is_stderr_tty: deno_terminal::is_stderr_tty(),
enable_op_summary_metrics: Default::default(), enable_op_summary_metrics: Default::default(),
enable_testing_features: Default::default(), enable_testing_features: Default::default(),
log_level: Default::default(), log_level: Default::default(),