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:
parent
60688c563e
commit
4eedac3604
11 changed files with 92 additions and 33 deletions
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
});
|
});
|
||||||
|
|
37
cli/tsc/dts/lib.deno.ns.d.ts
vendored
37
cli/tsc/dts/lib.deno.ns.d.ts
vendored
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 };
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue