summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastien Filion <sebastienfilion@mac.com>2020-07-10 10:07:12 -0400
committerGitHub <noreply@github.com>2020-07-10 10:07:12 -0400
commit1bcc35b84a78fb052b8092b7ed57c2ce763f5d4b (patch)
tree913a4533901ba35bf47012009c0fa4c88b8ebe60
parentdc6b3ef714c743358703512cd766aed4abc8bd3b (diff)
feat(unstable): add Deno.consoleSize (#6520)
-rw-r--r--cli/js/deno_unstable.ts2
-rw-r--r--cli/js/lib.deno.unstable.d.ts15
-rw-r--r--cli/js/ops/tty.ts4
-rw-r--r--cli/ops/tty.rs80
-rw-r--r--cli/tests/unit/tty_test.ts17
5 files changed, 115 insertions, 3 deletions
diff --git a/cli/js/deno_unstable.ts b/cli/js/deno_unstable.ts
index 7d75c1c6a..f92d767b3 100644
--- a/cli/js/deno_unstable.ts
+++ b/cli/js/deno_unstable.ts
@@ -12,7 +12,7 @@ export { openPlugin } from "./ops/plugins.ts";
export { transpileOnly, compile, bundle } from "./compiler_api.ts";
export { applySourceMap, formatDiagnostics } from "./ops/errors.ts";
export { signal, signals, Signal, SignalStream } from "./signals.ts";
-export { setRaw } from "./ops/tty.ts";
+export { setRaw, consoleSize } from "./ops/tty.ts";
export { utimeSync, utime } from "./ops/fs/utime.ts";
export { ftruncateSync, ftruncate } from "./ops/fs/truncate.ts";
export { shutdown, ShutdownMode } from "./net.ts";
diff --git a/cli/js/lib.deno.unstable.d.ts b/cli/js/lib.deno.unstable.d.ts
index f237cd4be..a6547ebca 100644
--- a/cli/js/lib.deno.unstable.d.ts
+++ b/cli/js/lib.deno.unstable.d.ts
@@ -43,6 +43,21 @@ declare namespace Deno {
* Requires `allow-read` and `allow-write` permissions. */
export function link(oldpath: string, newpath: string): Promise<void>;
+ /** **UNSTABLE**: New API, yet to be vetted.
+ *
+ * Gets the size of the console as columns/rows.
+ *
+ * ```ts
+ * const { columns, rows } = await Deno.consoleSize(Deno.stdout.rid);
+ * ```
+ */
+ export function consoleSize(
+ rid: number
+ ): {
+ columns: number;
+ rows: number;
+ };
+
export type SymlinkOptions = {
type: "file" | "dir";
};
diff --git a/cli/js/ops/tty.ts b/cli/js/ops/tty.ts
index 8899ca5b8..f9da7bd0d 100644
--- a/cli/js/ops/tty.ts
+++ b/cli/js/ops/tty.ts
@@ -2,6 +2,10 @@
import { sendSync } from "./dispatch_json.ts";
+export function consoleSize(rid: number): [number, number] {
+ return sendSync("op_console_size", { rid });
+}
+
export function isatty(rid: number): boolean {
return sendSync("op_isatty", { rid });
}
diff --git a/cli/ops/tty.rs b/cli/ops/tty.rs
index bf94ec17f..d86100232 100644
--- a/cli/ops/tty.rs
+++ b/cli/ops/tty.rs
@@ -8,7 +8,7 @@ use deno_core::CoreIsolateState;
use deno_core::ZeroCopyBuf;
#[cfg(unix)]
use nix::sys::termios;
-use serde_derive::Deserialize;
+use serde_derive::{Deserialize, Serialize};
use serde_json::Value;
#[cfg(windows)]
@@ -38,6 +38,7 @@ fn get_windows_handle(
pub fn init(i: &mut CoreIsolate, s: &State) {
i.register_op("op_set_raw", s.stateful_json_op2(op_set_raw));
i.register_op("op_isatty", s.stateful_json_op2(op_isatty));
+ i.register_op("op_console_size", s.stateful_json_op2(op_console_size));
}
#[derive(Deserialize)]
@@ -250,3 +251,80 @@ pub fn op_isatty(
})?;
Ok(JsonOp::Sync(json!(isatty)))
}
+
+#[derive(Deserialize)]
+struct ConsoleSizeArgs {
+ rid: u32,
+}
+
+#[derive(Serialize)]
+struct ConsoleSize {
+ columns: u32,
+ rows: u32,
+}
+
+pub fn op_console_size(
+ isolate_state: &mut CoreIsolateState,
+ state: &State,
+ args: Value,
+ _zero_copy: &mut [ZeroCopyBuf],
+) -> Result<JsonOp, OpError> {
+ state.check_unstable("Deno.consoleSize");
+ let args: ConsoleSizeArgs = serde_json::from_value(args)?;
+ let rid = args.rid;
+
+ let mut resource_table = isolate_state.resource_table.borrow_mut();
+ let size =
+ std_file_resource(&mut resource_table, rid as u32, move |r| match r {
+ Ok(std_file) => {
+ #[cfg(windows)]
+ {
+ use std::os::windows::io::AsRawHandle;
+ let handle = std_file.as_raw_handle();
+
+ unsafe {
+ let mut bufinfo: winapi::um::wincon::CONSOLE_SCREEN_BUFFER_INFO =
+ std::mem::zeroed();
+
+ if winapi::um::wincon::GetConsoleScreenBufferInfo(
+ handle,
+ &mut bufinfo,
+ ) == 0
+ {
+ // TODO (caspervonb) use GetLastError
+ return Err(OpError::other(
+ winapi::um::errhandlingapi::GetLastError().to_string(),
+ ));
+ }
+
+ Ok(ConsoleSize {
+ columns: bufinfo.dwSize.X as u32,
+ rows: bufinfo.dwSize.Y as u32,
+ })
+ }
+ }
+
+ #[cfg(unix)]
+ {
+ use std::os::unix::io::AsRawFd;
+
+ let fd = std_file.as_raw_fd();
+ unsafe {
+ let mut size: libc::winsize = std::mem::zeroed();
+ if libc::ioctl(fd, libc::TIOCGWINSZ, &mut size as *mut _) != 0 {
+ return Err(OpError::from(std::io::Error::last_os_error()));
+ }
+
+ // TODO (caspervonb) return a tuple instead
+ Ok(ConsoleSize {
+ columns: size.ws_col as u32,
+ rows: size.ws_row as u32,
+ })
+ }
+ }
+ }
+ Err(_) => Err(OpError::bad_resource_id()),
+ })?;
+
+ Ok(JsonOp::Sync(json!(size)))
+}
diff --git a/cli/tests/unit/tty_test.ts b/cli/tests/unit/tty_test.ts
index 116b0dfe9..7e9873791 100644
--- a/cli/tests/unit/tty_test.ts
+++ b/cli/tests/unit/tty_test.ts
@@ -1,8 +1,23 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-import { unitTest, assert } from "./test_util.ts";
+import { unitTest, assert, assertThrows } from "./test_util.ts";
// Note tests for Deno.setRaw is in integration tests.
+unitTest({ perms: { read: true } }, function consoleSizeFile(): void {
+ const file = Deno.openSync("cli/tests/hello.txt");
+ assertThrows(() => {
+ Deno.consoleSize(file.rid);
+ }, Error);
+ file.close();
+});
+
+unitTest(function consoleSizeError(): void {
+ assertThrows(() => {
+ // Absurdly large rid.
+ Deno.consoleSize(0x7fffffff);
+ }, Deno.errors.BadResource);
+});
+
unitTest({ perms: { read: true } }, function isatty(): void {
// CI not under TTY, so cannot test stdin/stdout/stderr.
const f = Deno.openSync("cli/tests/hello.txt");