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




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

    modules: Implement console.clear()

 modules/console.cpp    | 22 +++++++++++++++++++++-
 modules/esm/console.js |  7 +++++++
 util/console.cpp       | 27 ++++++++++++++++++++++++++-
 util/console.h         |  1 +
 4 files changed, 55 insertions(+), 2 deletions(-)
---
diff --git a/modules/console.cpp b/modules/console.cpp
index 70d0b7a1..128fb942 100644
--- a/modules/console.cpp
+++ b/modules/console.cpp
@@ -277,6 +277,23 @@ gjs_console_interact(JSContext *context,
     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)
@@ -285,5 +302,8 @@ gjs_define_console_stuff(JSContext              *context,
     const GjsAtoms& atoms = GjsContextPrivate::atoms(context);
     return JS_DefineFunctionById(context, module, atoms.interact(),
                                  gjs_console_interact, 1,
-                                 GJS_MODULE_PROP_FLAGS);
+                                 GJS_MODULE_PROP_FLAGS) &&
+           JS_DefineFunction(context, module, "clearTerminal",
+                             gjs_console_clear_terminal, 1,
+                             GJS_MODULE_PROP_FLAGS);
 }
diff --git a/modules/esm/console.js b/modules/esm/console.js
index 6e19a8f8..04caced6 100644
--- a/modules/esm/console.js
+++ b/modules/esm/console.js
@@ -3,6 +3,8 @@
 
 import GLib from 'gi://GLib';
 
+const {clearTerminal} = import.meta.importSync('console');
+
 const sLogger = Symbol('Logger');
 const sPrinter = Symbol('Printer');
 const sFormatter = Symbol('Formatter');
@@ -149,6 +151,11 @@ class Console {
      */
     clear() {
         this[sGroupIndentation] = '';
+
+        try {
+            // clearTerminal will throw on unsupported platforms.
+            clearTerminal();
+        } catch {}
     }
 
     /**
diff --git a/util/console.cpp b/util/console.cpp
index 2323189a..43e120c0 100644
--- a/util/console.cpp
+++ b/util/console.cpp
@@ -11,10 +11,28 @@
 #    include <io.h>
 #endif
 
+#include <glib.h>
+
 #include "util/console.h"
 
 namespace Gjs {
 namespace Console {
+/**
+ * ANSI escape code sequences to manipulate terminals.
+ *
+ * See
+ * https://en.wikipedia.org/wiki/ANSI_escape_code#CSI_(Control_Sequence_Introducer)_sequences
+ */
+namespace ANSICode {
+/**
+ * ANSI escape code sequence to clear the terminal screen.
+ *
+ * Combination of 0x1B (Escape) and the sequence nJ where n=2,
+ * n=2 clears the entire display instead of only after the cursor.
+ */
+constexpr const char CLEAR_SCREEN[] = "\x1b[2J";
+
+}  // namespace ANSICode
 
 #ifdef HAVE_UNISTD_H
 const int stdin_fd = STDIN_FILENO;
@@ -40,5 +58,12 @@ bool is_tty(int fd) {
 #endif
 }
 
+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
\ No newline at end of file
+}  // namespace Gjs
diff --git a/util/console.h b/util/console.h
index 275c6c7c..7f4272b1 100644
--- a/util/console.h
+++ b/util/console.h
@@ -11,6 +11,7 @@ extern const int stdin_fd;
 extern const int stderr_fd;
 
 [[nodiscard]] bool is_tty(int fd = stdout_fd);
+[[nodiscard]] bool clear();
 
 };  // namespace Console
 };  // namespace Gjs


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