summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAsher Gomez <ashersaupingomez@gmail.com>2024-02-19 01:27:44 +1100
committerGitHub <noreply@github.com>2024-02-18 07:27:44 -0700
commitc1fac11dfaf9d656b7361708d9faab1916eac846 (patch)
tree151c729aa2774c21924b0bb8a1c6aa6daffea854
parent7abd72a80f0aafe071ad7d298b48e0da741cc9f3 (diff)
feat(fs): `Deno.FsFile.{isTerminal,setRaw}()` (#22234)
Closes #22229. --------- Signed-off-by: Asher Gomez <ashersaupingomez@gmail.com>
-rw-r--r--cli/tsc/dts/lib.deno.ns.d.ts25
-rw-r--r--ext/fs/30_fs.js11
-rw-r--r--ext/io/12_io.js4
-rw-r--r--runtime/js/40_tty.js2
-rw-r--r--runtime/ops/tty.rs6
-rw-r--r--tests/integration/run_tests.rs19
-rw-r--r--tests/unit/files_test.ts8
7 files changed, 69 insertions, 6 deletions
diff --git a/cli/tsc/dts/lib.deno.ns.d.ts b/cli/tsc/dts/lib.deno.ns.d.ts
index 720f7fc94..787c1a225 100644
--- a/cli/tsc/dts/lib.deno.ns.d.ts
+++ b/cli/tsc/dts/lib.deno.ns.d.ts
@@ -2668,6 +2668,31 @@ declare namespace Deno {
utimeSync(atime: number | Date, mtime: number | Date): void;
/** **UNSTABLE**: New API, yet to be vetted.
*
+ * Checks if the file resource is a TTY (terminal).
+ *
+ * ```ts
+ * // This example is system and context specific
+ * using file = await Deno.open("/dev/tty6");
+ * file.isTerminal(); // true
+ * ```
+ */
+ isTerminal(): boolean;
+ /** **UNSTABLE**: New API, yet to be vetted.
+ *
+ * Set TTY to be under raw mode or not. In raw mode, characters are read and
+ * returned as is, without being processed. All special processing of
+ * characters by the terminal is disabled, including echoing input
+ * characters. Reading from a TTY device in raw mode is faster than reading
+ * from a TTY device in canonical mode.
+ *
+ * ```ts
+ * using file = await Deno.open("/dev/tty6");
+ * file.setRaw(true, { cbreak: true });
+ * ```
+ */
+ setRaw(mode: boolean, options?: SetRawOptions): void;
+ /** **UNSTABLE**: New API, yet to be vetted.
+ *
* Acquire an advisory file-system lock for the file.
*
* @param [exclusive=false]
diff --git a/ext/fs/30_fs.js b/ext/fs/30_fs.js
index 46358c42a..2efb0a878 100644
--- a/ext/fs/30_fs.js
+++ b/ext/fs/30_fs.js
@@ -72,6 +72,8 @@ import {
op_fs_utime_sync,
op_fs_write_file_async,
op_fs_write_file_sync,
+ op_is_terminal,
+ op_set_raw,
} from "ext:core/ops";
const {
ArrayPrototypeFilter,
@@ -766,6 +768,15 @@ class FsFile {
futimeSync(this.#rid, atime, mtime);
}
+ isTerminal() {
+ return op_is_terminal(this.#rid);
+ }
+
+ setRaw(mode, options = {}) {
+ const cbreak = !!(options.cbreak ?? false);
+ op_set_raw(this.#rid, mode, cbreak);
+ }
+
lockSync(exclusive = false) {
op_fs_flock_sync(this.#rid, exclusive);
}
diff --git a/ext/io/12_io.js b/ext/io/12_io.js
index 70b639d45..fbaf28de7 100644
--- a/ext/io/12_io.js
+++ b/ext/io/12_io.js
@@ -5,7 +5,7 @@
// Thank you! We love Go! <3
import { core, internals, primordials } from "ext:core/mod.js";
-import { op_is_terminal, op_stdin_set_raw } from "ext:core/ops";
+import { op_is_terminal, op_set_raw } from "ext:core/ops";
const {
Uint8Array,
ArrayPrototypePush,
@@ -218,7 +218,7 @@ class Stdin {
setRaw(mode, options = {}) {
const cbreak = !!(options.cbreak ?? false);
- op_stdin_set_raw(mode, cbreak);
+ op_set_raw(this.#rid, mode, cbreak);
}
isTerminal() {
diff --git a/runtime/js/40_tty.js b/runtime/js/40_tty.js
index 5b8bbc0be..dd364f18d 100644
--- a/runtime/js/40_tty.js
+++ b/runtime/js/40_tty.js
@@ -16,7 +16,7 @@ function isatty(rid) {
internals.warnOnDeprecatedApi(
"Deno.isatty()",
new Error().stack,
- "Use `Deno.stdin.isTerminal()`, `Deno.stdout.isTerminal()` or `Deno.stderr.isTerminal()` instead.",
+ "Use `Deno.stdin.isTerminal()`, `Deno.stdout.isTerminal()`, `Deno.stderr.isTerminal()` or `Deno.FsFile.isTerminal()` instead.",
);
return op_is_terminal(rid);
}
diff --git a/runtime/ops/tty.rs b/runtime/ops/tty.rs
index 40aa28494..e570754f2 100644
--- a/runtime/ops/tty.rs
+++ b/runtime/ops/tty.rs
@@ -51,7 +51,7 @@ use winapi::um::wincon;
deno_core::extension!(
deno_tty,
ops = [
- op_stdin_set_raw,
+ op_set_raw,
op_is_terminal,
op_console_size,
op_read_line_prompt
@@ -83,12 +83,12 @@ fn mode_raw_input_off(original_mode: DWORD) -> DWORD {
}
#[op2(fast)]
-fn op_stdin_set_raw(
+fn op_set_raw(
state: &mut OpState,
+ rid: u32,
is_raw: bool,
cbreak: bool,
) -> Result<(), AnyError> {
- let rid = 0; // stdin is always rid=0
let handle_or_fd = state.resource_table.get_fd(rid)?;
// From https://github.com/kkawakam/rustyline/blob/master/src/tty/windows.rs
diff --git a/tests/integration/run_tests.rs b/tests/integration/run_tests.rs
index 68b72ffed..02fb915b5 100644
--- a/tests/integration/run_tests.rs
+++ b/tests/integration/run_tests.rs
@@ -4304,6 +4304,25 @@ fn set_raw_should_not_panic_on_no_tty() {
assert!(stderr.contains("BadResource"));
}
+#[cfg(not(windows))]
+#[test]
+fn fsfile_set_raw_should_not_panic_on_no_tty() {
+ let output = util::deno_cmd()
+ .arg("eval")
+ .arg("Deno.openSync(\"/dev/stdin\").setRaw(true)")
+ // stdin set to piped so it certainly does not refer to TTY
+ .stdin(std::process::Stdio::piped())
+ // stderr is piped so we can capture output.
+ .stderr_piped()
+ .spawn()
+ .unwrap()
+ .wait_with_output()
+ .unwrap();
+ assert!(!output.status.success());
+ let stderr = std::str::from_utf8(&output.stderr).unwrap().trim();
+ assert!(stderr.contains("BadResource"));
+}
+
#[test]
fn timeout_clear() {
// https://github.com/denoland/deno/issues/7599
diff --git a/tests/unit/files_test.ts b/tests/unit/files_test.ts
index 47fa03ddd..0034a8472 100644
--- a/tests/unit/files_test.ts
+++ b/tests/unit/files_test.ts
@@ -10,6 +10,8 @@ import {
} from "./test_util.ts";
import { copy } from "@std/streams/copy.ts";
+// Note tests for Deno.FsFile.setRaw is in integration tests.
+
Deno.test(function filesStdioFileDescriptors() {
assertEquals(Deno.stdin.rid, 0);
assertEquals(Deno.stdout.rid, 1);
@@ -899,6 +901,12 @@ Deno.test(
},
);
+Deno.test({ permissions: { read: true } }, function fsFileIsTerminal() {
+ // CI not under TTY, so cannot test stdin/stdout/stderr.
+ using file = Deno.openSync("tests/testdata/assets/hello.txt");
+ assert(!file.isTerminal());
+});
+
Deno.test(
{ permissions: { read: true, run: true, hrtime: true } },
async function fsFileLockFileSync() {