summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
authorPhilip Chimento <philip.chimento@gmail.com>2021-03-17 22:17:46 -0700
committerNasah Kuma <nasahnash19@gmail.com>2022-02-25 02:35:12 +0100
commit410748846ee9b34db67d84abf95b6c7b7cac75a6 (patch)
treebb52b894b4951d2a27c06c5c9afa1ddaa437f439 /modules
parentbec10836b3f571b3e8bcabb34ae577f3f83c4f17 (diff)
downloadgjs-410748846ee9b34db67d84abf95b6c7b7cac75a6.tar.gz
print: Connect up prettyPrint() to Console.interact() and log()
It makes sense for the prettyPrint() function to be written in JS, but it does need to be called internally in Console.interact() which is written in C++. Therefore, create a slot on the global object in which to store the prettyPrint() function, which can be retrieved when needing to call the function from internal code. Console.interact() no longer needs to use gjs_value_debug_string(), so that code and its dependencies can be removed. Also pass the arguments of log() and logError() through prettyPrint(). This enables the work from #107.
Diffstat (limited to 'modules')
-rw-r--r--modules/console.cpp40
-rw-r--r--modules/print.cpp28
-rw-r--r--modules/script/_bootstrap/default.js19
3 files changed, 84 insertions, 3 deletions
diff --git a/modules/console.cpp b/modules/console.cpp
index e54554b6..f92d63d0 100644
--- a/modules/console.cpp
+++ b/modules/console.cpp
@@ -28,6 +28,7 @@
#include <glib/gprintf.h> // for g_fprintf
#include <js/CallArgs.h>
+#include <js/CharacterEncoding.h> // for JS_EncodeStringToUTF8
#include <js/CompilationAndEvaluation.h>
#include <js/CompileOptions.h>
#include <js/ErrorReport.h>
@@ -35,11 +36,15 @@
#include <js/RootingAPI.h>
#include <js/SourceText.h>
#include <js/TypeDecls.h>
+#include <js/Utility.h> // for UniqueChars
+#include <js/Value.h>
+#include <js/ValueArray.h>
#include <js/Warnings.h>
#include <jsapi.h> // for JS_IsExceptionPending, Exce...
#include "gjs/atoms.h"
#include "gjs/context-private.h"
+#include "gjs/global.h"
#include "gjs/jsapi-util.h"
#include "modules/console.h"
@@ -146,11 +151,26 @@ sigjmp_buf AutoCatchCtrlC::jump_buffer;
return true;
}
+std::string print_string_value(JSContext* cx, JS::HandleValue v_string) {
+ if (!v_string.isString())
+ return "[unexpected result from printing value]";
+
+ JS::RootedString printed_string(cx, v_string.toString());
+ JS::AutoSaveExceptionState exc_state(cx);
+ JS::UniqueChars chars(JS_EncodeStringToUTF8(cx, printed_string));
+ exc_state.restore();
+ if (!chars)
+ return "[error printing value]";
+
+ return chars.get();
+}
+
/* Return value of false indicates an uncatchable exception, rather than any
* exception. (This is because the exception should be auto-printed around the
* invocation of this function.)
*/
[[nodiscard]] static bool gjs_console_eval_and_print(JSContext* cx,
+ JS::HandleObject global,
const std::string& bytes,
int lineno) {
JS::SourceText<mozilla::Utf8Unit> source;
@@ -173,7 +193,23 @@ sigjmp_buf AutoCatchCtrlC::jump_buffer;
if (result.isUndefined())
return true;
- g_fprintf(stdout, "%s\n", gjs_value_debug_string(cx, result).c_str());
+ JS::AutoSaveExceptionState exc_state(cx);
+ JS::RootedValue v_printed_string(cx);
+ JS::RootedValue v_pretty_print(
+ cx, gjs_get_global_slot(global, GjsGlobalSlot::PRETTY_PRINT_FUNC));
+ bool ok = JS::Call(cx, global, v_pretty_print, JS::HandleValueArray(result),
+ &v_printed_string);
+ if (!ok)
+ gjs_log_exception(cx);
+ exc_state.restore();
+
+ if (ok) {
+ g_fprintf(stdout, "%s\n",
+ print_string_value(cx, v_printed_string).c_str());
+ } else {
+ g_fprintf(stdout, "[error printing value]\n");
+ }
+
return true;
}
@@ -251,7 +287,7 @@ gjs_console_interact(JSContext *context,
bool ok;
{
AutoReportException are(context);
- ok = gjs_console_eval_and_print(context, buffer, startline);
+ ok = gjs_console_eval_and_print(context, global, buffer, startline);
}
exit_warning = false;
diff --git a/modules/print.cpp b/modules/print.cpp
index ad39058b..2b07a27b 100644
--- a/modules/print.cpp
+++ b/modules/print.cpp
@@ -17,8 +17,10 @@
#include <js/RootingAPI.h>
#include <js/TypeDecls.h>
#include <js/Utility.h> // for UniqueChars
+#include <js/Value.h>
#include <jsapi.h>
+#include "gjs/global.h"
#include "gjs/jsapi-util.h"
#include "modules/print.h"
@@ -135,12 +137,38 @@ static bool gjs_printerr(JSContext* context, unsigned argc, JS::Value* vp) {
return true;
}
+// The pretty-print functionality is best written in JS, but needs to be used
+// from C++ code. This stores the prettyPrint() function in a slot on the global
+// object so that it can be used internally by the Console module.
+// This function is not available to user code.
+GJS_JSAPI_RETURN_CONVENTION
+static bool set_pretty_print_function(JSContext*, unsigned argc,
+ JS::Value* vp) {
+ JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+
+ // can only be called internally, so OK to assert correct arguments
+ g_assert(args.length() == 2 && "setPrettyPrintFunction takes 2 arguments");
+
+ JS::Value v_global = args[0];
+ JS::Value v_func = args[1];
+
+ g_assert(v_global.isObject() && "first argument must be an object");
+ g_assert(v_func.isObject() && "second argument must be an object");
+
+ gjs_set_global_slot(&v_global.toObject(), GjsGlobalSlot::PRETTY_PRINT_FUNC,
+ v_func);
+
+ args.rval().setUndefined();
+ return true;
+}
+
// clang-format off
static constexpr JSFunctionSpec funcs[] = {
JS_FN("log", gjs_log, 1, GJS_MODULE_PROP_FLAGS),
JS_FN("logError", gjs_log_error, 2, GJS_MODULE_PROP_FLAGS),
JS_FN("print", gjs_print, 0, GJS_MODULE_PROP_FLAGS),
JS_FN("printerr", gjs_printerr, 0, GJS_MODULE_PROP_FLAGS),
+ JS_FN("setPrettyPrintFunction", set_pretty_print_function, 1, GJS_MODULE_PROP_FLAGS),
JS_FS_END};
// clang-format on
diff --git a/modules/script/_bootstrap/default.js b/modules/script/_bootstrap/default.js
index 952d7fe3..7d77a2cd 100644
--- a/modules/script/_bootstrap/default.js
+++ b/modules/script/_bootstrap/default.js
@@ -5,7 +5,23 @@
(function (exports) {
'use strict';
- const {print, printerr, log, logError} = imports._print;
+ const {
+ print,
+ printerr,
+ log: nativeLog,
+ logError: nativeLogError,
+ setPrettyPrintFunction,
+ } = imports._print;
+
+ function log(...args) {
+ return nativeLog(args.map(prettyPrint).join(' '));
+ }
+
+ function logError(e, ...args) {
+ if (args.length === 0)
+ return nativeLogError(e);
+ return nativeLogError(e, args.map(prettyPrint).join(' '));
+ }
Object.defineProperties(exports, {
ARGV: {
@@ -41,4 +57,5 @@
value: logError,
},
});
+ setPrettyPrintFunction(exports, prettyPrint);
})(globalThis);