1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-25 08:39:09 -05:00

fix(node): support tty.hasColors() and tty.getColorDepth() (#24619)

This PR adds support for
[`tty.WriteStream.prototype.hasColors()`](https://nodejs.org/api/tty.html#writestreamhascolorscount-env)
and
[`tty.WriteStream.prototype.getColorDepth()`](https://nodejs.org/api/tty.html#writestreamgetcolordepthenv).

I couldn't find any usage on GitHub which passes parameters to it.
Therefore I've skipped adding support for the `env` parameter to keep
our snapshot size small.

Based on https://github.com/denoland/deno_terminal/pull/3

Fixes https://github.com/denoland/deno/issues/24616
This commit is contained in:
Marvin Hagemeister 2024-07-19 12:39:05 +02:00 committed by Bartek Iwańczuk
parent 600b32fdc1
commit a2ca399227
No known key found for this signature in database
GPG key ID: 0C6BCDDC3B3AD750
7 changed files with 70 additions and 7 deletions

22
Cargo.lock generated
View file

@ -729,7 +729,7 @@ dependencies = [
"deno_core", "deno_core",
"deno_fetch", "deno_fetch",
"deno_lockfile", "deno_lockfile",
"deno_terminal", "deno_terminal 0.2.0",
"deno_tls", "deno_tls",
"fastwebsockets", "fastwebsockets",
"file_test_runner", "file_test_runner",
@ -1134,7 +1134,7 @@ dependencies = [
"deno_runtime", "deno_runtime",
"deno_semver", "deno_semver",
"deno_task_shell", "deno_task_shell",
"deno_terminal", "deno_terminal 0.2.0",
"dissimilar", "dissimilar",
"dotenvy", "dotenvy",
"dprint-plugin-json", "dprint-plugin-json",
@ -1216,7 +1216,7 @@ dependencies = [
"anyhow", "anyhow",
"base64 0.21.7", "base64 0.21.7",
"deno_media_type", "deno_media_type",
"deno_terminal", "deno_terminal 0.1.1",
"dprint-swc-ext", "dprint-swc-ext",
"once_cell", "once_cell",
"percent-encoding", "percent-encoding",
@ -1836,7 +1836,7 @@ name = "deno_permissions"
version = "0.21.0" version = "0.21.0"
dependencies = [ dependencies = [
"deno_core", "deno_core",
"deno_terminal", "deno_terminal 0.2.0",
"fqdn", "fqdn",
"libc", "libc",
"log", "log",
@ -1868,7 +1868,7 @@ dependencies = [
"deno_net", "deno_net",
"deno_node", "deno_node",
"deno_permissions", "deno_permissions",
"deno_terminal", "deno_terminal 0.2.0",
"deno_tls", "deno_tls",
"deno_url", "deno_url",
"deno_web", "deno_web",
@ -1948,6 +1948,16 @@ dependencies = [
"termcolor", "termcolor",
] ]
[[package]]
name = "deno_terminal"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "daef12499e89ee99e51ad6000a91f600d3937fb028ad4918af76810c5bc9e0d5"
dependencies = [
"once_cell",
"termcolor",
]
[[package]] [[package]]
name = "deno_tls" name = "deno_tls"
version = "0.148.0" version = "0.148.0"
@ -2734,7 +2744,7 @@ checksum = "05b23dcc1b671771c6f59fdace6da685735c925f859733e8fd07fba6cae6462a"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"crossbeam-channel", "crossbeam-channel",
"deno_terminal", "deno_terminal 0.1.1",
"parking_lot 0.12.3", "parking_lot 0.12.3",
"regex", "regex",
"thiserror", "thiserror",

View file

@ -51,7 +51,7 @@ deno_lockfile = "0.20.0"
deno_media_type = { version = "0.1.4", features = ["module_specifier"] } deno_media_type = { version = "0.1.4", features = ["module_specifier"] }
deno_permissions = { version = "0.21.0", path = "./runtime/permissions" } deno_permissions = { version = "0.21.0", path = "./runtime/permissions" }
deno_runtime = { version = "0.169.0", path = "./runtime" } deno_runtime = { version = "0.169.0", path = "./runtime" }
deno_terminal = "0.1.1" deno_terminal = "0.2.0"
napi_sym = { version = "0.91.0", path = "./cli/napi/sym" } napi_sym = { version = "0.91.0", path = "./cli/napi/sym" }
test_util = { package = "test_server", path = "./tests/util/server" } test_util = { package = "test_server", path = "./tests/util/server" }

View file

@ -571,6 +571,7 @@ impl CliMainWorkerFactory {
no_color: !colors::use_color(), no_color: !colors::use_color(),
is_stdout_tty: deno_terminal::is_stdout_tty(), is_stdout_tty: deno_terminal::is_stdout_tty(),
is_stderr_tty: deno_terminal::is_stderr_tty(), is_stderr_tty: deno_terminal::is_stderr_tty(),
color_level: colors::get_color_level(),
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(),
@ -773,6 +774,7 @@ 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(),
color_level: colors::get_color_level(),
is_stdout_tty: deno_terminal::is_stdout_tty(), is_stdout_tty: deno_terminal::is_stdout_tty(),
is_stderr_tty: deno_terminal::is_stderr_tty(), is_stderr_tty: deno_terminal::is_stderr_tty(),
unstable: shared.options.unstable, unstable: shared.options.unstable,

View file

@ -1,5 +1,6 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
import { op_bootstrap_color_depth } from "ext:core/ops";
import { core, primordials } from "ext:core/mod.js"; import { core, primordials } from "ext:core/mod.js";
const { const {
Error, Error,
@ -105,6 +106,32 @@ export class WriteStream extends Socket {
this.rows = rows; this.rows = rows;
this.isTTY = true; this.isTTY = true;
} }
/**
* @param {number | Record<string, string>} [count]
* @param {Record<string, string>} [env]
* @returns {boolean}
*/
hasColors(count, env) {
if (env === undefined && typeof count === "object") {
env = count;
count = 16;
}
const depth = this.getColorDepth(env);
return count <= 2 ** depth;
}
/**
* @param {Record<string, string} [env]
* @returns {1 | 4 | 8 | 24}
*/
getColorDepth(_env) {
// TODO(@marvinhagemeister): Ignore env parameter.
// Haven't seen it used anywhere, seems more done
// to make testing easier in Node
return op_bootstrap_color_depth();
}
} }
export { isatty }; export { isatty };

View file

@ -2,6 +2,7 @@
use deno_core::op2; use deno_core::op2;
use deno_core::OpState; use deno_core::OpState;
use deno_terminal::colors::ColorLevel;
use serde::Serialize; use serde::Serialize;
use crate::BootstrapOptions; use crate::BootstrapOptions;
@ -16,6 +17,7 @@ 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_color_depth,
op_bootstrap_is_stdout_tty, op_bootstrap_is_stdout_tty,
op_bootstrap_is_stderr_tty, op_bootstrap_is_stderr_tty,
op_bootstrap_unstable_args, op_bootstrap_unstable_args,
@ -126,6 +128,17 @@ pub fn op_bootstrap_no_color(state: &mut OpState) -> bool {
options.no_color options.no_color
} }
#[op2(fast)]
pub fn op_bootstrap_color_depth(state: &mut OpState) -> i32 {
let options = state.borrow::<BootstrapOptions>();
match options.color_level {
ColorLevel::None => 1,
ColorLevel::Ansi => 4,
ColorLevel::Ansi256 => 8,
ColorLevel::TrueColor => 24,
}
}
#[op2(fast)] #[op2(fast)]
pub fn op_bootstrap_is_stdout_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>();

View file

@ -77,6 +77,7 @@ pub struct BootstrapOptions {
pub no_color: bool, pub no_color: bool,
pub is_stdout_tty: bool, pub is_stdout_tty: bool,
pub is_stderr_tty: bool, pub is_stderr_tty: bool,
pub color_level: deno_terminal::colors::ColorLevel,
// --unstable flag, deprecated // --unstable flag, deprecated
pub unstable: bool, pub unstable: bool,
// --unstable-* flags // --unstable-* flags
@ -111,6 +112,7 @@ impl Default for BootstrapOptions {
no_color: !colors::use_color(), no_color: !colors::use_color(),
is_stdout_tty: deno_terminal::is_stdout_tty(), is_stdout_tty: deno_terminal::is_stdout_tty(),
is_stderr_tty: deno_terminal::is_stderr_tty(), is_stderr_tty: deno_terminal::is_stderr_tty(),
color_level: colors::get_color_level(),
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(),

View file

@ -3,6 +3,7 @@
import { assert } from "@std/assert/mod.ts"; import { assert } from "@std/assert/mod.ts";
import { isatty } from "node:tty"; import { isatty } from "node:tty";
import tty from "node:tty";
import process from "node:process"; import process from "node:process";
Deno.test("[node/tty isatty] returns true when fd is a tty, false otherwise", () => { Deno.test("[node/tty isatty] returns true when fd is a tty, false otherwise", () => {
@ -34,3 +35,11 @@ Deno.test("[node/tty WriteStream.isTTY] returns true when fd is a tty", () => {
assert(Deno.stdin.isTerminal() === process.stdin.isTTY); assert(Deno.stdin.isTerminal() === process.stdin.isTTY);
assert(Deno.stdout.isTerminal() === process.stdout.isTTY); assert(Deno.stdout.isTerminal() === process.stdout.isTTY);
}); });
Deno.test("[node/tty WriteStream.hasColors] returns true when colors are supported", () => {
assert(tty.WriteStream.prototype.hasColors() === !Deno.noColor);
});
Deno.test("[node/tty WriteStream.getColorDepth] returns current terminal color depth", () => {
assert([1, 4, 8, 24].includes(tty.WriteStream.prototype.getColorDepth()));
});