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

feat(fs): Deno.FsFile.{isTerminal,setRaw}() (#22234)

Closes #22229.

---------

Signed-off-by: Asher Gomez <ashersaupingomez@gmail.com>
This commit is contained in:
Asher Gomez 2024-02-19 01:27:44 +11:00 committed by GitHub
parent 7abd72a80f
commit c1fac11dfa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 69 additions and 6 deletions

View file

@ -2666,6 +2666,31 @@ declare namespace Deno {
* @category File System * @category File System
*/ */
utimeSync(atime: number | Date, mtime: number | Date): void; 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. /** **UNSTABLE**: New API, yet to be vetted.
* *
* Acquire an advisory file-system lock for the file. * Acquire an advisory file-system lock for the file.

View file

@ -72,6 +72,8 @@ import {
op_fs_utime_sync, op_fs_utime_sync,
op_fs_write_file_async, op_fs_write_file_async,
op_fs_write_file_sync, op_fs_write_file_sync,
op_is_terminal,
op_set_raw,
} from "ext:core/ops"; } from "ext:core/ops";
const { const {
ArrayPrototypeFilter, ArrayPrototypeFilter,
@ -766,6 +768,15 @@ class FsFile {
futimeSync(this.#rid, atime, mtime); 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) { lockSync(exclusive = false) {
op_fs_flock_sync(this.#rid, exclusive); op_fs_flock_sync(this.#rid, exclusive);
} }

View file

@ -5,7 +5,7 @@
// Thank you! We love Go! <3 // Thank you! We love Go! <3
import { core, internals, primordials } from "ext:core/mod.js"; 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 { const {
Uint8Array, Uint8Array,
ArrayPrototypePush, ArrayPrototypePush,
@ -218,7 +218,7 @@ class Stdin {
setRaw(mode, options = {}) { setRaw(mode, options = {}) {
const cbreak = !!(options.cbreak ?? false); const cbreak = !!(options.cbreak ?? false);
op_stdin_set_raw(mode, cbreak); op_set_raw(this.#rid, mode, cbreak);
} }
isTerminal() { isTerminal() {

View file

@ -16,7 +16,7 @@ function isatty(rid) {
internals.warnOnDeprecatedApi( internals.warnOnDeprecatedApi(
"Deno.isatty()", "Deno.isatty()",
new Error().stack, 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); return op_is_terminal(rid);
} }

View file

@ -51,7 +51,7 @@ use winapi::um::wincon;
deno_core::extension!( deno_core::extension!(
deno_tty, deno_tty,
ops = [ ops = [
op_stdin_set_raw, op_set_raw,
op_is_terminal, op_is_terminal,
op_console_size, op_console_size,
op_read_line_prompt op_read_line_prompt
@ -83,12 +83,12 @@ fn mode_raw_input_off(original_mode: DWORD) -> DWORD {
} }
#[op2(fast)] #[op2(fast)]
fn op_stdin_set_raw( fn op_set_raw(
state: &mut OpState, state: &mut OpState,
rid: u32,
is_raw: bool, is_raw: bool,
cbreak: bool, cbreak: bool,
) -> Result<(), AnyError> { ) -> Result<(), AnyError> {
let rid = 0; // stdin is always rid=0
let handle_or_fd = state.resource_table.get_fd(rid)?; let handle_or_fd = state.resource_table.get_fd(rid)?;
// From https://github.com/kkawakam/rustyline/blob/master/src/tty/windows.rs // From https://github.com/kkawakam/rustyline/blob/master/src/tty/windows.rs

View file

@ -4304,6 +4304,25 @@ fn set_raw_should_not_panic_on_no_tty() {
assert!(stderr.contains("BadResource")); 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] #[test]
fn timeout_clear() { fn timeout_clear() {
// https://github.com/denoland/deno/issues/7599 // https://github.com/denoland/deno/issues/7599

View file

@ -10,6 +10,8 @@ import {
} from "./test_util.ts"; } from "./test_util.ts";
import { copy } from "@std/streams/copy.ts"; import { copy } from "@std/streams/copy.ts";
// Note tests for Deno.FsFile.setRaw is in integration tests.
Deno.test(function filesStdioFileDescriptors() { Deno.test(function filesStdioFileDescriptors() {
assertEquals(Deno.stdin.rid, 0); assertEquals(Deno.stdin.rid, 0);
assertEquals(Deno.stdout.rid, 1); 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( Deno.test(
{ permissions: { read: true, run: true, hrtime: true } }, { permissions: { read: true, run: true, hrtime: true } },
async function fsFileLockFileSync() { async function fsFileLockFileSync() {