[gjs/ewlsh/whatwg-console: 3/4] modules: Implement console.clear()




commit 6a62be3a28e0d13b22fefd7ded1215184007d744
Author: Evan Welsh <contact evanwelsh com>
Date:   Tue Jun 29 01:07:13 2021 -0700

    modules: Implement console.clear()

 meson.build            | 11 +++++++++++
 modules/console.cpp    | 28 ++++++++++++++++++++++++++++
 modules/esm/console.js |  9 ++++++---
 util/console.cpp       | 18 ++++++++++++++++++
 util/console.h         |  2 ++
 5 files changed, 65 insertions(+), 3 deletions(-)
---
diff --git a/meson.build b/meson.build
index dfd5a935..09dd1249 100644
--- a/meson.build
+++ b/meson.build
@@ -124,6 +124,11 @@ gi = dependency('gobject-introspection-1.0', version: '>= 1.66.0',
     fallback: ['gobject-introspection', 'girepo_dep'])
 spidermonkey = dependency('mozjs-78', version: '>= 78.2.0')
 
+gio_unix = dependency('gio-unix-2.0', version: glib_required_version,
+    required: false)
+
+has_gio_unix = gio_unix.found()
+
 # We might need to look for the headers and lib's for Cairo
 # manually on MSVC/clang-cl builds...
 cairo = dependency('cairo', required: get_option('cairo').enabled() and cxx.get_argument_syntax() != 'msvc')
@@ -313,6 +318,8 @@ header_conf.set('HAVE_SIGNAL_H', cxx.check_header('signal.h',
 # enable GNU extensions on systems that have them
 header_conf.set('_GNU_SOURCE', 1)
 
+header_conf.set('HAVE_GIO_UNIX', has_gio_unix)
+
 configure_file(output: 'config.h', configuration: header_conf)
 
 ### Check for environment ######################################################
@@ -485,6 +492,10 @@ if build_readline
     libgjs_dependencies += readline_deps
 endif
 
+if has_gio_unix
+    libgjs_dependencies += gio_unix
+endif
+
 libgjs_cpp_args = ['-DGJS_COMPILATION'] + directory_defines
 
 # Check G-I and/or Meson on this one.
diff --git a/modules/console.cpp b/modules/console.cpp
index 5e4f9405..30a7d3c6 100644
--- a/modules/console.cpp
+++ b/modules/console.cpp
@@ -39,6 +39,13 @@
 #include <glib.h>
 #include <glib/gprintf.h>  // for g_fprintf
 
+#ifdef HAVE_GIO_UNIX
+#    include <gio/gio.h>
+#    include <gio/gunixoutputstream.h>  // IWYU pragma: keep
+#    include <glib-object.h>
+#    include <string.h>
+#endif
+
 #include <js/CallArgs.h>
 #include <js/CompilationAndEvaluation.h>
 #include <js/CompileOptions.h>
@@ -316,6 +323,24 @@ bool gjs_console_get_terminal_size(JSContext* cx, unsigned argc,
     return true;
 }
 
+
+bool gjs_console_clear_terminal(JSContext* cx, unsigned argc, JS::Value* vp) {
+    JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+
+    if (!Gjs::Console::is_tty()) {
+        gjs_throw(cx, "Output is not a tty.");
+        return false;
+    }
+
+    if (!Gjs::Console::clear()) {
+        gjs_throw(cx, "Output does not support ANSI escape codes.");
+        return false;
+    }
+
+    args.rval().setUndefined();
+    return true;
+}
+
 bool
 gjs_define_console_stuff(JSContext              *context,
                          JS::MutableHandleObject module)
@@ -325,6 +350,9 @@ gjs_define_console_stuff(JSContext              *context,
     return JS_DefineFunction(context, module, "getTerminalSize",
                              gjs_console_get_terminal_size, 1,
                              GJS_MODULE_PROP_FLAGS) &&
+           JS_DefineFunction(context, module, "clearTerminal",
+                             gjs_console_clear_terminal, 1,
+                             GJS_MODULE_PROP_FLAGS) &&
            JS_DefineFunctionById(context, module, atoms.interact(),
                                  gjs_console_interact, 1,
                                  GJS_MODULE_PROP_FLAGS);
diff --git a/modules/esm/console.js b/modules/esm/console.js
index 6a9c6481..a72c8755 100644
--- a/modules/esm/console.js
+++ b/modules/esm/console.js
@@ -9,11 +9,11 @@
 // @ts-expect-error
 import GLib from 'gi://GLib';
 
-const {getTerminalSize: getNativeTerminalSize } =
+const {getTerminalSize: getNativeTerminalSize, clearTerminal} =
     // @ts-expect-error
     import.meta.importSync('console');
 
-export { getNativeTerminalSize };
+export {getNativeTerminalSize};
 
 /**
  * @typedef TerminalSize
@@ -174,7 +174,10 @@ export class Console {
 
     // 1.1.2 clear()
     clear() {
-        throw new Error('clear() is not implemented.');
+        try {
+            // clearTerminal can throw Gio-related errors.
+            clearTerminal();
+        } catch {}
     }
 
     // 1.1.3 debug(...data)
diff --git a/util/console.cpp b/util/console.cpp
index 323ed108..71831b5f 100644
--- a/util/console.cpp
+++ b/util/console.cpp
@@ -60,6 +60,24 @@ bool Gjs::Console::is_tty(int fd) {
 #endif
 }
 
+bool Gjs::Console::supports_ansi() {
+#ifdef _WIN32
+    DWORD mode;
+    GetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), &mode);
+    return mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING == mode;
+#else
+    // For now we'll assume all TTYs on other operating systems support ANSI.
+    return is_tty(stdout_fd);
+#endif
+}
+
+bool Gjs::Console::clear() {
+    if (stdout_fd < 0 || !supports_ansi())
+        return false;
+
+    return fputs(ANSICode::ESCAPE, stdout) > 0 && fflush(stdout) > 0;
+}
+
 void Gjs::Console::size(int* width, int* height) {
     {
         const char* lines = g_getenv("LINES");
diff --git a/util/console.h b/util/console.h
index 9facf313..dbed98e0 100644
--- a/util/console.h
+++ b/util/console.h
@@ -11,6 +11,8 @@ extern const int stdin_fd;
 extern const int stderr_fd;
 
 [[nodiscard]] bool is_tty(int fd = stdout_fd);
+[[nodiscard]] bool supports_ansi();
+[[nodiscard]] bool clear();
 void size(int* width, int* height);
 
 };  // namespace Console


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]