2024-01-01 14:58:21 -05:00
|
|
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
2023-10-30 11:53:08 -04:00
|
|
|
|
2024-07-19 06:39:05 -04:00
|
|
|
import { op_bootstrap_color_depth } from "ext:core/ops";
|
2024-03-06 18:08:10 -05:00
|
|
|
import { core, primordials } from "ext:core/mod.js";
|
2024-01-10 17:37:25 -05:00
|
|
|
const {
|
|
|
|
Error,
|
|
|
|
} = primordials;
|
2024-03-06 18:08:10 -05:00
|
|
|
const {
|
|
|
|
isTerminal,
|
|
|
|
} = core;
|
2024-01-10 17:37:25 -05:00
|
|
|
|
2023-10-30 11:53:08 -04:00
|
|
|
import { ERR_INVALID_FD } from "ext:deno_node/internal/errors.ts";
|
2024-04-27 07:25:18 -04:00
|
|
|
import {
|
|
|
|
kStreamBaseField,
|
|
|
|
LibuvStreamWrap,
|
|
|
|
} from "ext:deno_node/internal_binding/stream_wrap.ts";
|
2023-10-30 11:53:08 -04:00
|
|
|
import { providerType } from "ext:deno_node/internal_binding/async_wrap.ts";
|
2023-10-31 07:54:43 -04:00
|
|
|
import { Socket } from "node:net";
|
|
|
|
import { setReadStream } from "ext:deno_node/_process/streams.mjs";
|
2024-03-27 23:25:05 -04:00
|
|
|
import * as io from "ext:deno_io/12_io.js";
|
2023-10-30 11:53:08 -04:00
|
|
|
|
|
|
|
// Returns true when the given numeric fd is associated with a TTY and false otherwise.
|
|
|
|
function isatty(fd) {
|
|
|
|
if (typeof fd !== "number") {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
try {
|
2024-01-23 18:01:56 -05:00
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*/
|
2024-03-06 18:08:10 -05:00
|
|
|
return isTerminal(fd);
|
2023-10-30 11:53:08 -04:00
|
|
|
} catch (_) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class TTY extends LibuvStreamWrap {
|
|
|
|
constructor(handle) {
|
|
|
|
super(providerType.TTYWRAP, handle);
|
|
|
|
}
|
2024-04-27 07:25:18 -04:00
|
|
|
|
|
|
|
ref() {
|
|
|
|
this[kStreamBaseField][io.REF]();
|
|
|
|
}
|
|
|
|
|
|
|
|
unref() {
|
|
|
|
this[kStreamBaseField][io.UNREF]();
|
|
|
|
}
|
2023-10-30 11:53:08 -04:00
|
|
|
}
|
|
|
|
|
2023-10-31 07:54:43 -04:00
|
|
|
export class ReadStream extends Socket {
|
2023-10-30 11:53:08 -04:00
|
|
|
constructor(fd, options) {
|
|
|
|
if (fd >> 0 !== fd || fd < 0) {
|
|
|
|
throw new ERR_INVALID_FD(fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
// We only support `stdin`.
|
|
|
|
if (fd != 0) throw new Error("Only fd 0 is supported.");
|
|
|
|
|
2024-03-27 23:25:05 -04:00
|
|
|
const tty = new TTY(io.stdin);
|
2023-10-30 11:53:08 -04:00
|
|
|
super({
|
|
|
|
readableHighWaterMark: 0,
|
|
|
|
handle: tty,
|
|
|
|
manualStart: true,
|
|
|
|
...options,
|
|
|
|
});
|
|
|
|
|
|
|
|
this.isRaw = false;
|
|
|
|
this.isTTY = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
setRawMode(flag) {
|
|
|
|
flag = !!flag;
|
|
|
|
this._handle.setRaw(flag);
|
|
|
|
|
|
|
|
this.isRaw = flag;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-31 07:54:43 -04:00
|
|
|
setReadStream(ReadStream);
|
|
|
|
|
|
|
|
export class WriteStream extends Socket {
|
2023-10-30 11:53:08 -04:00
|
|
|
constructor(fd) {
|
|
|
|
if (fd >> 0 !== fd || fd < 0) {
|
|
|
|
throw new ERR_INVALID_FD(fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
// We only support `stdin`, `stdout` and `stderr`.
|
|
|
|
if (fd > 2) throw new Error("Only fd 0, 1 and 2 are supported.");
|
|
|
|
|
|
|
|
const tty = new TTY(
|
2024-04-13 11:55:00 -04:00
|
|
|
fd === 0 ? io.stdin : fd === 1 ? io.stdout : io.stderr,
|
2023-10-30 11:53:08 -04:00
|
|
|
);
|
|
|
|
|
|
|
|
super({
|
|
|
|
readableHighWaterMark: 0,
|
|
|
|
handle: tty,
|
|
|
|
manualStart: true,
|
|
|
|
});
|
|
|
|
|
|
|
|
const { columns, rows } = Deno.consoleSize();
|
|
|
|
this.columns = columns;
|
|
|
|
this.rows = rows;
|
2024-01-05 16:37:14 -05:00
|
|
|
this.isTTY = true;
|
2023-10-30 11:53:08 -04:00
|
|
|
}
|
2024-07-19 06:39:05 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @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();
|
|
|
|
}
|
2023-10-30 11:53:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
export { isatty };
|
|
|
|
export default { isatty, WriteStream, ReadStream };
|