summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIdan Horowitz <idan.horowitz@gmail.com>2021-11-23 22:46:28 +0200
committerLinus Groh <mail@linusgroh.de>2021-11-24 18:05:24 +0000
commit11d1950e742a6a2ec11e852e644e24682cd5072e (patch)
tree8fba36915b0a3d01d5848f43617ae56236e47e86
parentc7d2df45b9dfe754eb9adfadbf42b24d48349a13 (diff)
downloadserenity-11d1950e742a6a2ec11e852e644e24682cd5072e.zip
js: Add command line flag for disabling ANSI colors
-rw-r--r--Base/usr/share/man/man1/js.md1
-rw-r--r--Userland/Utilities/js.cpp342
2 files changed, 193 insertions, 150 deletions
diff --git a/Base/usr/share/man/man1/js.md b/Base/usr/share/man/man1/js.md
index 4aaab8236e..0d797df1b9 100644
--- a/Base/usr/share/man/man1/js.md
+++ b/Base/usr/share/man/man1/js.md
@@ -28,6 +28,7 @@ Run `help()` in REPL mode to see its available built-in functions.
* `-m`, `--as-module`: Treat as module
* `-l`, `--print-last-result`: Print the result of the last statement executed.
* `-g`, `--gc-on-every-allocation`: Run garbage collection on every allocation.
+* `-c`, `--disable-ansi-colors`: Disable ANSI colors
* `-s`, `--no-syntax-highlight`: Disable live syntax highlighting in the REPL
## Examples
diff --git a/Userland/Utilities/js.cpp b/Userland/Utilities/js.cpp
index 7eef2531b3..d5a10ee759 100644
--- a/Userland/Utilities/js.cpp
+++ b/Userland/Utilities/js.cpp
@@ -104,6 +104,7 @@ static bool s_run_bytecode = false;
static bool s_opt_bytecode = false;
static bool s_as_module = false;
static bool s_print_last_result = false;
+static bool s_strip_ansi = false;
static RefPtr<Line::Editor> s_editor;
static String s_history_path = String::formatted("{}/.js-history", Core::StandardPaths::home_directory());
static int s_repl_line_level = 0;
@@ -193,22 +194,62 @@ static String read_next_piece()
return piece.to_string();
}
+static String strip_ansi(StringView format_string)
+{
+ if (format_string.is_empty())
+ return String::empty();
+
+ StringBuilder builder;
+ size_t i;
+ for (i = 0; i < format_string.length() - 1; ++i) {
+ if (format_string[i] == '\033' && format_string[i + 1] == '[') {
+ while (i < format_string.length() && format_string[i] != 'm')
+ ++i;
+ } else {
+ builder.append(format_string[i]);
+ }
+ }
+ if (i < format_string.length())
+ builder.append(format_string[i]);
+ return builder.to_string();
+}
+
+template<typename... Parameters>
+static void js_out(CheckedFormatString<Parameters...>&& fmtstr, const Parameters&... parameters)
+{
+ if (!s_strip_ansi)
+ return out(move(fmtstr), parameters...);
+ auto stripped_fmtstr = strip_ansi(fmtstr.view());
+ out(stripped_fmtstr, parameters...);
+}
+
+template<typename... Parameters>
+static void js_outln(CheckedFormatString<Parameters...>&& fmtstr, const Parameters&... parameters)
+{
+ if (!s_strip_ansi)
+ return outln(move(fmtstr), parameters...);
+ auto stripped_fmtstr = strip_ansi(fmtstr.view());
+ outln(stripped_fmtstr, parameters...);
+}
+
+inline void js_outln() { outln(); }
+
static void print_value(JS::Value value, HashTable<JS::Object*>& seen_objects);
static void print_type(FlyString const& name)
{
- out("[\033[36;1m{}\033[0m]", name);
+ js_out("[\033[36;1m{}\033[0m]", name);
}
static void print_separator(bool& first)
{
- out(first ? " " : ", ");
+ js_out(first ? " " : ", ");
first = false;
}
static void print_array(JS::Array& array, HashTable<JS::Object*>& seen_objects)
{
- out("[");
+ js_out("[");
bool first = true;
for (auto it = array.indexed_properties().begin(false); it != array.indexed_properties().end(); ++it) {
print_separator(first);
@@ -222,17 +263,17 @@ static void print_array(JS::Array& array, HashTable<JS::Object*>& seen_objects)
print_value(value, seen_objects);
}
if (!first)
- out(" ");
- out("]");
+ js_out(" ");
+ js_out("]");
}
static void print_object(JS::Object& object, HashTable<JS::Object*>& seen_objects)
{
- out("{{");
+ js_out("{{");
bool first = true;
for (auto& entry : object.indexed_properties()) {
print_separator(first);
- out("\"\033[33;1m{}\033[0m\": ", entry.index());
+ js_out("\"\033[33;1m{}\033[0m\": ", entry.index());
auto value_or_error = object.get(entry.index());
// The V8 repl doesn't throw an exception here, and instead just
// prints 'undefined'. We may choose to replicate that behavior in
@@ -245,30 +286,30 @@ static void print_object(JS::Object& object, HashTable<JS::Object*>& seen_object
for (auto& it : object.shape().property_table_ordered()) {
print_separator(first);
if (it.key.is_string()) {
- out("\"\033[33;1m{}\033[0m\": ", it.key.to_display_string());
+ js_out("\"\033[33;1m{}\033[0m\": ", it.key.to_display_string());
} else {
- out("[\033[33;1m{}\033[0m]: ", it.key.to_display_string());
+ js_out("[\033[33;1m{}\033[0m]: ", it.key.to_display_string());
}
print_value(object.get_direct(it.value.offset), seen_objects);
}
if (!first)
- out(" ");
- out("}}");
+ js_out(" ");
+ js_out("}}");
}
static void print_function(JS::Object const& object, HashTable<JS::Object*>&)
{
print_type(object.class_name());
if (is<JS::ECMAScriptFunctionObject>(object))
- out(" {}", static_cast<JS::ECMAScriptFunctionObject const&>(object).name());
+ js_out(" {}", static_cast<JS::ECMAScriptFunctionObject const&>(object).name());
else if (is<JS::NativeFunction>(object))
- out(" {}", static_cast<JS::NativeFunction const&>(object).name());
+ js_out(" {}", static_cast<JS::NativeFunction const&>(object).name());
}
static void print_date(JS::Object const& object, HashTable<JS::Object*>&)
{
print_type("Date");
- out(" \033[34;1m{}\033[0m", static_cast<JS::Date const&>(object).string());
+ js_out(" \033[34;1m{}\033[0m", static_cast<JS::Date const&>(object).string());
}
static void print_error(JS::Object const& object, HashTable<JS::Object*>& seen_objects)
@@ -282,7 +323,7 @@ static void print_error(JS::Object const& object, HashTable<JS::Object*>& seen_o
auto message_string = message.to_string_without_side_effects();
print_type(name_string);
if (!message_string.is_empty())
- out(" \033[31;1m{}\033[0m", message_string);
+ js_out(" \033[31;1m{}\033[0m", message_string);
}
}
@@ -290,16 +331,16 @@ static void print_regexp_object(JS::Object const& object, HashTable<JS::Object*>
{
auto& regexp_object = static_cast<JS::RegExpObject const&>(object);
print_type("RegExp");
- out(" \033[34;1m/{}/{}\033[0m", regexp_object.escape_regexp_pattern(), regexp_object.flags());
+ js_out(" \033[34;1m/{}/{}\033[0m", regexp_object.escape_regexp_pattern(), regexp_object.flags());
}
static void print_proxy_object(JS::Object const& object, HashTable<JS::Object*>& seen_objects)
{
auto& proxy_object = static_cast<JS::ProxyObject const&>(object);
print_type("Proxy");
- out("\n target: ");
+ js_out("\n target: ");
print_value(&proxy_object.target(), seen_objects);
- out("\n handler: ");
+ js_out("\n handler: ");
print_value(&proxy_object.handler(), seen_objects);
}
@@ -308,17 +349,17 @@ static void print_map(JS::Object const& object, HashTable<JS::Object*>& seen_obj
auto& map = static_cast<JS::Map const&>(object);
auto& entries = map.entries();
print_type("Map");
- out(" {{");
+ js_out(" {{");
bool first = true;
for (auto& entry : entries) {
print_separator(first);
print_value(entry.key, seen_objects);
- out(" => ");
+ js_out(" => ");
print_value(entry.value, seen_objects);
}
if (!first)
- out(" ");
- out("}}");
+ js_out(" ");
+ js_out("}}");
}
static void print_set(JS::Object const& object, HashTable<JS::Object*>& seen_objects)
@@ -326,15 +367,15 @@ static void print_set(JS::Object const& object, HashTable<JS::Object*>& seen_obj
auto& set = static_cast<JS::Set const&>(object);
auto& values = set.values();
print_type("Set");
- out(" {{");
+ js_out(" {{");
bool first = true;
for (auto& value : values) {
print_separator(first);
print_value(value, seen_objects);
}
if (!first)
- out(" ");
- out("}}");
+ js_out(" ");
+ js_out("}}");
}
static void print_promise(JS::Object const& object, HashTable<JS::Object*>& seen_objects)
@@ -343,19 +384,19 @@ static void print_promise(JS::Object const& object, HashTable<JS::Object*>& seen
print_type("Promise");
switch (promise.state()) {
case JS::Promise::State::Pending:
- out("\n state: ");
- out("\033[36;1mPending\033[0m");
+ js_out("\n state: ");
+ js_out("\033[36;1mPending\033[0m");
break;
case JS::Promise::State::Fulfilled:
- out("\n state: ");
- out("\033[32;1mFulfilled\033[0m");
- out("\n result: ");
+ js_out("\n state: ");
+ js_out("\033[32;1mFulfilled\033[0m");
+ js_out("\n result: ");
print_value(promise.result(), seen_objects);
break;
case JS::Promise::State::Rejected:
- out("\n state: ");
- out("\033[31;1mRejected\033[0m");
- out("\n result: ");
+ js_out("\n state: ");
+ js_out("\033[31;1mRejected\033[0m");
+ js_out("\n result: ");
print_value(promise.result(), seen_objects);
break;
default:
@@ -369,20 +410,20 @@ static void print_array_buffer(JS::Object const& object, HashTable<JS::Object*>&
auto& buffer = array_buffer.buffer();
auto byte_length = array_buffer.byte_length();
print_type("ArrayBuffer");
- out("\n byteLength: ");
+ js_out("\n byteLength: ");
print_value(JS::Value((double)byte_length), seen_objects);
if (!byte_length)
return;
- outln();
+ js_outln();
for (size_t i = 0; i < byte_length; ++i) {
- out("{:02x}", buffer[i]);
+ js_out("{:02x}", buffer[i]);
if (i + 1 < byte_length) {
if ((i + 1) % 32 == 0)
- outln();
+ js_outln();
else if ((i + 1) % 16 == 0)
- out(" ");
+ js_out(" ");
else
- out(" ");
+ js_out(" ");
}
}
}
@@ -396,9 +437,9 @@ static void print_shadow_realm(JS::Object const&, HashTable<JS::Object*>&)
template<typename T>
static void print_number(T number) requires IsArithmetic<T>
{
- out("\033[35;1m");
- out("{}", number);
- out("\033[0m");
+ js_out("\033[35;1m");
+ js_out("{}", number);
+ js_out("\033[0m");
}
static void print_typed_array(JS::Object const& object, HashTable<JS::Object*>& seen_objects)
@@ -407,30 +448,30 @@ static void print_typed_array(JS::Object const& object, HashTable<JS::Object*>&
auto& array_buffer = *typed_array_base.viewed_array_buffer();
auto length = typed_array_base.array_length();
print_type(object.class_name());
- out("\n length: ");
+ js_out("\n length: ");
print_value(JS::Value(length), seen_objects);
- out("\n byteLength: ");
+ js_out("\n byteLength: ");
print_value(JS::Value(typed_array_base.byte_length()), seen_objects);
- out("\n buffer: ");
+ js_out("\n buffer: ");
print_type("ArrayBuffer");
if (array_buffer.is_detached())
- out(" (detached)");
- out(" @ {:p}", &array_buffer);
+ js_out(" (detached)");
+ js_out(" @ {:p}", &array_buffer);
if (!length || array_buffer.is_detached())
return;
- outln();
+ js_outln();
// FIXME: This kinda sucks.
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType) \
if (is<JS::ClassName>(object)) { \
- out("[ "); \
+ js_out("[ "); \
auto& typed_array = static_cast<JS::ClassName const&>(typed_array_base); \
auto data = typed_array.data(); \
for (size_t i = 0; i < length; ++i) { \
if (i > 0) \
- out(", "); \
+ js_out(", "); \
print_number(data[i]); \
} \
- out(" ]"); \
+ js_out(" ]"); \
return; \
}
JS_ENUMERATE_TYPED_ARRAYS
@@ -442,20 +483,20 @@ static void print_data_view(JS::Object const& object, HashTable<JS::Object*>& se
{
auto& data_view = static_cast<JS::DataView const&>(object);
print_type("DataView");
- out("\n byteLength: ");
+ js_out("\n byteLength: ");
print_value(JS::Value(data_view.byte_length()), seen_objects);
- out("\n byteOffset: ");
+ js_out("\n byteOffset: ");
print_value(JS::Value(data_view.byte_offset()), seen_objects);
- out("\n buffer: ");
+ js_out("\n buffer: ");
print_type("ArrayBuffer");
- out(" @ {:p}", data_view.viewed_array_buffer());
+ js_out(" @ {:p}", data_view.viewed_array_buffer());
}
static void print_temporal_calendar(JS::Object const& object, HashTable<JS::Object*>& seen_objects)
{
auto& calendar = static_cast<JS::Temporal::Calendar const&>(object);
print_type("Temporal.Calendar");
- out(" ");
+ js_out(" ");
print_value(JS::js_string(object.vm(), calendar.identifier()), seen_objects);
}
@@ -463,14 +504,14 @@ static void print_temporal_duration(JS::Object const& object, HashTable<JS::Obje
{
auto& duration = static_cast<JS::Temporal::Duration const&>(object);
print_type("Temporal.Duration");
- out(" \033[34;1m{} y, {} M, {} w, {} d, {} h, {} m, {} s, {} ms, {} us, {} ns\033[0m", duration.years(), duration.months(), duration.weeks(), duration.days(), duration.hours(), duration.minutes(), duration.seconds(), duration.milliseconds(), duration.microseconds(), duration.nanoseconds());
+ js_out(" \033[34;1m{} y, {} M, {} w, {} d, {} h, {} m, {} s, {} ms, {} us, {} ns\033[0m", duration.years(), duration.months(), duration.weeks(), duration.days(), duration.hours(), duration.minutes(), duration.seconds(), duration.milliseconds(), duration.microseconds(), duration.nanoseconds());
}
static void print_temporal_instant(JS::Object const& object, HashTable<JS::Object*>& seen_objects)
{
auto& instant = static_cast<JS::Temporal::Instant const&>(object);
print_type("Temporal.Instant");
- out(" ");
+ js_out(" ");
// FIXME: Print human readable date and time, like in print_date() - ideally handling arbitrarily large values since we get a bigint.
print_value(&instant.nanoseconds(), seen_objects);
}
@@ -479,8 +520,8 @@ static void print_temporal_plain_date(JS::Object const& object, HashTable<JS::Ob
{
auto& plain_date = static_cast<JS::Temporal::PlainDate const&>(object);
print_type("Temporal.PlainDate");
- out(" \033[34;1m{:04}-{:02}-{:02}\033[0m", plain_date.iso_year(), plain_date.iso_month(), plain_date.iso_day());
- out("\n calendar: ");
+ js_out(" \033[34;1m{:04}-{:02}-{:02}\033[0m", plain_date.iso_year(), plain_date.iso_month(), plain_date.iso_day());
+ js_out("\n calendar: ");
print_value(&plain_date.calendar(), seen_objects);
}
@@ -488,8 +529,8 @@ static void print_temporal_plain_date_time(JS::Object const& object, HashTable<J
{
auto& plain_date_time = static_cast<JS::Temporal::PlainDateTime const&>(object);
print_type("Temporal.PlainDateTime");
- out(" \033[34;1m{:04}-{:02}-{:02} {:02}:{:02}:{:02}.{:03}{:03}{:03}\033[0m", plain_date_time.iso_year(), plain_date_time.iso_month(), plain_date_time.iso_day(), plain_date_time.iso_hour(), plain_date_time.iso_minute(), plain_date_time.iso_second(), plain_date_time.iso_millisecond(), plain_date_time.iso_microsecond(), plain_date_time.iso_nanosecond());
- out("\n calendar: ");
+ js_out(" \033[34;1m{:04}-{:02}-{:02} {:02}:{:02}:{:02}.{:03}{:03}{:03}\033[0m", plain_date_time.iso_year(), plain_date_time.iso_month(), plain_date_time.iso_day(), plain_date_time.iso_hour(), plain_date_time.iso_minute(), plain_date_time.iso_second(), plain_date_time.iso_millisecond(), plain_date_time.iso_microsecond(), plain_date_time.iso_nanosecond());
+ js_out("\n calendar: ");
print_value(&plain_date_time.calendar(), seen_objects);
}
@@ -498,8 +539,8 @@ static void print_temporal_plain_month_day(JS::Object const& object, HashTable<J
auto& plain_month_day = static_cast<JS::Temporal::PlainMonthDay const&>(object);
print_type("Temporal.PlainMonthDay");
// Also has an [[ISOYear]] internal slot, but showing that here seems rather unexpected.
- out(" \033[34;1m{:02}-{:02}\033[0m", plain_month_day.iso_month(), plain_month_day.iso_day());
- out("\n calendar: ");
+ js_out(" \033[34;1m{:02}-{:02}\033[0m", plain_month_day.iso_month(), plain_month_day.iso_day());
+ js_out("\n calendar: ");
print_value(&plain_month_day.calendar(), seen_objects);
}
@@ -507,8 +548,8 @@ static void print_temporal_plain_time(JS::Object const& object, HashTable<JS::Ob
{
auto& plain_time = static_cast<JS::Temporal::PlainTime const&>(object);
print_type("Temporal.PlainTime");
- out(" \033[34;1m{:02}:{:02}:{:02}.{:03}{:03}{:03}\033[0m", plain_time.iso_hour(), plain_time.iso_minute(), plain_time.iso_second(), plain_time.iso_millisecond(), plain_time.iso_microsecond(), plain_time.iso_nanosecond());
- out("\n calendar: ");
+ js_out(" \033[34;1m{:02}:{:02}:{:02}.{:03}{:03}{:03}\033[0m", plain_time.iso_hour(), plain_time.iso_minute(), plain_time.iso_second(), plain_time.iso_millisecond(), plain_time.iso_microsecond(), plain_time.iso_nanosecond());
+ js_out("\n calendar: ");
print_value(&plain_time.calendar(), seen_objects);
}
@@ -517,8 +558,8 @@ static void print_temporal_plain_year_month(JS::Object const& object, HashTable<
auto& plain_year_month = static_cast<JS::Temporal::PlainYearMonth const&>(object);
print_type("Temporal.PlainYearMonth");
// Also has an [[ISODay]] internal slot, but showing that here seems rather unexpected.
- out(" \033[34;1m{:04}-{:02}\033[0m", plain_year_month.iso_year(), plain_year_month.iso_month());
- out("\n calendar: ");
+ js_out(" \033[34;1m{:04}-{:02}\033[0m", plain_year_month.iso_year(), plain_year_month.iso_month());
+ js_out("\n calendar: ");
print_value(&plain_year_month.calendar(), seen_objects);
}
@@ -526,10 +567,10 @@ static void print_temporal_time_zone(JS::Object const& object, HashTable<JS::Obj
{
auto& time_zone = static_cast<JS::Temporal::TimeZone const&>(object);
print_type("Temporal.TimeZone");
- out(" ");
+ js_out(" ");
print_value(JS::js_string(object.vm(), time_zone.identifier()), seen_objects);
if (time_zone.offset_nanoseconds().has_value()) {
- out("\n offset (ns): ");
+ js_out("\n offset (ns): ");
print_value(JS::Value(*time_zone.offset_nanoseconds()), seen_objects);
}
}
@@ -538,11 +579,11 @@ static void print_temporal_zoned_date_time(JS::Object const& object, HashTable<J
{
auto& zoned_date_time = static_cast<JS::Temporal::ZonedDateTime const&>(object);
print_type("Temporal.ZonedDateTime");
- out("\n epochNanoseconds: ");
+ js_out("\n epochNanoseconds: ");
print_value(&zoned_date_time.nanoseconds(), seen_objects);
- out("\n timeZone: ");
+ js_out("\n timeZone: ");
print_value(&zoned_date_time.time_zone(), seen_objects);
- out("\n calendar: ");
+ js_out("\n calendar: ");
print_value(&zoned_date_time.calendar(), seen_objects);
}
@@ -550,13 +591,13 @@ static void print_intl_display_names(JS::Object const& object, HashTable<JS::Obj
{
auto& display_names = static_cast<JS::Intl::DisplayNames const&>(object);
print_type("Intl.DisplayNames");
- out("\n locale: ");
+ js_out("\n locale: ");
print_value(js_string(object.vm(), display_names.locale()), seen_objects);
- out("\n type: ");
+ js_out("\n type: ");
print_value(js_string(object.vm(), display_names.type_string()), seen_objects);
- out("\n style: ");
+ js_out("\n style: ");
print_value(js_string(object.vm(), display_names.style_string()), seen_objects);
- out("\n fallback: ");
+ js_out("\n fallback: ");
print_value(js_string(object.vm(), display_names.fallback_string()), seen_objects);
}
@@ -564,29 +605,29 @@ static void print_intl_locale(JS::Object const& object, HashTable<JS::Object*>&
{
auto& locale = static_cast<JS::Intl::Locale const&>(object);
print_type("Intl.Locale");
- out("\n locale: ");
+ js_out("\n locale: ");
print_value(js_string(object.vm(), locale.locale()), seen_objects);
if (locale.has_calendar()) {
- out("\n calendar: ");
+ js_out("\n calendar: ");
print_value(js_string(object.vm(), locale.calendar()), seen_objects);
}
if (locale.has_case_first()) {
- out("\n caseFirst: ");
+ js_out("\n caseFirst: ");
print_value(js_string(object.vm(), locale.case_first()), seen_objects);
}
if (locale.has_collation()) {
- out("\n collation: ");
+ js_out("\n collation: ");
print_value(js_string(object.vm(), locale.collation()), seen_objects);
}
if (locale.has_hour_cycle()) {
- out("\n hourCycle: ");
+ js_out("\n hourCycle: ");
print_value(js_string(object.vm(), locale.hour_cycle()), seen_objects);
}
if (locale.has_numbering_system()) {
- out("\n numberingSystem: ");
+ js_out("\n numberingSystem: ");
print_value(js_string(object.vm(), locale.numbering_system()), seen_objects);
}
- out("\n numeric: ");
+ js_out("\n numeric: ");
print_value(JS::Value(locale.numeric()), seen_objects);
}
@@ -594,11 +635,11 @@ static void print_intl_list_format(JS::Object const& object, HashTable<JS::Objec
{
auto& list_format = static_cast<JS::Intl::ListFormat const&>(object);
print_type("Intl.ListFormat");
- out("\n locale: ");
+ js_out("\n locale: ");
print_value(js_string(object.vm(), list_format.locale()), seen_objects);
- out("\n type: ");
+ js_out("\n type: ");
print_value(js_string(object.vm(), list_format.type_string()), seen_objects);
- out("\n style: ");
+ js_out("\n style: ");
print_value(js_string(object.vm(), list_format.style_string()), seen_objects);
}
@@ -606,63 +647,63 @@ static void print_intl_number_format(JS::Object const& object, HashTable<JS::Obj
{
auto& number_format = static_cast<JS::Intl::NumberFormat const&>(object);
print_type("Intl.NumberFormat");
- out("\n locale: ");
+ js_out("\n locale: ");
print_value(js_string(object.vm(), number_format.locale()), seen_objects);
- out("\n dataLocale: ");
+ js_out("\n dataLocale: ");
print_value(js_string(object.vm(), number_format.data_locale()), seen_objects);
- out("\n numberingSystem: ");
+ js_out("\n numberingSystem: ");
print_value(js_string(object.vm(), number_format.numbering_system()), seen_objects);
- out("\n style: ");
+ js_out("\n style: ");
print_value(js_string(object.vm(), number_format.style_string()), seen_objects);
if (number_format.has_currency()) {
- out("\n currency: ");
+ js_out("\n currency: ");
print_value(js_string(object.vm(), number_format.currency()), seen_objects);
}
if (number_format.has_currency_display()) {
- out("\n currencyDisplay: ");
+ js_out("\n currencyDisplay: ");
print_value(js_string(object.vm(), number_format.currency_display_string()), seen_objects);
}
if (number_format.has_currency_sign()) {
- out("\n currencySign: ");
+ js_out("\n currencySign: ");
print_value(js_string(object.vm(), number_format.currency_sign_string()), seen_objects);
}
if (number_format.has_unit()) {
- out("\n unit: ");
+ js_out("\n unit: ");
print_value(js_string(object.vm(), number_format.unit()), seen_objects);
}
if (number_format.has_unit_display()) {
- out("\n unitDisplay: ");
+ js_out("\n unitDisplay: ");
print_value(js_string(object.vm(), number_format.unit_display_string()), seen_objects);
}
- out("\n minimumIntegerDigits: ");
+ js_out("\n minimumIntegerDigits: ");
print_value(JS::Value(number_format.min_integer_digits()), seen_objects);
if (number_format.has_min_fraction_digits()) {
- out("\n minimumFractionDigits: ");
+ js_out("\n minimumFractionDigits: ");
print_value(JS::Value(number_format.min_fraction_digits()), seen_objects);
}
if (number_format.has_max_fraction_digits()) {
- out("\n maximumFractionDigits: ");
+ js_out("\n maximumFractionDigits: ");
print_value(JS::Value(number_format.max_fraction_digits()), seen_objects);
}
if (number_format.has_min_significant_digits()) {
- out("\n minimumSignificantDigits: ");
+ js_out("\n minimumSignificantDigits: ");
print_value(JS::Value(number_format.min_significant_digits()), seen_objects);
}
if (number_format.has_max_significant_digits()) {
- out("\n maximumSignificantDigits: ");
+ js_out("\n maximumSignificantDigits: ");
print_value(JS::Value(number_format.max_significant_digits()), seen_objects);
}
- out("\n useGrouping: ");
+ js_out("\n useGrouping: ");
print_value(JS::Value(number_format.use_grouping()), seen_objects);
- out("\n roundingType: ");
+ js_out("\n roundingType: ");
print_value(js_string(object.vm(), number_format.rounding_type_string()), seen_objects);
- out("\n notation: ");
+ js_out("\n notation: ");
print_value(js_string(object.vm(), number_format.notation_string()), seen_objects);
if (number_format.has_compact_display()) {
- out("\n compactDisplay: ");
+ js_out("\n compactDisplay: ");
print_value(js_string(object.vm(), number_format.compact_display_string()), seen_objects);
}
- out("\n signDisplay: ");
+ js_out("\n signDisplay: ");
print_value(js_string(object.vm(), number_format.sign_display_string()), seen_objects);
}
@@ -670,14 +711,14 @@ static void print_primitive_wrapper_object(FlyString const& name, JS::Object con
{
// BooleanObject, NumberObject, StringObject
print_type(name);
- out(" ");
+ js_out(" ");
print_value(object.value_of(), seen_objects);
}
static void print_value(JS::Value value, HashTable<JS::Object*>& seen_objects)
{
if (value.is_empty()) {
- out("\033[34;1m<empty>\033[0m");
+ js_out("\033[34;1m<empty>\033[0m");
return;
}
@@ -685,7 +726,7 @@ static void print_value(JS::Value value, HashTable<JS::Object*>& seen_objects)
if (seen_objects.contains(&value.as_object())) {
// FIXME: Maybe we should only do this for circular references,
// not for all reoccurring objects.
- out("<already printed Object {}>", &value.as_object());
+ js_out("<already printed Object {}>", &value.as_object());
return;
}
seen_objects.set(&value.as_object());
@@ -757,30 +798,30 @@ static void print_value(JS::Value value, HashTable<JS::Object*>& seen_objects)
}
if (value.is_string())
- out("\033[32;1m");
+ js_out("\033[32;1m");
else if (value.is_number() || value.is_bigint())
- out("\033[35;1m");
+ js_out("\033[35;1m");
else if (value.is_boolean())
- out("\033[33;1m");
+ js_out("\033[33;1m");
else if (value.is_null())
- out("\033[33;1m");
+ js_out("\033[33;1m");
else if (value.is_undefined())
- out("\033[34;1m");
+ js_out("\033[34;1m");
if (value.is_string())
- out("\"");
+ js_out("\"");
else if (value.is_negative_zero())
- out("-");
- out("{}", value.to_string_without_side_effects());
+ js_out("-");
+ js_out("{}", value.to_string_without_side_effects());
if (value.is_string())
- out("\"");
- out("\033[0m");
+ js_out("\"");
+ js_out("\033[0m");
}
static void print(JS::Value value)
{
HashTable<JS::Object*> seen_objects;
print_value(value, seen_objects);
- outln();
+ js_outln();
}
static bool write_to_file(String const& path)
@@ -822,7 +863,7 @@ static bool parse_and_run(JS::Interpreter& interpreter, StringView source, Strin
auto error = parser.errors()[0];
auto hint = error.source_location_hint(source);
if (!hint.is_empty())
- outln("{}", hint);
+ js_outln("{}", hint);
vm->throw_exception<JS::SyntaxError>(interpreter.global_object(), error.to_string());
} else {
if (JS::Bytecode::g_dump_bytecode || s_run_bytecode) {
@@ -854,7 +895,7 @@ static bool parse_and_run(JS::Interpreter& interpreter, StringView source, Strin
auto handle_exception = [&] {
auto* exception = vm->exception();
vm->clear_exception();
- out("Uncaught exception: ");
+ js_out("Uncaught exception: ");
print(exception->value());
auto& traceback = exception->traceback();
if (traceback.size() > 1) {
@@ -872,11 +913,11 @@ static bool parse_and_run(JS::Interpreter& interpreter, StringView source, Strin
// If more than 5 (1 + >4) consecutive function calls with the same name, print
// the name only once and show the number of repetitions instead. This prevents
// printing ridiculously large call stacks of recursive functions.
- outln(" -> {}", traceback_frame.function_name);
- outln(" {} more calls", repetitions);
+ js_outln(" -> {}", traceback_frame.function_name);
+ js_outln(" {} more calls", repetitions);
} else {
for (size_t j = 0; j < repetitions + 1; ++j)
- outln(" -> {}", traceback_frame.function_name);
+ js_outln(" -> {}", traceback_frame.function_name);
}
repetitions = 0;
}
@@ -961,11 +1002,11 @@ JS_DEFINE_NATIVE_FUNCTION(ReplObject::exit_interpreter)
JS_DEFINE_NATIVE_FUNCTION(ReplObject::repl_help)
{
- outln("REPL commands:");
- outln(" exit(code): exit the REPL with specified code. Defaults to 0.");
- outln(" help(): display this menu");
- outln(" load(file): load given JS file into running session. For example: load(\"foo.js\")");
- outln(" save(file): write REPL input history to the given file. For example: save(\"foo.txt\")");
+ js_outln("REPL commands:");
+ js_outln(" exit(code): exit the REPL with specified code. Defaults to 0.");
+ js_outln(" help(): display this menu");
+ js_outln(" load(file): load given JS file into running session. For example: load(\"foo.js\")");
+ js_outln(" save(file): write REPL input history to the given file. For example: save(\"foo.txt\")");
return JS::js_undefined();
}
@@ -1024,49 +1065,49 @@ public:
virtual JS::Value log() override
{
- outln("{}", vm().join_arguments());
+ js_outln("{}", vm().join_arguments());
return JS::js_undefined();
}
virtual JS::Value info() override
{
- outln("(i) {}", vm().join_arguments());
+ js_outln("(i) {}", vm().join_arguments());
return JS::js_undefined();
}
virtual JS::Value debug() override
{
- outln("\033[36;1m{}\033[0m", vm().join_arguments());
+ js_outln("\033[36;1m{}\033[0m", vm().join_arguments());
return JS::js_undefined();
}
virtual JS::Value warn() override
{
- outln("\033[33;1m{}\033[0m", vm().join_arguments());
+ js_outln("\033[33;1m{}\033[0m", vm().join_arguments());
return JS::js_undefined();
}
virtual JS::Value error() override
{
- outln("\033[31;1m{}\033[0m", vm().join_arguments());
+ js_outln("\033[31;1m{}\033[0m", vm().join_arguments());
return JS::js_undefined();
}
virtual JS::Value clear() override
{
- out("\033[3J\033[H\033[2J");
+ js_out("\033[3J\033[H\033[2J");
fflush(stdout);
return JS::js_undefined();
}
virtual JS::Value trace() override
{
- outln("{}", vm().join_arguments());
+ js_outln("{}", vm().join_arguments());
auto trace = get_trace();
for (auto& function_name : trace) {
if (function_name.is_empty())
function_name = "<anonymous>";
- outln(" -> {}", function_name);
+ js_outln(" -> {}", function_name);
}
return JS::js_undefined();
}
@@ -1075,7 +1116,7 @@ public:
{
auto label = vm().argument_count() ? vm().argument(0).to_string_without_side_effects() : "default";
auto counter_value = m_console.counter_increment(label);
- outln("{}: {}", label, counter_value);
+ js_outln("{}: {}", label, counter_value);
return JS::js_undefined();
}
@@ -1083,9 +1124,9 @@ public:
{
auto label = vm().argument_count() ? vm().argument(0).to_string_without_side_effects() : "default";
if (m_console.counter_reset(label))
- outln("{}: 0", label);
+ js_outln("{}: 0", label);
else
- outln("\033[33;1m\"{}\" doesn't have a count\033[0m", label);
+ js_outln("\033[33;1m\"{}\" doesn't have a count\033[0m", label);
return JS::js_undefined();
}
@@ -1094,10 +1135,10 @@ public:
auto& vm = this->vm();
if (!vm.argument(0).to_boolean()) {
if (vm.argument_count() > 1) {
- out("\033[31;1mAssertion failed:\033[0m");
- outln(" {}", vm.join_arguments(1));
+ js_out("\033[31;1mAssertion failed:\033[0m");
+ js_outln(" {}", vm.join_arguments(1));
} else {
- outln("\033[31;1mAssertion failed\033[0m");
+ js_outln("\033[31;1mAssertion failed\033[0m");
}
}
return JS::js_undefined();
@@ -1122,6 +1163,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
args_parser.add_option(s_opt_bytecode, "Optimize the bytecode", "optimize-bytecode", 'p');
args_parser.add_option(s_as_module, "Treat as module", "as-module", 'm');
args_parser.add_option(s_print_last_result, "Print last result", "print-last-result", 'l');
+ args_parser.add_option(s_strip_ansi, "Disable ANSI colors", "disable-ansi-colors", 'c');
args_parser.add_option(gc_on_every_allocation, "GC on every allocation", "gc-on-every-allocation", 'g');
#ifdef JS_TRACK_ZOMBIE_CELLS
bool zombify_dead_cells = false;
@@ -1140,19 +1182,19 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
// might want to revisit at a later point and disable warnings for promises created this way.
vm->on_promise_unhandled_rejection = [](auto& promise) {
// FIXME: Optionally make print_value() to print to stderr
- out("WARNING: A promise was rejected without any handlers");
- out(" (result: ");
+ js_out("WARNING: A promise was rejected without any handlers");
+ js_out(" (result: ");
HashTable<JS::Object*> seen_objects;
print_value(promise.result(), seen_objects);
- outln(")");
+ js_outln(")");
};
vm->on_promise_rejection_handled = [](auto& promise) {
// FIXME: Optionally make print_value() to print to stderr
- out("WARNING: A handler was added to an already rejected promise");
- out(" (result: ");
+ js_out("WARNING: A handler was added to an already rejected promise");
+ js_out(" (result: ");
HashTable<JS::Object*> seen_objects;
print_value(promise.result(), seen_objects);
- outln(")");
+ js_outln(")");
};
OwnPtr<JS::Interpreter> interpreter;