summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarvin Hagemeister <marvin@deno.com>2024-07-19 12:39:05 +0200
committerGitHub <noreply@github.com>2024-07-19 12:39:05 +0200
commitee2e6933403811d398540e0e8275b2d216546dd8 (patch)
tree4ed2944dfbc516ea127c4bee50cc771ac12f902d
parent76b8ecbb6d8c07d29c34fb0b301cc3bf3351e3aa (diff)
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
-rw-r--r--Cargo.lock22
-rw-r--r--Cargo.toml2
-rw-r--r--cli/worker.rs2
-rw-r--r--ext/node/polyfills/tty.js27
-rw-r--r--runtime/ops/bootstrap.rs13
-rw-r--r--runtime/worker_bootstrap.rs2
-rw-r--r--tests/unit_node/tty_test.ts9
7 files changed, 70 insertions, 7 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 615abf0f0..57449dbc7 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -729,7 +729,7 @@ dependencies = [
"deno_core",
"deno_fetch",
"deno_lockfile",
- "deno_terminal",
+ "deno_terminal 0.2.0",
"deno_tls",
"fastwebsockets",
"file_test_runner",
@@ -1134,7 +1134,7 @@ dependencies = [
"deno_runtime",
"deno_semver",
"deno_task_shell",
- "deno_terminal",
+ "deno_terminal 0.2.0",
"dissimilar",
"dotenvy",
"dprint-plugin-json",
@@ -1216,7 +1216,7 @@ dependencies = [
"anyhow",
"base64 0.21.7",
"deno_media_type",
- "deno_terminal",
+ "deno_terminal 0.1.1",
"dprint-swc-ext",
"once_cell",
"percent-encoding",
@@ -1836,7 +1836,7 @@ name = "deno_permissions"
version = "0.21.0"
dependencies = [
"deno_core",
- "deno_terminal",
+ "deno_terminal 0.2.0",
"fqdn",
"libc",
"log",
@@ -1868,7 +1868,7 @@ dependencies = [
"deno_net",
"deno_node",
"deno_permissions",
- "deno_terminal",
+ "deno_terminal 0.2.0",
"deno_tls",
"deno_url",
"deno_web",
@@ -1949,6 +1949,16 @@ dependencies = [
]
[[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]]
name = "deno_tls"
version = "0.148.0"
dependencies = [
@@ -2734,7 +2744,7 @@ checksum = "05b23dcc1b671771c6f59fdace6da685735c925f859733e8fd07fba6cae6462a"
dependencies = [
"anyhow",
"crossbeam-channel",
- "deno_terminal",
+ "deno_terminal 0.1.1",
"parking_lot 0.12.3",
"regex",
"thiserror",
diff --git a/Cargo.toml b/Cargo.toml
index 492ddc47f..b1e1a20cc 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -51,7 +51,7 @@ deno_lockfile = "0.20.0"
deno_media_type = { version = "0.1.4", features = ["module_specifier"] }
deno_permissions = { version = "0.21.0", path = "./runtime/permissions" }
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" }
test_util = { package = "test_server", path = "./tests/util/server" }
diff --git a/cli/worker.rs b/cli/worker.rs
index 9125f28be..36435d634 100644
--- a/cli/worker.rs
+++ b/cli/worker.rs
@@ -571,6 +571,7 @@ impl CliMainWorkerFactory {
no_color: !colors::use_color(),
is_stdout_tty: deno_terminal::is_stdout_tty(),
is_stderr_tty: deno_terminal::is_stderr_tty(),
+ color_level: colors::get_color_level(),
unstable: shared.options.unstable,
unstable_features,
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(),
location: Some(args.main_module.clone()),
no_color: !colors::use_color(),
+ color_level: colors::get_color_level(),
is_stdout_tty: deno_terminal::is_stdout_tty(),
is_stderr_tty: deno_terminal::is_stderr_tty(),
unstable: shared.options.unstable,
diff --git a/ext/node/polyfills/tty.js b/ext/node/polyfills/tty.js
index 3a84a1f94..2e8ecc8e1 100644
--- a/ext/node/polyfills/tty.js
+++ b/ext/node/polyfills/tty.js
@@ -1,5 +1,6 @@
// 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";
const {
Error,
@@ -105,6 +106,32 @@ export class WriteStream extends Socket {
this.rows = rows;
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 };
diff --git a/runtime/ops/bootstrap.rs b/runtime/ops/bootstrap.rs
index c5c193ef3..997bebd76 100644
--- a/runtime/ops/bootstrap.rs
+++ b/runtime/ops/bootstrap.rs
@@ -2,6 +2,7 @@
use deno_core::op2;
use deno_core::OpState;
+use deno_terminal::colors::ColorLevel;
use serde::Serialize;
use crate::BootstrapOptions;
@@ -16,6 +17,7 @@ deno_core::extension!(
op_bootstrap_language,
op_bootstrap_log_level,
op_bootstrap_no_color,
+ op_bootstrap_color_depth,
op_bootstrap_is_stdout_tty,
op_bootstrap_is_stderr_tty,
op_bootstrap_unstable_args,
@@ -127,6 +129,17 @@ pub fn op_bootstrap_no_color(state: &mut OpState) -> bool {
}
#[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)]
pub fn op_bootstrap_is_stdout_tty(state: &mut OpState) -> bool {
let options = state.borrow::<BootstrapOptions>();
options.is_stdout_tty
diff --git a/runtime/worker_bootstrap.rs b/runtime/worker_bootstrap.rs
index 0838da2d1..b13c3c428 100644
--- a/runtime/worker_bootstrap.rs
+++ b/runtime/worker_bootstrap.rs
@@ -77,6 +77,7 @@ pub struct BootstrapOptions {
pub no_color: bool,
pub is_stdout_tty: bool,
pub is_stderr_tty: bool,
+ pub color_level: deno_terminal::colors::ColorLevel,
// --unstable flag, deprecated
pub unstable: bool,
// --unstable-* flags
@@ -111,6 +112,7 @@ impl Default for BootstrapOptions {
no_color: !colors::use_color(),
is_stdout_tty: deno_terminal::is_stdout_tty(),
is_stderr_tty: deno_terminal::is_stderr_tty(),
+ color_level: colors::get_color_level(),
enable_op_summary_metrics: Default::default(),
enable_testing_features: Default::default(),
log_level: Default::default(),
diff --git a/tests/unit_node/tty_test.ts b/tests/unit_node/tty_test.ts
index 39ab4fe17..cde05b9ff 100644
--- a/tests/unit_node/tty_test.ts
+++ b/tests/unit_node/tty_test.ts
@@ -3,6 +3,7 @@
import { assert } from "@std/assert/mod.ts";
import { isatty } from "node:tty";
+import tty from "node:tty";
import process from "node:process";
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.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()));
+});