1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-21 15:04:11 -05:00

feat: Deno.{stdin,stdout,stderr}.isTerminal(), deprecate Deno.isatty() (#22011)

This change:
1. Implements `Deno.stdin.isTerminal()`, `Deno.stdout.isTerminal()` and
`Deno.stderr.isTerminal()`.
2. Deprecates `Deno.isatty()` for removal in Deno v2, in favour of the
above instance methods.
3. Replaces use of `Deno.isatty()` with the above instance methods.

Related #21995

---------

Co-authored-by: Bartek Iwańczuk <biwanczuk@gmail.com>
Co-authored-by: Divy Srivastava <dj.srivastava23@gmail.com>
This commit is contained in:
Asher Gomez 2024-01-24 10:01:56 +11:00 committed by GitHub
parent 60688c563e
commit 4eedac3604
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 92 additions and 33 deletions

View file

@ -4,7 +4,7 @@ import { assert } from "./test_util.ts";
// Note tests for Deno.stdin.setRaw is in integration tests. // Note tests for Deno.stdin.setRaw is in integration tests.
Deno.test(function consoleSize() { Deno.test(function consoleSize() {
if (!Deno.isatty(Deno.stdout.rid)) { if (!Deno.stdout.isTerminal()) {
return; return;
} }
const result = Deno.consoleSize(); const result = Deno.consoleSize();

View file

@ -356,14 +356,14 @@ Deno.test({
name: "process.stdin", name: "process.stdin",
fn() { fn() {
assertEquals(process.stdin.fd, Deno.stdin.rid); assertEquals(process.stdin.fd, Deno.stdin.rid);
assertEquals(process.stdin.isTTY, Deno.isatty(Deno.stdin.rid)); assertEquals(process.stdin.isTTY, Deno.stdin.isTerminal());
}, },
}); });
Deno.test({ Deno.test({
name: "process.stdin readable with a TTY", name: "process.stdin readable with a TTY",
// TODO(PolarETech): Run this test even in non tty environment // TODO(PolarETech): Run this test even in non tty environment
ignore: !Deno.isatty(Deno.stdin.rid), ignore: !Deno.stdin.isTerminal(),
// stdin resource is present before the test starts. // stdin resource is present before the test starts.
sanitizeResources: false, sanitizeResources: false,
async fn() { async fn() {
@ -535,7 +535,7 @@ Deno.test({
name: "process.stdout", name: "process.stdout",
fn() { fn() {
assertEquals(process.stdout.fd, Deno.stdout.rid); assertEquals(process.stdout.fd, Deno.stdout.rid);
const isTTY = Deno.isatty(Deno.stdout.rid); const isTTY = Deno.stdout.isTerminal();
assertEquals(process.stdout.isTTY, isTTY); assertEquals(process.stdout.isTTY, isTTY);
const consoleSize = isTTY ? Deno.consoleSize() : undefined; const consoleSize = isTTY ? Deno.consoleSize() : undefined;
assertEquals(process.stdout.columns, consoleSize?.columns); assertEquals(process.stdout.columns, consoleSize?.columns);
@ -563,7 +563,7 @@ Deno.test({
name: "process.stderr", name: "process.stderr",
fn() { fn() {
assertEquals(process.stderr.fd, Deno.stderr.rid); assertEquals(process.stderr.fd, Deno.stderr.rid);
const isTTY = Deno.isatty(Deno.stderr.rid); const isTTY = Deno.stderr.isTerminal();
assertEquals(process.stderr.isTTY, isTTY); assertEquals(process.stderr.isTTY, isTTY);
const consoleSize = isTTY ? Deno.consoleSize() : undefined; const consoleSize = isTTY ? Deno.consoleSize() : undefined;
assertEquals(process.stderr.columns, consoleSize?.columns); assertEquals(process.stderr.columns, consoleSize?.columns);

View file

@ -6,9 +6,9 @@ import { isatty } 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", () => {
assert(Deno.isatty(Deno.stdin.rid) === isatty(Deno.stdin.rid)); assert(Deno.stdin.isTerminal() === isatty(Deno.stdin.rid));
assert(Deno.isatty(Deno.stdout.rid) === isatty(Deno.stdout.rid)); assert(Deno.stdout.isTerminal() === isatty(Deno.stdout.rid));
assert(Deno.isatty(Deno.stderr.rid) === isatty(Deno.stderr.rid)); assert(Deno.stderr.isTerminal() === isatty(Deno.stderr.rid));
const file = Deno.openSync("README.md"); const file = Deno.openSync("README.md");
assert(!isatty(file.rid)); assert(!isatty(file.rid));
@ -32,6 +32,6 @@ Deno.test("[node/tty isatty] returns false for irrelevant values", () => {
}); });
Deno.test("[node/tty WriteStream.isTTY] returns true when fd is a tty", () => { Deno.test("[node/tty WriteStream.isTTY] returns true when fd is a tty", () => {
assert(Deno.isatty(Deno.stdin.rid) === process.stdin.isTTY); assert(Deno.stdin.isTerminal() === process.stdin.isTTY);
assert(Deno.isatty(Deno.stdout.rid) === process.stdout.isTTY); assert(Deno.stdout.isTerminal() === process.stdout.isTTY);
}); });

View file

@ -2612,6 +2612,17 @@ declare namespace Deno {
* @category I/O * @category I/O
*/ */
setRaw(mode: boolean, options?: SetRawOptions): void; setRaw(mode: boolean, options?: SetRawOptions): void;
/**
* Checks if `stdin` is a TTY (terminal).
*
* ```ts
* // This example is system and context specific
* Deno.stdin.isTerminal(); // true
* ```
*
* @category I/O
*/
isTerminal(): boolean;
}; };
/** A reference to `stdout` which can be used to write directly to `stdout`. /** A reference to `stdout` which can be used to write directly to `stdout`.
* It implements the Deno specific {@linkcode Writer}, {@linkcode WriterSync}, * It implements the Deno specific {@linkcode Writer}, {@linkcode WriterSync},
@ -2629,6 +2640,17 @@ declare namespace Deno {
readonly rid: number; readonly rid: number;
/** A writable stream interface to `stdout`. */ /** A writable stream interface to `stdout`. */
readonly writable: WritableStream<Uint8Array>; readonly writable: WritableStream<Uint8Array>;
/**
* Checks if `stdout` is a TTY (terminal).
*
* ```ts
* // This example is system and context specific
* Deno.stdout.isTerminal(); // true
* ```
*
* @category I/O
*/
isTerminal(): boolean;
}; };
/** A reference to `stderr` which can be used to write directly to `stderr`. /** A reference to `stderr` which can be used to write directly to `stderr`.
* It implements the Deno specific {@linkcode Writer}, {@linkcode WriterSync}, * It implements the Deno specific {@linkcode Writer}, {@linkcode WriterSync},
@ -2646,6 +2668,17 @@ declare namespace Deno {
readonly rid: number; readonly rid: number;
/** A writable stream interface to `stderr`. */ /** A writable stream interface to `stderr`. */
readonly writable: WritableStream<Uint8Array>; readonly writable: WritableStream<Uint8Array>;
/**
* Checks if `stderr` is a TTY (terminal).
*
* ```ts
* // This example is system and context specific
* Deno.stderr.isTerminal(); // true
* ```
*
* @category I/O
*/
isTerminal(): boolean;
}; };
/** /**
@ -2728,6 +2761,10 @@ declare namespace Deno {
* Deno.close(ttyRid); * Deno.close(ttyRid);
* ``` * ```
* *
* @deprecated Use `Deno.stdin.isTerminal()`, `Deno.stdout.isTerminal()` or
* `Deno.stderr.isTerminal()` instead.
* {@linkcode Deno.isatty} will be removed in v2.0.0.
*
* @category I/O * @category I/O
*/ */
export function isatty(rid: number): boolean; export function isatty(rid: number): boolean;

View file

@ -7,6 +7,7 @@
import { core, primordials } from "ext:core/mod.js"; import { core, primordials } from "ext:core/mod.js";
const { const {
op_stdin_set_raw, op_stdin_set_raw,
op_is_terminal,
} = core.ensureFastOps(true); } = core.ensureFastOps(true);
const { const {
Uint8Array, Uint8Array,
@ -197,6 +198,10 @@ class Stdin {
const cbreak = !!(options.cbreak ?? false); const cbreak = !!(options.cbreak ?? false);
op_stdin_set_raw(mode, cbreak); op_stdin_set_raw(mode, cbreak);
} }
isTerminal() {
return op_is_terminal(this.rid);
}
} }
class Stdout { class Stdout {
@ -227,6 +232,10 @@ class Stdout {
} }
return this.#writable; return this.#writable;
} }
isTerminal() {
return op_is_terminal(this.rid);
}
} }
class Stderr { class Stderr {
@ -257,6 +266,10 @@ class Stderr {
} }
return this.#writable; return this.#writable;
} }
isTerminal() {
return op_is_terminal(this.rid);
}
} }
const stdin = new Stdin(); const stdin = new Stdin();

View file

@ -46,30 +46,27 @@ export function createWritableStdioStream(writer, name) {
enumerable: true, enumerable: true,
configurable: true, configurable: true,
get: () => get: () =>
Deno.isatty?.(writer?.rid) ? Deno.consoleSize?.().columns : undefined, writer?.isTerminal() ? Deno.consoleSize?.().columns : undefined,
}, },
rows: { rows: {
enumerable: true, enumerable: true,
configurable: true, configurable: true,
get: () => get: () => writer?.isTerminal() ? Deno.consoleSize?.().rows : undefined,
Deno.isatty?.(writer?.rid) ? Deno.consoleSize?.().rows : undefined,
}, },
isTTY: { isTTY: {
enumerable: true, enumerable: true,
configurable: true, configurable: true,
get: () => Deno.isatty?.(writer?.rid), get: () => writer?.isTerminal(),
}, },
getWindowSize: { getWindowSize: {
enumerable: true, enumerable: true,
configurable: true, configurable: true,
value: () => value: () =>
Deno.isatty?.(writer?.rid) writer?.isTerminal() ? Object.values(Deno.consoleSize?.()) : undefined,
? Object.values(Deno.consoleSize?.())
: undefined,
}, },
}); });
if (Deno.isatty?.(writer?.rid)) { if (writer?.isTerminal()) {
// These belong on tty.WriteStream(), but the TTY streams currently have // These belong on tty.WriteStream(), but the TTY streams currently have
// following problems: // following problems:
// 1. Using them here introduces a circular dependency. // 1. Using them here introduces a circular dependency.
@ -180,7 +177,7 @@ export const initStdin = () => {
enumerable: true, enumerable: true,
configurable: true, configurable: true,
get() { get() {
return Deno.isatty?.(io.stdin.rid); return io.stdin.isTerminal();
}, },
}); });
stdin._isRawMode = false; stdin._isRawMode = false;

View file

@ -163,7 +163,7 @@ export function createErrDiff(
// If the stderr is a tty and the input length is lower than the current // If the stderr is a tty and the input length is lower than the current
// columns per line, add a mismatch indicator below the output. If it is // columns per line, add a mismatch indicator below the output. If it is
// not a tty, use a default value of 80 characters. // not a tty, use a default value of 80 characters.
const maxLength = Deno.isatty(io.stderr.rid) ? getConsoleWidth() : 80; const maxLength = io.stderr.isTerminal() ? getConsoleWidth() : 80;
if (inputLength < maxLength) { if (inputLength < maxLength) {
while (actualRaw[i] === expectedRaw[i]) { while (actualRaw[i] === expectedRaw[i]) {
i++; i++;
@ -406,7 +406,7 @@ export class AssertionError extends Error {
if (message != null) { if (message != null) {
super(String(message)); super(String(message));
} else { } else {
if (Deno.isatty(io.stderr.rid)) { if (io.stderr.isTerminal()) {
// Reset on each call to make sure we handle dynamically set environment // Reset on each call to make sure we handle dynamically set environment
// variables correct. // variables correct.
if (Deno.noColor) { if (Deno.noColor) {

View file

@ -1,9 +1,12 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
import { primordials } from "ext:core/mod.js"; import { core, primordials } from "ext:core/mod.js";
const { const {
Error, Error,
} = primordials; } = primordials;
const {
op_is_terminal,
} = core.ensureFastOps(true);
import { ERR_INVALID_FD } from "ext:deno_node/internal/errors.ts"; import { ERR_INVALID_FD } from "ext:deno_node/internal/errors.ts";
import { LibuvStreamWrap } from "ext:deno_node/internal_binding/stream_wrap.ts"; import { LibuvStreamWrap } from "ext:deno_node/internal_binding/stream_wrap.ts";
@ -17,7 +20,12 @@ function isatty(fd) {
return false; return false;
} }
try { try {
return Deno.isatty(fd); /**
* TODO: Treat `fd` as real file descriptors. Currently, `rid` 0, 1, 2
* correspond to `fd` 0, 1, 2 (stdin, stdout, stderr). This may change in
* the future.
*/
return op_is_terminal(fd);
} catch (_) { } catch (_) {
return false; return false;
} }

View file

@ -1,9 +1,9 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
import { core, primordials } from "ext:core/mod.js"; import { core, internals, primordials } from "ext:core/mod.js";
const { const {
op_console_size, op_console_size,
op_isatty, op_is_terminal,
} = core.ensureFastOps(); } = core.ensureFastOps(true);
const { const {
Uint32Array, Uint32Array,
} = primordials; } = primordials;
@ -16,7 +16,12 @@ function consoleSize() {
} }
function isatty(rid) { function isatty(rid) {
return op_isatty(rid); internals.warnOnDeprecatedApi(
"Deno.isatty()",
new Error().stack,
"Use `stdStream.isTerminal()` instead.",
);
return op_is_terminal(rid);
} }
export { consoleSize, isatty }; export { consoleSize, isatty };

View file

@ -9,14 +9,13 @@ const {
Uint8Array, Uint8Array,
} = primordials; } = primordials;
import { isatty } from "ext:runtime/40_tty.js";
import { stdin } from "ext:deno_io/12_io.js"; import { stdin } from "ext:deno_io/12_io.js";
const LF = StringPrototypeCharCodeAt("\n", 0); const LF = StringPrototypeCharCodeAt("\n", 0);
const CR = StringPrototypeCharCodeAt("\r", 0); const CR = StringPrototypeCharCodeAt("\r", 0);
function alert(message = "Alert") { function alert(message = "Alert") {
if (!isatty(stdin.rid)) { if (!stdin.isTerminal()) {
return; return;
} }
@ -26,7 +25,7 @@ function alert(message = "Alert") {
} }
function confirm(message = "Confirm") { function confirm(message = "Confirm") {
if (!isatty(stdin.rid)) { if (!stdin.isTerminal()) {
return false; return false;
} }
@ -40,7 +39,7 @@ function confirm(message = "Confirm") {
function prompt(message = "Prompt", defaultValue) { function prompt(message = "Prompt", defaultValue) {
defaultValue ??= ""; defaultValue ??= "";
if (!isatty(stdin.rid)) { if (!stdin.isTerminal()) {
return null; return null;
} }

View file

@ -52,7 +52,7 @@ deno_core::extension!(
deno_tty, deno_tty,
ops = [ ops = [
op_stdin_set_raw, op_stdin_set_raw,
op_isatty, op_is_terminal,
op_console_size, op_console_size,
op_read_line_prompt op_read_line_prompt
], ],
@ -210,7 +210,7 @@ fn op_stdin_set_raw(
} }
#[op2(fast)] #[op2(fast)]
fn op_isatty(state: &mut OpState, rid: u32) -> Result<bool, AnyError> { fn op_is_terminal(state: &mut OpState, rid: u32) -> Result<bool, AnyError> {
let handle = state.resource_table.get_handle(rid)?; let handle = state.resource_table.get_handle(rid)?;
Ok(handle.is_terminal()) Ok(handle.is_terminal())
} }