[gjs/ewlsh/nova-repl: 1/2] Refactor console utilities
- From: Evan Welsh <ewlsh src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gjs/ewlsh/nova-repl: 1/2] Refactor console utilities
- Date: Sun, 30 Jan 2022 03:08:39 +0000 (UTC)
commit 6543784ba853f9845ce88ad910a89fcdafcf7b2f
Author: Evan Welsh <contact evanwelsh com>
Date: Sat Jan 29 19:05:36 2022 -0800
Refactor console utilities
gjs/debugger.cpp | 4 +--
libgjs-private/gjs-util.c | 13 ---------
meson.build | 1 +
modules/console.cpp | 39 ++++++++++++++++++++-------
modules/esm/console.js | 5 ++--
util/console.cpp | 67 +++++++++++++++++++++++++++++++++++++++++++++--
util/console.h | 33 +++++++++++------------
7 files changed, 116 insertions(+), 46 deletions(-)
---
diff --git a/gjs/debugger.cpp b/gjs/debugger.cpp
index 310fa3843..282e43c23 100644
--- a/gjs/debugger.cpp
+++ b/gjs/debugger.cpp
@@ -59,7 +59,7 @@ static bool do_readline(JSContext* cx, unsigned argc, JS::Value* vp) {
do {
const char* real_prompt = prompt ? prompt.get() : "db> ";
#ifdef HAVE_READLINE_READLINE_H
- if (gjs_console_is_tty(stdin_fd)) {
+ if (Gjs::Console::is_tty(Gjs::Console::stdin_fd)) {
line = readline(real_prompt);
} else {
#else
@@ -72,7 +72,7 @@ static bool do_readline(JSContext* cx, unsigned argc, JS::Value* vp) {
buf[0] = '\0';
line.reset(g_strdup(g_strchomp(buf)));
- if (!gjs_console_is_tty(stdin_fd)) {
+ if (!Gjs::Console::is_tty(Gjs::Console::stdin_fd)) {
if (feof(stdin)) {
g_print("[quit due to end of input]\n");
line.reset(g_strdup("quit"));
diff --git a/libgjs-private/gjs-util.c b/libgjs-private/gjs-util.c
index afae2988f..c2399b803 100644
--- a/libgjs-private/gjs-util.c
+++ b/libgjs-private/gjs-util.c
@@ -17,7 +17,6 @@
#include <glib/gi18n.h> /* for bindtextdomain, bind_textdomain_codeset, textdomain */
#include "libgjs-private/gjs-util.h"
-#include "util/console.h"
char *
gjs_format_int_alternative_output(int n)
@@ -325,15 +324,3 @@ void gjs_log_set_writer_func(GjsGLogWriterFunc func, void* user_data,
g_log_set_writer_func(gjs_log_writer_func_wrapper, func, NULL);
}
-
-/**
- * gjs_clear_terminal:
- *
- * Clears the terminal, if possible.
- */
-void gjs_clear_terminal(void) {
- if (!gjs_console_is_tty(stdout_fd))
- return;
-
- gjs_console_clear();
-}
diff --git a/meson.build b/meson.build
index 136e812b3..0d4d54a99 100644
--- a/meson.build
+++ b/meson.build
@@ -334,6 +334,7 @@ if build_readline
endif
header_conf.set('USE_UNITY_BUILD', get_option('unity'))
header_conf.set('HAVE_SYS_SYSCALL_H', cxx.check_header('sys/syscall.h'))
+header_conf.set('HAVE_TERMIOS_H', cxx.check_header('termios.h'))
header_conf.set('HAVE_UNISTD_H', cxx.check_header('unistd.h'))
header_conf.set('HAVE_SIGNAL_H', cxx.check_header('signal.h',
required: build_profiler))
diff --git a/modules/console.cpp b/modules/console.cpp
index e54554b6d..c21942490 100644
--- a/modules/console.cpp
+++ b/modules/console.cpp
@@ -274,13 +274,34 @@ gjs_console_interact(JSContext *context,
return true;
}
-bool
-gjs_define_console_stuff(JSContext *context,
- JS::MutableHandleObject module)
-{
- module.set(JS_NewPlainObject(context));
- const GjsAtoms& atoms = GjsContextPrivate::atoms(context);
- return JS_DefineFunctionById(context, module, atoms.interact(),
- gjs_console_interact, 1,
- GJS_MODULE_PROP_FLAGS);
+GJS_JSAPI_RETURN_CONVENTION
+static bool gjs_console_clear_terminal(JSContext* cx, unsigned argc,
+ JS::Value* vp) {
+ JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+ if (!gjs_parse_call_args(cx, "clearTerminal", args, ""))
+ return false;
+
+ if (!Gjs::Console::is_tty(Gjs::Console::stdout_fd)) {
+ args.rval().setBoolean(false);
+ return true;
+ }
+
+ args.rval().setBoolean(Gjs::Console::clear());
+ return true;
+}
+
+static JSFunctionSpec console_module_funcs[] = {
+ JS_FN("clearTerminal", gjs_console_clear_terminal, 1,
+ GJS_MODULE_PROP_FLAGS),
+ JS_FN("interact", gjs_console_interact, 1, GJS_MODULE_PROP_FLAGS),
+ JS_FS_END,
+};
+
+bool gjs_define_console_private_stuff(JSContext* cx,
+ JS::MutableHandleObject module) {
+ module.set(JS_NewPlainObject(cx));
+ if (!module)
+ return false;
+
+ return JS_DefineFunctions(cx, module, console_module_funcs);
}
diff --git a/modules/esm/console.js b/modules/esm/console.js
index bdbfc69dd..210298c1e 100644
--- a/modules/esm/console.js
+++ b/modules/esm/console.js
@@ -2,7 +2,8 @@
// SPDX-FileCopyrightText: 2021 Evan Welsh <contact evanwelsh com>
import GLib from 'gi://GLib';
-import GjsPrivate from 'gi://GjsPrivate';
+
+const NativeConsole = import.meta.importSync('_consoleNative');
const sLogger = Symbol('Logger');
const sPrinter = Symbol('Printer');
@@ -151,7 +152,7 @@ class Console {
*/
clear() {
this[sGroupIndentation] = '';
- GjsPrivate.clear_terminal();
+ NativeConsole.clearTerminal();
}
/**
diff --git a/util/console.cpp b/util/console.cpp
index 76451ce11..82ddcc098 100644
--- a/util/console.cpp
+++ b/util/console.cpp
@@ -37,6 +37,9 @@ constexpr const char CLEAR_SCREEN[] = "\x1b[2J";
} // namespace ANSICode
+namespace Gjs {
+namespace Console {
+
#ifdef HAVE_UNISTD_H
const int stdin_fd = STDIN_FILENO;
const int stdout_fd = STDOUT_FILENO;
@@ -51,7 +54,64 @@ const int stdout_fd = 1;
const int stderr_fd = 2;
#endif
-bool gjs_console_is_tty(int fd) {
+#ifdef HAVE_TERMIOS_H
+struct termios saved_termios;
+#endif
+
+bool disable_raw_mode() {
+#ifdef HAVE_TERMIOS_H
+ return tcsetattr(stdin_fd, TCSAFLUSH, &saved_termios) != -1;
+#else
+ return false;
+#endif
+}
+
+void _disable_raw_mode() {
+ void* _ [[maybe_unused]] = reinterpret_cast<void*>(disable_raw_mode());
+}
+
+bool enable_raw_mode() {
+#ifdef HAVE_TERMIOS_H
+ // Save the current terminal flags to reset later
+ if (tcgetattr(stdin_fd, &saved_termios) == -1) {
+ if (disable_raw_mode())
+ return false;
+
+ return false;
+ }
+
+ // Register an exit handler to restore
+ // the terminal modes on exit.
+ atexit(_disable_raw_mode);
+
+ struct termios raw = saved_termios;
+ // - Disable \r to \n conversion on input
+ // - Disable parity checking
+ // - Disable stripping characters to 7-bits
+ // - Disable START/STOP characters
+ // https://www.gnu.org/software/libc/manual/html_node/Input-Modes.html
+ raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
+ // Enforce 8-bit characters
+ // https://www.gnu.org/software/libc/manual/html_node/Control-Modes.html
+ raw.c_cflag |= (CS8);
+ // Disable echoing (terminal reprinting input)
+ // Disable canonical mode (output reflects input)
+ // Disable "extensions" that allow users to inject
+ // Disable C signal handling
+ // https://www.gnu.org/software/libc/manual/html_node/Other-Special.html
+ raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
+ // Set 0 characters required for a read
+ raw.c_cc[VMIN] = 0;
+ // Set the read timeout to 1 decisecond (0.1 seconds)
+ raw.c_cc[VTIME] = 1;
+
+ return tcsetattr(stdin_fd, TCSAFLUSH, &raw) != -1;
+#else
+ return false;
+#endif
+}
+
+bool is_tty(int fd) {
#ifdef HAVE_UNISTD_H
return isatty(fd);
#elif defined(_WIN32)
@@ -61,9 +121,12 @@ bool gjs_console_is_tty(int fd) {
#endif
}
-bool gjs_console_clear() {
+bool clear() {
if (stdout_fd < 0 || !g_log_writer_supports_color(stdout_fd))
return false;
return fputs(ANSICode::CLEAR_SCREEN, stdout) > 0 && fflush(stdout) > 0;
}
+
+} // namespace Console
+} // namespace Gjs
diff --git a/util/console.h b/util/console.h
index df27f305e..306721ed2 100644
--- a/util/console.h
+++ b/util/console.h
@@ -1,31 +1,28 @@
-/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
-/*
- * SPDX-License-Identifier: MIT OR LGPL-2.0-or-later
- * SPDX-FileCopyrightText: 2021 Evan Welsh <contact evanwelsh com>
- */
+// SPDX-License-Identifier: MIT OR LGPL-2.0-or-later
+// SPDX-FileCopyrightText: 2021 Evan Welsh <contact evanwelsh com>
#ifndef UTIL_CONSOLE_H_
#define UTIL_CONSOLE_H_
-/* This file has to be valid C, because it's used in libgjs-private */
-
-#include <stdbool.h> /* IWYU pragma: keep */
-
-#include <glib.h>
-
-#include "gjs/macros.h"
-
-G_BEGIN_DECLS
+#include <config.h>
+namespace Gjs {
+namespace Console {
extern const int stdout_fd;
extern const int stdin_fd;
extern const int stderr_fd;
-GJS_USE
-bool gjs_console_is_tty(int fd);
+[[nodiscard]] bool is_tty(int fd = stdout_fd);
+
+[[nodiscard]] bool clear();
+
+[[nodiscard]] bool enable_raw_mode();
+
+[[nodiscard]] bool disable_raw_mode();
-bool gjs_console_clear(void);
+[[nodiscard]] bool get_size(int* width, int* height);
-G_END_DECLS
+}; // namespace Console
+}; // namespace Gjs
#endif // UTIL_CONSOLE_H_
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]