[gjs/107-connect-pretty-print] WIP: connect up prettyPrint() to console.interact and log
- From: Philip Chimento <pchimento src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gjs/107-connect-pretty-print] WIP: connect up prettyPrint() to console.interact and log
- Date: Sun, 21 Mar 2021 20:06:03 +0000 (UTC)
commit fee9abb2c3c2217eeaf77bfc6099e967613454d2
Author: Philip Chimento <philip chimento gmail com>
Date: Wed Mar 17 22:17:46 2021 -0700
WIP: connect up prettyPrint() to console.interact and log
gjs/atoms.h | 1 +
gjs/jsapi-util.cpp | 115 -----------------------------------
gjs/jsapi-util.h | 3 -
modules/console.cpp | 46 ++++++++++++--
modules/print.cpp | 16 ++---
modules/script/_bootstrap/default.js | 26 +++++++-
test/gjs-tests.cpp | 44 --------------
7 files changed, 76 insertions(+), 175 deletions(-)
---
diff --git a/gjs/atoms.h b/gjs/atoms.h
index 25c9904d..013b80be 100644
--- a/gjs/atoms.h
+++ b/gjs/atoms.h
@@ -72,6 +72,7 @@ class JSTracer;
#define FOR_EACH_SYMBOL_ATOM(macro) \
macro(hook_up_vfunc, "__GObject__hook_up_vfunc") \
+ macro(pretty_print, "__prettyPrint") \
macro(private_ns_marker, "__gjsPrivateNS") \
macro(signal_find, "__GObject__signal_find") \
macro(signals_block, "__GObject__signals_block") \
diff --git a/gjs/jsapi-util.cpp b/gjs/jsapi-util.cpp
index 6262ac2d..9f8d63c1 100644
--- a/gjs/jsapi-util.cpp
+++ b/gjs/jsapi-util.cpp
@@ -235,121 +235,6 @@ JSObject* gjs_define_string_array(JSContext* context,
return array;
}
-/**
- * gjs_string_readable:
- *
- * Return a string that can be read back by gjs-console; for
- * JS strings that contain valid Unicode, we return a UTF-8 formatted
- * string. Otherwise, we return one where non-ASCII-printable bytes
- * are \x escaped.
- *
- */
-[[nodiscard]] static std::string gjs_string_readable(JSContext* context,
- JS::HandleString string) {
- std::string buf(1, '"');
-
- JS::UniqueChars chars(JS_EncodeStringToUTF8(context, string));
- if (!chars) {
- /* I'm not sure this code will actually ever be reached except in the
- * case of OOM, since JS_EncodeStringToUTF8() seems to happily output
- * non-valid UTF-8 bytes. However, let's leave this in, since
- * SpiderMonkey may decide to do validation in the future. */
-
- /* Find out size of buffer to allocate, not counting 0-terminator */
- size_t len = JS_PutEscapedString(context, NULL, 0, string, '"');
- char *escaped = g_new(char, len + 1);
-
- JS_PutEscapedString(context, escaped, len, string, '"');
- buf += escaped;
- g_free(escaped);
- } else {
- buf += chars.get();
- }
-
- return buf + '"';
-}
-
-[[nodiscard]] static std::string _gjs_g_utf8_make_valid(const char* name) {
- const char *remainder, *invalid;
- int remaining_bytes, valid_bytes;
-
- g_return_val_if_fail (name != NULL, NULL);
-
- remainder = name;
- remaining_bytes = strlen (name);
-
- if (remaining_bytes == 0)
- return std::string(name);
-
- std::string buf;
- buf.reserve(remaining_bytes);
- while (remaining_bytes != 0) {
- if (g_utf8_validate (remainder, remaining_bytes, &invalid))
- break;
- valid_bytes = invalid - remainder;
-
- buf.append(remainder, valid_bytes);
- /* append U+FFFD REPLACEMENT CHARACTER */
- buf += "\357\277\275";
-
- remaining_bytes -= valid_bytes + 1;
- remainder = invalid + 1;
- }
-
- buf += remainder;
-
- g_assert(g_utf8_validate(buf.c_str(), -1, nullptr));
-
- return buf;
-}
-
-/**
- * gjs_value_debug_string:
- * @context:
- * @value: Any JavaScript value
- *
- * Returns: A UTF-8 encoded string describing @value
- */
-std::string gjs_value_debug_string(JSContext* context, JS::HandleValue value) {
- /* Special case debug strings for strings */
- if (value.isString()) {
- JS::RootedString str(context, value.toString());
- return gjs_string_readable(context, str);
- }
-
- JS::RootedString str(context, JS::ToString(context, value));
-
- if (!str) {
- JS_ClearPendingException(context);
- str = JS_ValueToSource(context, value);
- }
-
- if (!str) {
- if (value.isObject()) {
- /* Specifically the Call object (see jsfun.c in spidermonkey)
- * does not have a toString; there may be others also.
- */
- const JSClass *klass = JS_GetClass(&value.toObject());
- if (klass != NULL) {
- str = JS_NewStringCopyZ(context, klass->name);
- JS_ClearPendingException(context);
- if (!str)
- return "[out of memory copying class name]";
- } else {
- gjs_log_exception(context);
- return "[unknown object]";
- }
- } else {
- return "[unknown non-object]";
- }
- }
-
- g_assert(str);
-
- JS::UniqueChars bytes = JS_EncodeStringToUTF8(context, str);
- return _gjs_g_utf8_make_valid(bytes.get());
-}
-
/**
* gjs_log_exception_full:
* @cx: the #JSContext
diff --git a/gjs/jsapi-util.h b/gjs/jsapi-util.h
index 11c23776..447fa0fa 100644
--- a/gjs/jsapi-util.h
+++ b/gjs/jsapi-util.h
@@ -423,9 +423,6 @@ bool gjs_log_exception_uncaught(JSContext* cx);
bool gjs_log_exception_full(JSContext* cx, JS::HandleValue exc,
JS::HandleString message, GLogLevelFlags level);
-[[nodiscard]] std::string gjs_value_debug_string(JSContext* cx,
- JS::HandleValue value);
-
void gjs_warning_reporter(JSContext*, JSErrorReport* report);
GJS_JSAPI_RETURN_CONVENTION
diff --git a/modules/console.cpp b/modules/console.cpp
index 2ef511aa..4a270081 100644
--- a/modules/console.cpp
+++ b/modules/console.cpp
@@ -148,13 +148,27 @@ struct AutoCatchCtrlC {};
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,
- const std::string& bytes,
- int lineno) {
+[[nodiscard]] static bool gjs_console_eval_and_print(
+ JSContext* cx, JS::HandleObject global, JS::HandleObject pretty_print,
+ const std::string& bytes, int lineno) {
JS::SourceText<mozilla::Utf8Unit> source;
if (!source.init(cx, bytes.c_str(), bytes.size(),
JS::SourceOwnership::Borrowed))
@@ -175,7 +189,22 @@ struct AutoCatchCtrlC {};
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_global(cx, JS::ObjectValue(*global));
+ bool ok = JS::Call(cx, v_global, 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;
}
@@ -198,6 +227,12 @@ gjs_console_interact(JSContext *context,
JS::SetWarningReporter(context, gjs_console_warning_reporter);
+ JS::RootedObject pretty_print(context);
+ const GjsAtoms& atoms = GjsContextPrivate::atoms(context);
+ if (!gjs_object_require_property(context, global, "global",
+ atoms.pretty_print(), &pretty_print))
+ return false;
+
AutoCatchCtrlC ctrl_c;
// Separate initialization from declaration because of possible overwriting
@@ -253,7 +288,8 @@ 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, pretty_print,
+ buffer, startline);
}
exit_warning = false;
diff --git a/modules/print.cpp b/modules/print.cpp
index cb0f1e3b..0b6266a5 100644
--- a/modules/print.cpp
+++ b/modules/print.cpp
@@ -19,15 +19,11 @@
#include <js/Utility.h> // for UniqueChars
#include <jsapi.h>
+#include "gjs/atoms.h"
+#include "gjs/context-private.h"
#include "gjs/jsapi-util.h"
#include "modules/print.h"
-// Avoid static_assert in MSVC builds
-namespace JS {
-template <>
-struct GCPolicy<void*> : public IgnoreGCPolicy<void*> {};
-}
-
GJS_JSAPI_RETURN_CONVENTION
static bool gjs_log(JSContext* cx, unsigned argc, JS::Value* vp) {
JS::CallArgs argv = JS::CallArgsFromVp(argc, vp);
@@ -155,5 +151,11 @@ bool gjs_define_print_stuff(JSContext* context,
module.set(JS_NewPlainObject(context));
if (!module)
return false;
- return JS_DefineFunctions(context, module, funcs);
+
+ const GjsAtoms& atoms = GjsContextPrivate::atoms(context);
+ JS::RootedValue v_pretty_print_symbol(
+ context, JS::SymbolValue(atoms.pretty_print().toSymbol()));
+ return JS_DefineProperty(context, module, "prettyPrintSymbol",
+ v_pretty_print_symbol, GJS_MODULE_PROP_FLAGS) &&
+ JS_DefineFunctions(context, module, funcs);
}
diff --git a/modules/script/_bootstrap/default.js b/modules/script/_bootstrap/default.js
index 952d7fe3..ef98fd09 100644
--- a/modules/script/_bootstrap/default.js
+++ b/modules/script/_bootstrap/default.js
@@ -5,7 +5,25 @@
(function (exports) {
'use strict';
- const {print, printerr, log, logError} = imports._print;
+ const {
+ print,
+ printerr,
+ log: nativeLog,
+ logError: nativeLogError,
+ prettyPrintSymbol,
+ } = imports._print;
+
+ function prettyPrint(value) {
+ // to be filled in
+ }
+
+ function log(...args) {
+ return nativeLog(args.map(prettyPrint).join(' '));
+ }
+
+ function logError(e, ...args) {
+ return nativeLogError(e, args.map(prettyPrint).join(' '));
+ }
Object.defineProperties(exports, {
ARGV: {
@@ -40,5 +58,11 @@
writable: true,
value: logError,
},
+ [prettyPrintSymbol]: {
+ configurable: false,
+ enumerable: true,
+ writable: true,
+ value: prettyPrint,
+ },
});
})(globalThis);
diff --git a/test/gjs-tests.cpp b/test/gjs-tests.cpp
index e63fc430..84ff2a54 100644
--- a/test/gjs-tests.cpp
+++ b/test/gjs-tests.cpp
@@ -536,44 +536,6 @@ static void test_jsapi_util_string_to_ucs4(GjsUnitTestFixture* fx,
g_free(chars);
}
-static void test_jsapi_util_debug_string_valid_utf8(GjsUnitTestFixture* fx,
- const void*) {
- JS::RootedValue v_string(fx->cx);
- g_assert_true(gjs_string_from_utf8(fx->cx, VALID_UTF8_STRING, &v_string));
-
- std::string debug_output = gjs_value_debug_string(fx->cx, v_string);
-
- g_assert_cmpstr("\"" VALID_UTF8_STRING "\"", ==, debug_output.c_str());
-}
-
-static void test_jsapi_util_debug_string_invalid_utf8(GjsUnitTestFixture* fx,
- const void*) {
- g_test_skip("SpiderMonkey doesn't validate UTF-8 after encoding it");
-
- JS::RootedValue v_string(fx->cx);
- const char16_t invalid_unicode[] = { 0xffff, 0xffff };
- v_string.setString(JS_NewUCStringCopyN(fx->cx, invalid_unicode, 2));
-
- std::string debug_output = gjs_value_debug_string(fx->cx, v_string);
- // g_assert_cmpstr("\"\\xff\\xff\\xff\\xff\"", ==, debug_output.c_str());
-}
-
-static void test_jsapi_util_debug_string_object_with_complicated_to_string(
- GjsUnitTestFixture* fx, const void*) {
- const char16_t desserts[] = {
- 0xd83c, 0xdf6a, /* cookie */
- 0xd83c, 0xdf69, /* doughnut */
- };
- JS::RootedValueArray<2> contents(fx->cx);
- contents[0].setString(JS_NewUCStringCopyN(fx->cx, desserts, 2));
- contents[1].setString(JS_NewUCStringCopyN(fx->cx, desserts + 2, 2));
- JS::RootedObject array(fx->cx, JS::NewArrayObject(fx->cx, contents));
- JS::RootedValue v_array(fx->cx, JS::ObjectValue(*array));
- std::string debug_output = gjs_value_debug_string(fx->cx, v_array);
-
- g_assert_cmpstr(u8"🍪,🍩", ==, debug_output.c_str());
-}
-
static void
gjstest_test_func_util_misc_strv_concat_null(void)
{
@@ -919,12 +881,6 @@ main(int argc,
test_jsapi_util_string_char16_data);
ADD_JSAPI_UTIL_TEST("string/to_ucs4",
test_jsapi_util_string_to_ucs4);
- ADD_JSAPI_UTIL_TEST("debug_string/valid-utf8",
- test_jsapi_util_debug_string_valid_utf8);
- ADD_JSAPI_UTIL_TEST("debug_string/invalid-utf8",
- test_jsapi_util_debug_string_invalid_utf8);
- ADD_JSAPI_UTIL_TEST("debug_string/object-with-complicated-to-string",
- test_jsapi_util_debug_string_object_with_complicated_to_string);
ADD_JSAPI_UTIL_TEST("gi/args/safe-integer/max",
gjstest_test_safe_integer_max);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]