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:
parent
7abd72a80f
commit
c1fac11dfa
7 changed files with 69 additions and 6 deletions
25
cli/tsc/dts/lib.deno.ns.d.ts
vendored
25
cli/tsc/dts/lib.deno.ns.d.ts
vendored
|
@ -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.
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
Loading…
Reference in a new issue