From 8baf3be121721b96966a2a6790eca323b82ba714 Mon Sep 17 00:00:00 2001 From: Daniel Beckert Date: Fri, 17 Aug 2018 11:34:08 -0300 Subject: [PATCH 1/4] src: colorize output for findjsinstances To make visualization easier, objects types, properties and addresses will be colorized. Using `rang` library color pallete, the current definition is: * cyan for addresses * magenta for objects being inspected * yellow for types * bold yellow for objects properties Fixes: https://github.com/nodejs/llnode/issues/179 Colorize findrefs output --- src/llscan.cc | 91 ++++++--- src/llscan.h | 4 +- src/llv8.cc | 162 ++++++++++++---- src/rang.hpp | 502 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 700 insertions(+), 59 deletions(-) create mode 100644 src/rang.hpp diff --git a/src/llscan.cc b/src/llscan.cc index f1241ce7..efa1192b 100644 --- a/src/llscan.cc +++ b/src/llscan.cc @@ -7,6 +7,9 @@ #include #include #include +#include +#include +#include #include @@ -14,6 +17,7 @@ #include "src/llnode.h" #include "src/llscan.h" #include "src/llv8-inl.h" +#include "src/rang.hpp" namespace llnode { @@ -28,18 +32,6 @@ using lldb::SBValue; using lldb::eReturnStatusFailed; using lldb::eReturnStatusSuccessFinishResult; -const char* const - FindReferencesCmd::ObjectScanner::property_reference_template = - "0x%" PRIx64 ": %s.%s=0x%" PRIx64 "\n"; -const char* const FindReferencesCmd::ObjectScanner::array_reference_template = - "0x%" PRIx64 ": %s[%" PRId64 "]=0x%" PRIx64 "\n"; - - -const char* const - FindReferencesCmd::StringScanner::property_reference_template = - "0x%" PRIx64 ": %s.%s=0x%" PRIx64 " '%s'\n"; -const char* const FindReferencesCmd::StringScanner::array_reference_template = - "0x%" PRIx64 ": %s[%" PRId64 "]=0x%" PRIx64 " '%s'\n"; char** ParseInspectOptions(char** cmd, v8::Value::InspectOptions* options) { static struct option opts[] = { @@ -241,7 +233,12 @@ bool FindInstancesCmd::DoExecute(SBDebugger d, char** cmd, } } else { - result.Printf("No objects found with type name %s\n", type_name.c_str()); + rang::setControlMode(rang::control::Force); + std::stringstream ss; + ss << rang::style::bold << rang::fg::red << "No objects found with type name " + << type_name.c_str() << rang::fg::reset << rang::style::reset << std::endl; + std::string str(ss.str()); + result.Printf(str.c_str()); result.SetStatus(eReturnStatusFailed); return false; } @@ -428,6 +425,7 @@ bool NodeInfoCmd::DoExecute(SBDebugger d, char** cmd, bool FindReferencesCmd::DoExecute(SBDebugger d, char** cmd, SBCommandReturnObject& result) { + rang::setControlMode(rang::control::Force); if (cmd == nullptr || *cmd == nullptr) { result.SetError("USAGE: v8 findrefs expr\n"); return false; @@ -706,6 +704,27 @@ void FindReferencesCmd::ReferenceScanner::PrintContextRefs( } } +std::string FindReferencesCmd::ObjectScanner::GetPropertyReferenceString() { + rang::setControlMode(rang::control::Force); + std::stringstream ss; + ss << rang::fg::cyan << "0x%" PRIx64 << rang::fg::reset << ": " << rang::fg::magenta + << "%s" << rang::style::bold << rang::fg::yellow << ".%s" << rang::fg::reset + << rang::style::reset << "=" << rang::fg::cyan << "0x%" PRIx64 << rang::fg::reset + << "\n"; + return ss.str(); +} + +std::string FindReferencesCmd::ObjectScanner::GetArrayReferenceString() { + rang::setControlMode(rang::control::Force); + std::stringstream ss; + ss << rang::fg::cyan << "0x%" PRIx64 << rang::fg::reset << ": " << rang::fg::magenta + << "%s" << rang::style::bold << rang::fg::yellow << "[%" PRId64 "]" << rang::fg::reset + << rang::style::reset << "=" << rang::fg::cyan << "0x%" PRIx64 << rang::fg::reset + << "\n"; + return ss.str(); +} + + void FindReferencesCmd::ReferenceScanner::PrintRefs( SBCommandReturnObject& result, v8::JSObject& js_obj, Error& err) { int64_t length = js_obj.GetArrayLength(err); @@ -718,7 +737,9 @@ void FindReferencesCmd::ReferenceScanner::PrintRefs( if (v.raw() != search_value_.raw()) continue; std::string type_name = js_obj.GetTypeName(err); - result.Printf(array_reference_template, js_obj.raw(), type_name.c_str(), i, + + std::string reference_template(GetArrayReferenceString()); + result.Printf(reference_template.c_str(), js_obj.raw(), type_name.c_str(), i, search_value_.raw()); } @@ -734,7 +755,9 @@ void FindReferencesCmd::ReferenceScanner::PrintRefs( if (v.raw() == search_value_.raw()) { std::string key = entry.first.ToString(err); std::string type_name = js_obj.GetTypeName(err); - result.Printf(property_reference_template, js_obj.raw(), + + std::string reference_template(GetPropertyReferenceString()); + result.Printf(reference_template.c_str(), js_obj.raw(), type_name.c_str(), key.c_str(), search_value_.raw()); } } @@ -754,7 +777,9 @@ void FindReferencesCmd::ReferenceScanner::PrintRefs( v8::String parent = sliced_str.Parent(err); if (err.Success() && parent.raw() == search_value_.raw()) { std::string type_name = sliced_str.GetTypeName(err); - result.Printf(property_reference_template, str.raw(), type_name.c_str(), + + std::string reference_template(GetPropertyReferenceString()); + result.Printf(reference_template.c_str(), str.raw(), type_name.c_str(), "", search_value_.raw()); } } else if (repr == v8->string()->kConsStringTag) { @@ -763,14 +788,18 @@ void FindReferencesCmd::ReferenceScanner::PrintRefs( v8::String first = cons_str.First(err); if (err.Success() && first.raw() == search_value_.raw()) { std::string type_name = cons_str.GetTypeName(err); - result.Printf(property_reference_template, str.raw(), type_name.c_str(), + + std::string reference_template(GetPropertyReferenceString()); + result.Printf(reference_template.c_str(), str.raw(), type_name.c_str(), "", search_value_.raw()); } v8::String second = cons_str.Second(err); if (err.Success() && second.raw() == search_value_.raw()) { std::string type_name = cons_str.GetTypeName(err); - result.Printf(property_reference_template, str.raw(), type_name.c_str(), + + std::string reference_template(GetPropertyReferenceString()); + result.Printf(reference_template.c_str(), str.raw(), type_name.c_str(), "", search_value_.raw()); } } else if (repr == v8->string()->kThinStringTag) { @@ -778,7 +807,9 @@ void FindReferencesCmd::ReferenceScanner::PrintRefs( v8::String actual = thin_str.Actual(err); if (err.Success() && actual.raw() == search_value_.raw()) { std::string type_name = thin_str.GetTypeName(err); - result.Printf(property_reference_template, str.raw(), type_name.c_str(), + + std::string reference_template(GetPropertyReferenceString()); + result.Printf(reference_template.c_str(), str.raw(), type_name.c_str(), "", search_value_.raw()); } } @@ -900,7 +931,9 @@ void FindReferencesCmd::PropertyScanner::PrintRefs( } if (key == search_value_) { std::string type_name = js_obj.GetTypeName(err); - result.Printf(property_reference_template, js_obj.raw(), + + std::string reference_template(GetPropertyReferenceString()); + result.Printf(reference_template.c_str(), js_obj.raw(), type_name.c_str(), key.c_str(), entry.second.raw()); } } @@ -967,8 +1000,11 @@ void FindReferencesCmd::StringScanner::PrintRefs(SBCommandReturnObject& result, if (err.Success() && search_value_ == value) { std::string type_name = js_obj.GetTypeName(err); - result.Printf("0x%" PRIx64 ": %s[%" PRId64 "]=0x%" PRIx64 " '%s'\n", - js_obj.raw(), type_name.c_str(), i, v.raw(), + std::stringstream ss; + ss << rang::fg::cyan << std::hex << js_obj.raw() << std::dec << rang::fg::reset; + + result.Printf("%s: %s[%" PRId64 "]=0x%" PRIx64 " '%s'\n", + ss.str().c_str(), type_name.c_str(), i, v.raw(), value.c_str()); } } @@ -997,9 +1033,14 @@ void FindReferencesCmd::StringScanner::PrintRefs(SBCommandReturnObject& result, continue; } std::string type_name = js_obj.GetTypeName(err); - result.Printf("0x%" PRIx64 ": %s.%s=0x%" PRIx64 " '%s'\n", - js_obj.raw(), type_name.c_str(), key.c_str(), - entry.second.raw(), value.c_str()); + + std::stringstream ss; + ss << rang::fg::cyan << "0x" << std::hex << js_obj.raw() << rang::fg::reset + << std::dec << ": " << type_name.c_str() << "." << key.c_str() << "=" + << std::hex << entry.second.raw() << std::dec << " '" << value.c_str() + << "'" << std::endl; + + result.Printf(ss.str().c_str()); } } } diff --git a/src/llscan.h b/src/llscan.h index 419fbd37..99295225 100644 --- a/src/llscan.h +++ b/src/llscan.h @@ -93,8 +93,8 @@ class FindReferencesCmd : public CommandBase { virtual void PrintContextRefs(lldb::SBCommandReturnObject& result, Error& err) {} - static const char* const property_reference_template; - static const char* const array_reference_template; + virtual std::string GetPropertyReferenceString(); + virtual std::string GetArrayReferenceString(); }; void PrintReferences(lldb::SBCommandReturnObject& result, diff --git a/src/llv8.cc b/src/llv8.cc index 4973a461..682aece2 100644 --- a/src/llv8.cc +++ b/src/llv8.cc @@ -3,9 +3,13 @@ #include #include #include +#include +#include +#include #include "llv8-inl.h" #include "llv8.h" +#include "src/rang.hpp" namespace llnode { namespace v8 { @@ -415,9 +419,16 @@ std::string JSFunction::Inspect(InspectOptions* options, Error& err) { res += source + "\n"; } } + res = res + ">"; } + else { + std::stringstream ss; + ss << rang::fg::yellow << res << ">" << rang::fg::reset; + res = ss.str().c_str(); + + } + return res; - return res + ">"; } @@ -767,6 +778,7 @@ std::string HeapObject::ToString(Error& err) { std::string HeapObject::Inspect(InspectOptions* options, Error& err) { + rang::setControlMode(rang::control::Force); int64_t type = GetType(err); if (err.Fail()) return std::string(); @@ -779,8 +791,11 @@ std::string HeapObject::Inspect(InspectOptions* options, Error& err) { snprintf(buf, sizeof(buf), "0x%016" PRIx64 "(map=0x%016" PRIx64 "):", raw(), map.raw()); } else { - snprintf(buf, sizeof(buf), "0x%016" PRIx64 ":", raw()); + std::stringstream ss; + ss << rang::fg::cyan << "0x" << std::hex << raw() << std::dec << rang::fg::reset; + snprintf(buf, sizeof(buf), "%s:", ss.str().c_str()); } + std::string pre = buf; if (type == v8()->types()->kGlobalObjectType) return pre + ""; @@ -854,7 +869,10 @@ std::string HeapObject::Inspect(InspectOptions* options, Error& err) { Error::PrintInDebugMode( "Unknown HeapObject Type %" PRId64 " at 0x%016" PRIx64 "", type, raw()); - return pre + ""; + + std::stringstream ss; + ss << rang::fg::yellow << "" << rang::fg::reset; + return pre + ss.str().c_str(); } @@ -953,7 +971,11 @@ std::string HeapObject::GetTypeName(Error& err) { } -std::string Smi::Inspect(Error& err) { return ""; } +std::string Smi::Inspect(Error& err) { + std::stringstream ss; + ss << rang::fg::yellow << "" << rang::fg::reset; + return ss.str().c_str(); +} std::string HeapNumber::ToString(bool whole, Error& err) { @@ -966,7 +988,9 @@ std::string HeapNumber::ToString(bool whole, Error& err) { std::string HeapNumber::Inspect(Error& err) { - return ""; + std::stringstream ss; + ss << rang::fg::yellow << "" << rang::fg::reset; + return ss.str().c_str(); } @@ -1023,7 +1047,9 @@ std::string String::Inspect(InspectOptions* options, Error& err) { if (len != 0 && val.length() > len) val = val.substr(0, len) + "..."; - return ""; + std::stringstream ss; + ss << rang::fg::yellow << "" << rang::fg::reset; + return ss.str().c_str(); } @@ -1039,7 +1065,9 @@ std::string FixedArray::Inspect(InspectOptions* options, Error& err) { if (!contents.empty()) res += " contents={\n" + contents + "}"; } - return res + ">"; + std::stringstream ss; + ss << rang::fg::yellow << res + ">" << rang::fg::reset; + return ss.str().c_str(); } @@ -1054,7 +1082,10 @@ std::string FixedArray::InspectContents(int length, Error& err) { if (!res.empty()) res += ",\n"; char tmp[128]; - snprintf(tmp, sizeof(tmp), " [%d]=", i); + + std::stringstream ss; + ss << rang::style::bold << rang::fg::yellow << " [" << i << "]" << rang::fg::reset << rang::style::reset << "="; + snprintf(tmp, sizeof(tmp), "%s", ss.str().c_str()); res += tmp + value.Inspect(&options, err); if (err.Fail()) return std::string(); } @@ -1197,21 +1228,30 @@ std::string Oddball::Inspect(Error& err) { if (err.Fail()) return std::string(); int64_t kind_val = kind.GetValue(); - if (kind_val == v8()->oddball()->kException) return ""; - if (kind_val == v8()->oddball()->kFalse) return ""; - if (kind_val == v8()->oddball()->kTrue) return ""; - if (kind_val == v8()->oddball()->kUndefined) return ""; - if (kind_val == v8()->oddball()->kNull) return ""; - if (kind_val == v8()->oddball()->kTheHole) return ""; - if (kind_val == v8()->oddball()->kUninitialized) return ""; - return ""; + std::string str; + if (kind_val == v8()->oddball()->kException) str = ""; + else if (kind_val == v8()->oddball()->kFalse) str = ""; + else if (kind_val == v8()->oddball()->kTrue) str = ""; + else if (kind_val == v8()->oddball()->kUndefined) str = ""; + else if (kind_val == v8()->oddball()->kNull) str = ""; + else if (kind_val == v8()->oddball()->kTheHole) str = ""; + else if (kind_val == v8()->oddball()->kUninitialized) str = ""; + else str = ""; + + std::stringstream ss; + ss << rang::fg::yellow << str << rang::fg::reset; + return ss.str().c_str(); } std::string JSArrayBuffer::Inspect(InspectOptions* options, Error& err) { bool neutered = WasNeutered(err); if (err.Fail()) return std::string(); - if (neutered) return ""; + if (neutered) { + std::stringstream ss; + ss << rang::fg::yellow << "" << rang::fg::reset; + return ss.str().c_str(); + } int64_t data = BackingStore(err); if (err.Fail()) return std::string(); @@ -1242,7 +1282,9 @@ std::string JSArrayBuffer::Inspect(InspectOptions* options, Error& err) { res += ">"; } - return res; + std::stringstream ss; + ss << rang::fg::yellow << res << rang::fg::reset; + return ss.str().c_str(); } @@ -1253,7 +1295,11 @@ std::string JSArrayBufferView::Inspect(InspectOptions* options, Error& err) { bool neutered = buf.WasNeutered(err); if (err.Fail()) return std::string(); - if (neutered) return ""; + if (neutered) { + std::stringstream ss; + ss << rang::fg::yellow << "" << rang::fg::reset; + return ss.str().c_str(); + } int64_t data = buf.BackingStore(err); if (err.Fail()) return std::string(); @@ -1373,8 +1419,11 @@ std::string JSObject::Inspect(InspectOptions* options, Error& err) { int64_t constructor_type = constructor_obj.GetType(err); if (err.Fail()) return std::string(); - if (constructor_type != v8()->types()->kJSFunctionType) - return ""; + if (constructor_type != v8()->types()->kJSFunctionType) { + std::stringstream ss; + ss << rang::fg::yellow << "" << rang::fg::reset; + return ss.str().c_str(); + } JSFunction constructor(constructor_obj); @@ -1383,17 +1432,29 @@ std::string JSObject::Inspect(InspectOptions* options, Error& err) { // Print properties in detailed mode if (options->detailed) { + std::stringstream ss; + ss << rang::fg::magenta << res << rang::fg::reset; + res = ss.str().c_str(); + res += " " + InspectProperties(err); if (err.Fail()) return std::string(); std::string fields = InspectInternalFields(err); if (err.Fail()) return std::string(); - if (!fields.empty()) res += "\n internal fields {\n" + fields + "}"; + if (!fields.empty()) { + std::stringstream ss; + ss << rang::fg::magenta << "\n internal fields" << rang::fg::reset << " {" << std::endl << fields << "}>"; + res += ss.str().c_str(); + } + return res; + } else { + std::stringstream ss; + ss << rang::fg::yellow << res << ">" << rang::fg::reset; + res = ss.str().c_str(); + return res; } - res += ">"; - return res; } @@ -1444,7 +1505,10 @@ std::string JSObject::InspectProperties(Error& err) { std::string elems = InspectElements(err); if (err.Fail()) return std::string(); - if (!elems.empty()) res = "elements {\n" + elems + "}"; + if (!elems.empty()) { + std::stringstream ss; + ss << rang::fg::magenta << "elements" << rang::fg::reset << " {" << std::endl << elems << "}"; + } HeapObject map_obj = GetMap(err); if (err.Fail()) return std::string(); @@ -1464,7 +1528,9 @@ std::string JSObject::InspectProperties(Error& err) { if (!props.empty()) { if (!res.empty()) res += "\n "; - res += "properties {\n" + props + "}"; + std::stringstream ss; + ss << rang::fg::magenta << "properties" << rang::fg::reset << " {" << std::endl << props << "}"; + res += ss.str().c_str(); } return res; @@ -1506,7 +1572,10 @@ std::string JSObject::InspectElements(int64_t length, Error& err) { if (!res.empty()) res += ",\n"; char tmp[64]; - snprintf(tmp, sizeof(tmp), " [%d]=", static_cast(i)); + + std::stringstream ss; + ss << rang::style::bold << rang::fg::yellow << " [" << static_cast(i) << "]" << rang::fg::reset << rang::style::reset << "="; + snprintf(tmp, sizeof(tmp), "%s", ss.str().c_str()); res += tmp; res += value.Inspect(&options, err); @@ -1529,6 +1598,8 @@ std::string JSObject::InspectDictionary(Error& err) { InspectOptions options; std::string res; + std::stringstream ss; + for (int64_t i = 0; i < length; i++) { Value key = dictionary.GetKey(i, err); if (err.Fail()) return std::string(); @@ -1543,7 +1614,10 @@ std::string JSObject::InspectDictionary(Error& err) { if (!res.empty()) res += ",\n"; - res += " ." + key.ToString(err) + "="; + ss.str(""); + ss.clear(); + ss << rang::style::bold << rang::fg::yellow << " ." + key.ToString(err) << rang::fg::reset << rang::style::reset; + res += ss.str() + "="; if (err.Fail()) return std::string(); res += value.Inspect(&options, err); @@ -1576,6 +1650,7 @@ std::string JSObject::InspectDescriptors(Map map, Error& err) { InspectOptions options; std::string res; + std::stringstream ss; for (int64_t i = 0; i < own_descriptors_count; i++) { Smi details = descriptors.GetDetails(i, err); if (err.Fail()) return std::string(); @@ -1585,7 +1660,10 @@ std::string JSObject::InspectDescriptors(Map map, Error& err) { if (!res.empty()) res += ",\n"; - res += " ." + key.ToString(err) + "="; + ss.str(""); + ss.clear(); + ss << rang::style::bold << rang::fg::yellow << " ." + key.ToString(err) << rang::fg::reset << rang::style::reset; + res += ss.str() + "="; if (err.Fail()) return std::string(); if (descriptors.IsConstFieldDetails(details) || @@ -1600,6 +1678,17 @@ std::string JSObject::InspectDescriptors(Map map, Error& err) { continue; } + // Skip non-fields for now + if (!descriptors.IsFieldDetails(details)) { + Error::PrintInDebugMode("Unknown field Type %" PRId64, + details.GetValue()); + ss.str(""); + ss.clear(); + ss << rang::fg::yellow << "" << rang::fg::reset; + res += ss.str(); + continue; + } + int64_t index = descriptors.FieldIndex(details) - in_object_count; if (descriptors.IsDoubleField(details)) { @@ -2045,15 +2134,24 @@ std::string JSArray::Inspect(InspectOptions* options, Error& err) { if (err.Fail()) return std::string(); std::string res = ""; + if (!elems.empty()) res += " {\n" + elems + "}>"; + return res; + } else { + std::stringstream ss; + ss << rang::fg::yellow << res << ">" << rang::fg::reset; + res = ss.str().c_str(); + return res; + } } } // namespace v8 diff --git a/src/rang.hpp b/src/rang.hpp new file mode 100644 index 00000000..831eda4c --- /dev/null +++ b/src/rang.hpp @@ -0,0 +1,502 @@ +#ifndef RANG_DOT_HPP +#define RANG_DOT_HPP + +#if defined(__unix__) || defined(__unix) || defined(__linux__) +#define OS_LINUX +#elif defined(WIN32) || defined(_WIN32) || defined(_WIN64) +#define OS_WIN +#elif defined(__APPLE__) || defined(__MACH__) +#define OS_MAC +#else +#error Unknown Platform +#endif + +#if defined(OS_LINUX) || defined(OS_MAC) +#include + +#elif defined(OS_WIN) + +#if defined(_WIN32_WINNT) && (_WIN32_WINNT < 0x0600) +#error \ + "Please include rang.hpp before any windows system headers or set _WIN32_WINNT at least to _WIN32_WINNT_VISTA" +#elif !defined(_WIN32_WINNT) +#define _WIN32_WINNT _WIN32_WINNT_VISTA +#endif + +#include +#include +#include + +// Only defined in windows 10 onwards, redefining in lower windows since it +// doesn't gets used in lower versions +// https://docs.microsoft.com/en-us/windows/console/getconsolemode +#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING +#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 +#endif + +#endif + +#include +#include +#include +#include +#include + +namespace rang { + +/* For better compability with most of terminals do not use any style settings + * except of reset, bold and reversed. + * Note that on Windows terminals bold style is same as fgB color. + */ +enum class style { + reset = 0, + bold = 1, + dim = 2, + italic = 3, + underline = 4, + blink = 5, + rblink = 6, + reversed = 7, + conceal = 8, + crossed = 9 +}; + +enum class fg { + black = 30, + red = 31, + green = 32, + yellow = 33, + blue = 34, + magenta = 35, + cyan = 36, + gray = 37, + reset = 39 +}; + +enum class bg { + black = 40, + red = 41, + green = 42, + yellow = 43, + blue = 44, + magenta = 45, + cyan = 46, + gray = 47, + reset = 49 +}; + +enum class fgB { + black = 90, + red = 91, + green = 92, + yellow = 93, + blue = 94, + magenta = 95, + cyan = 96, + gray = 97 +}; + +enum class bgB { + black = 100, + red = 101, + green = 102, + yellow = 103, + blue = 104, + magenta = 105, + cyan = 106, + gray = 107 +}; + +enum class control { // Behaviour of rang function calls + Off = 0, // toggle off rang style/color calls + Auto = 1, // (Default) autodect terminal and colorize if needed + Force = 2 // force ansi color output to non terminal streams +}; +// Use rang::setControlMode to set rang control mode + +enum class winTerm { // Windows Terminal Mode + Auto = 0, // (Default) automatically detects wheter Ansi or Native API + Ansi = 1, // Force use Ansi API + Native = 2 // Force use Native API +}; +// Use rang::setWinTermMode to explicitly set terminal API for Windows +// Calling rang::setWinTermMode have no effect on other OS + +namespace rang_implementation { + + inline std::atomic &controlMode() noexcept + { + static std::atomic value(control::Auto); + return value; + } + + inline std::atomic &winTermMode() noexcept + { + static std::atomic termMode(winTerm::Auto); + return termMode; + } + + inline bool supportsColor() noexcept + { +#if defined(OS_LINUX) || defined(OS_MAC) + + static const bool result = [] { + const char *Terms[] + = { "ansi", "color", "console", "cygwin", "gnome", + "konsole", "kterm", "linux", "msys", "putty", + "rxvt", "screen", "vt100", "xterm" }; + + const char *env_p = std::getenv("TERM"); + if (env_p == nullptr) { + return false; + } + return std::any_of(std::begin(Terms), std::end(Terms), + [&](const char *term) { + return std::strstr(env_p, term) != nullptr; + }); + }(); + +#elif defined(OS_WIN) + // All windows versions support colors through native console methods + static constexpr bool result = true; +#endif + return result; + } + +#ifdef OS_WIN + + + inline bool isMsysPty(int fd) noexcept + { + // Dynamic load for binary compability with old Windows + const auto ptrGetFileInformationByHandleEx + = reinterpret_cast( + GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), + "GetFileInformationByHandleEx")); + if (!ptrGetFileInformationByHandleEx) { + return false; + } + + HANDLE h = reinterpret_cast(_get_osfhandle(fd)); + if (h == INVALID_HANDLE_VALUE) { + return false; + } + + // Check that it's a pipe: + if (GetFileType(h) != FILE_TYPE_PIPE) { + return false; + } + + // POD type is binary compatible with FILE_NAME_INFO from WinBase.h + // It have the same alignment and used to avoid UB in caller code + struct MY_FILE_NAME_INFO { + DWORD FileNameLength; + WCHAR FileName[MAX_PATH]; + }; + + auto pNameInfo = std::unique_ptr( + new (std::nothrow) MY_FILE_NAME_INFO()); + if (!pNameInfo) { + return false; + } + + // Check pipe name is template of + // {"cygwin-","msys-"}XXXXXXXXXXXXXXX-ptyX-XX + if (!ptrGetFileInformationByHandleEx(h, FileNameInfo, pNameInfo.get(), + sizeof(MY_FILE_NAME_INFO))) { + return false; + } + std::wstring name(pNameInfo->FileName, pNameInfo->FileNameLength / sizeof(WCHAR)); + if ((name.find(L"msys-") == std::wstring::npos + && name.find(L"cygwin-") == std::wstring::npos) + || name.find(L"-pty") == std::wstring::npos) { + return false; + } + + return true; + } + +#endif + + inline bool isTerminal(const std::streambuf *osbuf) noexcept + { + using std::cerr; + using std::clog; + using std::cout; +#if defined(OS_LINUX) || defined(OS_MAC) + if (osbuf == cout.rdbuf()) { + static const bool cout_term = isatty(fileno(stdout)) != 0; + return cout_term; + } else if (osbuf == cerr.rdbuf() || osbuf == clog.rdbuf()) { + static const bool cerr_term = isatty(fileno(stderr)) != 0; + return cerr_term; + } +#elif defined(OS_WIN) + if (osbuf == cout.rdbuf()) { + static const bool cout_term + = (_isatty(_fileno(stdout)) || isMsysPty(_fileno(stdout))); + return cout_term; + } else if (osbuf == cerr.rdbuf() || osbuf == clog.rdbuf()) { + static const bool cerr_term + = (_isatty(_fileno(stderr)) || isMsysPty(_fileno(stderr))); + return cerr_term; + } +#endif + return false; + } + + template + using enableStd = typename std::enable_if< + std::is_same::value || std::is_same::value + || std::is_same::value || std::is_same::value + || std::is_same::value, + std::ostream &>::type; + + +#ifdef OS_WIN + + struct SGR { // Select Graphic Rendition parameters for Windows console + BYTE fgColor; // foreground color (0-15) lower 3 rgb bits + intense bit + BYTE bgColor; // background color (0-15) lower 3 rgb bits + intense bit + BYTE bold; // emulated as FOREGROUND_INTENSITY bit + BYTE underline; // emulated as BACKGROUND_INTENSITY bit + BOOLEAN inverse; // swap foreground/bold & background/underline + BOOLEAN conceal; // set foreground/bold to background/underline + }; + + enum class AttrColor : BYTE { // Color attributes for console screen buffer + black = 0, + red = 4, + green = 2, + yellow = 6, + blue = 1, + magenta = 5, + cyan = 3, + gray = 7 + }; + + inline HANDLE getConsoleHandle(const std::streambuf *osbuf) noexcept + { + if (osbuf == std::cout.rdbuf()) { + static const HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); + return hStdout; + } else if (osbuf == std::cerr.rdbuf() || osbuf == std::clog.rdbuf()) { + static const HANDLE hStderr = GetStdHandle(STD_ERROR_HANDLE); + return hStderr; + } + return INVALID_HANDLE_VALUE; + } + + inline bool setWinTermAnsiColors(const std::streambuf *osbuf) noexcept + { + HANDLE h = getConsoleHandle(osbuf); + if (h == INVALID_HANDLE_VALUE) { + return false; + } + DWORD dwMode = 0; + if (!GetConsoleMode(h, &dwMode)) { + return false; + } + dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + if (!SetConsoleMode(h, dwMode)) { + return false; + } + return true; + } + + inline bool supportsAnsi(const std::streambuf *osbuf) noexcept + { + using std::cerr; + using std::clog; + using std::cout; + if (osbuf == cout.rdbuf()) { + static const bool cout_ansi + = (isMsysPty(_fileno(stdout)) || setWinTermAnsiColors(osbuf)); + return cout_ansi; + } else if (osbuf == cerr.rdbuf() || osbuf == clog.rdbuf()) { + static const bool cerr_ansi + = (isMsysPty(_fileno(stderr)) || setWinTermAnsiColors(osbuf)); + return cerr_ansi; + } + return false; + } + + inline const SGR &defaultState() noexcept + { + static const SGR defaultSgr = []() -> SGR { + CONSOLE_SCREEN_BUFFER_INFO info; + WORD attrib = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; + if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), + &info) + || GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), + &info)) { + attrib = info.wAttributes; + } + SGR sgr = { 0, 0, 0, 0, FALSE, FALSE }; + sgr.fgColor = attrib & 0x0F; + sgr.bgColor = (attrib & 0xF0) >> 4; + return sgr; + }(); + return defaultSgr; + } + + inline BYTE ansi2attr(BYTE rgb) noexcept + { + static const AttrColor rev[8] + = { AttrColor::black, AttrColor::red, AttrColor::green, + AttrColor::yellow, AttrColor::blue, AttrColor::magenta, + AttrColor::cyan, AttrColor::gray }; + return static_cast(rev[rgb]); + } + + inline void setWinSGR(rang::bg col, SGR &state) noexcept + { + if (col != rang::bg::reset) { + state.bgColor = ansi2attr(static_cast(col) - 40); + } else { + state.bgColor = defaultState().bgColor; + } + } + + inline void setWinSGR(rang::fg col, SGR &state) noexcept + { + if (col != rang::fg::reset) { + state.fgColor = ansi2attr(static_cast(col) - 30); + } else { + state.fgColor = defaultState().fgColor; + } + } + + inline void setWinSGR(rang::bgB col, SGR &state) noexcept + { + state.bgColor = (BACKGROUND_INTENSITY >> 4) + | ansi2attr(static_cast(col) - 100); + } + + inline void setWinSGR(rang::fgB col, SGR &state) noexcept + { + state.fgColor + = FOREGROUND_INTENSITY | ansi2attr(static_cast(col) - 90); + } + + inline void setWinSGR(rang::style style, SGR &state) noexcept + { + switch (style) { + case rang::style::reset: state = defaultState(); break; + case rang::style::bold: state.bold = FOREGROUND_INTENSITY; break; + case rang::style::underline: + case rang::style::blink: + state.underline = BACKGROUND_INTENSITY; + break; + case rang::style::reversed: state.inverse = TRUE; break; + case rang::style::conceal: state.conceal = TRUE; break; + default: break; + } + } + + inline SGR ¤t_state() noexcept + { + static SGR state = defaultState(); + return state; + } + + inline WORD SGR2Attr(const SGR &state) noexcept + { + WORD attrib = 0; + if (state.conceal) { + if (state.inverse) { + attrib = (state.fgColor << 4) | state.fgColor; + if (state.bold) + attrib |= FOREGROUND_INTENSITY | BACKGROUND_INTENSITY; + } else { + attrib = (state.bgColor << 4) | state.bgColor; + if (state.underline) + attrib |= FOREGROUND_INTENSITY | BACKGROUND_INTENSITY; + } + } else if (state.inverse) { + attrib = (state.fgColor << 4) | state.bgColor; + if (state.bold) attrib |= BACKGROUND_INTENSITY; + if (state.underline) attrib |= FOREGROUND_INTENSITY; + } else { + attrib = state.fgColor | (state.bgColor << 4) | state.bold + | state.underline; + } + return attrib; + } + + template + inline void setWinColorAnsi(std::ostream &os, T const value) + { + os << "\033[" << static_cast(value) << "m"; + } + + template + inline void setWinColorNative(std::ostream &os, T const value) + { + const HANDLE h = getConsoleHandle(os.rdbuf()); + if (h != INVALID_HANDLE_VALUE) { + setWinSGR(value, current_state()); + // Out all buffered text to console with previous settings: + os.flush(); + SetConsoleTextAttribute(h, SGR2Attr(current_state())); + } + } + + template + inline enableStd setColor(std::ostream &os, T const value) + { + if (winTermMode() == winTerm::Auto) { + if (supportsAnsi(os.rdbuf())) { + setWinColorAnsi(os, value); + } else { + setWinColorNative(os, value); + } + } else if (winTermMode() == winTerm::Ansi) { + setWinColorAnsi(os, value); + } else { + setWinColorNative(os, value); + } + return os; + } +#else + template + inline enableStd setColor(std::ostream &os, T const value) + { + return os << "\033[" << static_cast(value) << "m"; + } +#endif +} // namespace rang_implementation + +template +inline rang_implementation::enableStd operator<<(std::ostream &os, + const T value) +{ + const control option = rang_implementation::controlMode(); + switch (option) { + case control::Auto: + return rang_implementation::supportsColor() + && rang_implementation::isTerminal(os.rdbuf()) + ? rang_implementation::setColor(os, value) + : os; + case control::Force: return rang_implementation::setColor(os, value); + default: return os; + } +} + +inline void setWinTermMode(const rang::winTerm value) noexcept +{ + rang_implementation::winTermMode() = value; +} + +inline void setControlMode(const control value) noexcept +{ + rang_implementation::controlMode() = value; +} + +} // namespace rang + +#undef OS_LINUX +#undef OS_WIN +#undef OS_MAC + +#endif /* ifndef RANG_DOT_HPP */ From 72e5fa99bccd3ad303933fac74cd1c675698a0ff Mon Sep 17 00:00:00 2001 From: Daniel Beckert Date: Thu, 23 Aug 2018 09:58:29 -0300 Subject: [PATCH 2/4] src: introduce settings Allow users to select if color output should be on or off. Default is auto, which verifies if current output is a tty and has color support. Colorize detailed output --- src/llnode.cc | 52 ++++ src/llnode.h | 36 +++ src/llscan.cc | 80 ++++-- src/llv8.cc | 154 +++++++---- src/rang.hpp | 723 ++++++++++++++++++++++++-------------------------- 5 files changed, 599 insertions(+), 446 deletions(-) diff --git a/src/llnode.cc b/src/llnode.cc index 31722844..e6e5090b 100644 --- a/src/llnode.cc +++ b/src/llnode.cc @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -14,6 +15,7 @@ #include "src/llscan.h" #include "src/llv8.h" #include "src/node-inl.h" +#include "src/rang.hpp" namespace llnode { @@ -31,6 +33,22 @@ using lldb::SBValue; using lldb::eReturnStatusFailed; using lldb::eReturnStatusSuccessFinishResult; +Settings Settings::instance; +Settings* Settings::GetSettings() { return &Settings::instance; } + +std::string Settings::SetColor(std::string option) { + if (option == "auto" || option == "always" || option == "never") + color = option; + return color; +} + +bool Settings::ShouldUseColor() { + if (color == "always" || + (color == "auto" && rang::rang_implementation::supportsColor() && + rang::rang_implementation::isTerminal(std::cout.rdbuf()))) + return true; + return false; +} bool BacktraceCmd::DoExecute(SBDebugger d, char** cmd, SBCommandReturnObject& result) { @@ -104,6 +122,31 @@ bool BacktraceCmd::DoExecute(SBDebugger d, char** cmd, return true; } +bool SetPropertyColorCmd::DoExecute(SBDebugger d, char** cmd, + SBCommandReturnObject& result) { + if (cmd != nullptr) { + Settings* settings = Settings::GetSettings(); + char* arg = cmd[0]; + if (strcmp(arg, "always") == 0) { + settings->SetColor(arg); + result.Printf("Color set to 'always'\n"); + return true; + } + if (strcmp(arg, "never") == 0) { + settings->SetColor(arg); + result.Printf("Color set to 'never'\n"); + return true; + } + if (strcmp(arg, "auto") == 0) { + settings->SetColor(arg); + result.Printf("Color set to 'auto'\n"); + return true; + } + } + result.Printf("Error: Available options are (always | never | auto)\n"); + return false; +} + bool PrintCmd::DoExecute(SBDebugger d, char** cmd, SBCommandReturnObject& result) { @@ -418,6 +461,15 @@ bool PluginInitialize(SBDebugger d) { #endif // LLDB_SBMemoryRegionInfoList_h_ ); + SBCommand settingsCmd = + v8.AddMultiwordCommand("settings", "Interpreter settings"); + + SBCommand setPropertyCmd = + settingsCmd.AddMultiwordCommand("set", "Set a property"); + + setPropertyCmd.AddCommand("color", new llnode::SetPropertyColorCmd(&llv8), + "Set color property value"); + interpreter.AddCommand("findjsobjects", new llnode::FindObjectsCmd(&llscan), "Alias for `v8 findjsobjects`"); diff --git a/src/llnode.h b/src/llnode.h index 539cd66a..a63ff377 100644 --- a/src/llnode.h +++ b/src/llnode.h @@ -10,6 +10,30 @@ namespace llnode { + +// Use singleton pattern to avoid multiples instatiations +// of Settings +class Settings { + private: + static Settings instance; + + // Private constructors to prevent instantiations + Settings(){}; + Settings(const Settings&){}; + ~Settings(){}; + + // Override assignment operator to avoid copies + Settings& operator=(const Settings&){}; + + std::string color = "auto"; + + public: + static Settings* GetSettings(); + std::string SetColor(std::string option); + std::string GetColor() { return color; }; + bool ShouldUseColor(); +}; + class CommandBase : public lldb::SBCommandPluginInterface {}; class BacktraceCmd : public CommandBase { @@ -24,6 +48,18 @@ class BacktraceCmd : public CommandBase { v8::LLV8* llv8_; }; +class SetPropertyColorCmd : public CommandBase { + public: + SetPropertyColorCmd(v8::LLV8* llv8) : llv8_(llv8) {} + ~SetPropertyColorCmd() override {} + + bool DoExecute(lldb::SBDebugger d, char** cmd, + lldb::SBCommandReturnObject& result) override; + + private: + v8::LLV8* llv8_; +}; + class PrintCmd : public CommandBase { public: PrintCmd(v8::LLV8* llv8, bool detailed) : llv8_(llv8), detailed_(detailed) {} diff --git a/src/llscan.cc b/src/llscan.cc index efa1192b..b061edf5 100644 --- a/src/llscan.cc +++ b/src/llscan.cc @@ -6,10 +6,10 @@ #include #include #include -#include +#include #include #include -#include +#include #include @@ -233,10 +233,17 @@ bool FindInstancesCmd::DoExecute(SBDebugger d, char** cmd, } } else { - rang::setControlMode(rang::control::Force); + Settings* settings = Settings::GetSettings(); + if (settings->ShouldUseColor()) { + rang::setControlMode(rang::control::Force); + } else { + rang::setControlMode(rang::control::Off); + } + std::stringstream ss; - ss << rang::style::bold << rang::fg::red << "No objects found with type name " - << type_name.c_str() << rang::fg::reset << rang::style::reset << std::endl; + ss << rang::style::bold << rang::fg::red + << "No objects found with type name " << type_name.c_str() + << rang::fg::reset << rang::style::reset << std::endl; std::string str(ss.str()); result.Printf(str.c_str()); result.SetStatus(eReturnStatusFailed); @@ -425,7 +432,13 @@ bool NodeInfoCmd::DoExecute(SBDebugger d, char** cmd, bool FindReferencesCmd::DoExecute(SBDebugger d, char** cmd, SBCommandReturnObject& result) { - rang::setControlMode(rang::control::Force); + Settings* settings = Settings::GetSettings(); + if (settings->ShouldUseColor()) { + rang::setControlMode(rang::control::Force); + } else { + rang::setControlMode(rang::control::Off); + } + if (cmd == nullptr || *cmd == nullptr) { result.SetError("USAGE: v8 findrefs expr\n"); return false; @@ -705,22 +718,34 @@ void FindReferencesCmd::ReferenceScanner::PrintContextRefs( } std::string FindReferencesCmd::ObjectScanner::GetPropertyReferenceString() { - rang::setControlMode(rang::control::Force); + Settings* settings = Settings::GetSettings(); + if (settings->ShouldUseColor()) { + rang::setControlMode(rang::control::Force); + } else { + rang::setControlMode(rang::control::Off); + } + std::stringstream ss; - ss << rang::fg::cyan << "0x%" PRIx64 << rang::fg::reset << ": " << rang::fg::magenta - << "%s" << rang::style::bold << rang::fg::yellow << ".%s" << rang::fg::reset - << rang::style::reset << "=" << rang::fg::cyan << "0x%" PRIx64 << rang::fg::reset - << "\n"; + ss << rang::fg::cyan << "0x%" PRIx64 << rang::fg::reset << ": " + << rang::fg::magenta << "%s" << rang::style::bold << rang::fg::yellow + << ".%s" << rang::fg::reset << rang::style::reset << "=" << rang::fg::cyan + << "0x%" PRIx64 << rang::fg::reset << "\n"; return ss.str(); } std::string FindReferencesCmd::ObjectScanner::GetArrayReferenceString() { - rang::setControlMode(rang::control::Force); + Settings* settings = Settings::GetSettings(); + if (settings->ShouldUseColor()) { + rang::setControlMode(rang::control::Force); + } else { + rang::setControlMode(rang::control::Off); + } + std::stringstream ss; - ss << rang::fg::cyan << "0x%" PRIx64 << rang::fg::reset << ": " << rang::fg::magenta - << "%s" << rang::style::bold << rang::fg::yellow << "[%" PRId64 "]" << rang::fg::reset - << rang::style::reset << "=" << rang::fg::cyan << "0x%" PRIx64 << rang::fg::reset - << "\n"; + ss << rang::fg::cyan << "0x%" PRIx64 << rang::fg::reset << ": " + << rang::fg::magenta << "%s" << rang::style::bold << rang::fg::yellow + << "[%" PRId64 "]" << rang::fg::reset << rang::style::reset << "=" + << rang::fg::cyan << "0x%" PRIx64 << rang::fg::reset << "\n"; return ss.str(); } @@ -739,8 +764,8 @@ void FindReferencesCmd::ReferenceScanner::PrintRefs( std::string type_name = js_obj.GetTypeName(err); std::string reference_template(GetArrayReferenceString()); - result.Printf(reference_template.c_str(), js_obj.raw(), type_name.c_str(), i, - search_value_.raw()); + result.Printf(reference_template.c_str(), js_obj.raw(), type_name.c_str(), + i, search_value_.raw()); } // Walk all the properties in this object. @@ -757,8 +782,8 @@ void FindReferencesCmd::ReferenceScanner::PrintRefs( std::string type_name = js_obj.GetTypeName(err); std::string reference_template(GetPropertyReferenceString()); - result.Printf(reference_template.c_str(), js_obj.raw(), - type_name.c_str(), key.c_str(), search_value_.raw()); + result.Printf(reference_template.c_str(), js_obj.raw(), type_name.c_str(), + key.c_str(), search_value_.raw()); } } } @@ -933,8 +958,8 @@ void FindReferencesCmd::PropertyScanner::PrintRefs( std::string type_name = js_obj.GetTypeName(err); std::string reference_template(GetPropertyReferenceString()); - result.Printf(reference_template.c_str(), js_obj.raw(), - type_name.c_str(), key.c_str(), entry.second.raw()); + result.Printf(reference_template.c_str(), js_obj.raw(), type_name.c_str(), + key.c_str(), entry.second.raw()); } } } @@ -1001,7 +1026,8 @@ void FindReferencesCmd::StringScanner::PrintRefs(SBCommandReturnObject& result, std::string type_name = js_obj.GetTypeName(err); std::stringstream ss; - ss << rang::fg::cyan << std::hex << js_obj.raw() << std::dec << rang::fg::reset; + ss << rang::fg::cyan << std::hex << js_obj.raw() << std::dec + << rang::fg::reset; result.Printf("%s: %s[%" PRId64 "]=0x%" PRIx64 " '%s'\n", ss.str().c_str(), type_name.c_str(), i, v.raw(), @@ -1035,10 +1061,10 @@ void FindReferencesCmd::StringScanner::PrintRefs(SBCommandReturnObject& result, std::string type_name = js_obj.GetTypeName(err); std::stringstream ss; - ss << rang::fg::cyan << "0x" << std::hex << js_obj.raw() << rang::fg::reset - << std::dec << ": " << type_name.c_str() << "." << key.c_str() << "=" - << std::hex << entry.second.raw() << std::dec << " '" << value.c_str() - << "'" << std::endl; + ss << rang::fg::cyan << "0x" << std::hex << js_obj.raw() + << rang::fg::reset << std::dec << ": " << type_name.c_str() << "." + << key.c_str() << "=" << std::hex << entry.second.raw() << std::dec + << " '" << value.c_str() << "'" << std::endl; result.Printf(ss.str().c_str()); } diff --git a/src/llv8.cc b/src/llv8.cc index 682aece2..573a0ce8 100644 --- a/src/llv8.cc +++ b/src/llv8.cc @@ -4,11 +4,12 @@ #include #include #include -#include #include +#include #include "llv8-inl.h" #include "llv8.h" +#include "src/llnode.h" #include "src/rang.hpp" namespace llnode { @@ -380,7 +381,9 @@ std::string JSFunction::GetDebugLine(std::string args, Error& err) { std::string JSFunction::Inspect(InspectOptions* options, Error& err) { + std::stringstream ss; std::string res = "detailed) { @@ -389,8 +392,19 @@ std::string JSFunction::Inspect(InspectOptions* options, Error& err) { Context context(context_obj); + ss << rang::fg::magenta << res << rang::fg::reset; + res = ss.str(); + + ss.str(""); + ss.clear(); + ss << rang::style::bold << rang::fg::yellow << "\n context" + << rang::fg::reset << rang::style::reset << "=" << rang::fg::cyan + << "0x%016" PRIx64 << rang::fg::reset; + + char tmp[128]; - snprintf(tmp, sizeof(tmp), "\n context=0x%016" PRIx64, context.raw()); + snprintf(tmp, sizeof(tmp), ss.str().c_str(), context.raw()); + // snprintf(tmp, sizeof(tmp), "\n context=0x%016" PRIx64, context.raw()); res += tmp; { @@ -420,15 +434,12 @@ std::string JSFunction::Inspect(InspectOptions* options, Error& err) { } } res = res + ">"; - } - else { + } else { std::stringstream ss; - ss << rang::fg::yellow << res << ">" << rang::fg::reset; + ss << rang::fg::yellow << res << ">" << rang::fg::reset; res = ss.str().c_str(); - } return res; - } @@ -778,7 +789,13 @@ std::string HeapObject::ToString(Error& err) { std::string HeapObject::Inspect(InspectOptions* options, Error& err) { - rang::setControlMode(rang::control::Force); + Settings* settings = Settings::GetSettings(); + if (settings->ShouldUseColor()) { + rang::setControlMode(rang::control::Force); + } else { + rang::setControlMode(rang::control::Off); + } + int64_t type = GetType(err); if (err.Fail()) return std::string(); @@ -792,7 +809,8 @@ std::string HeapObject::Inspect(InspectOptions* options, Error& err) { map.raw()); } else { std::stringstream ss; - ss << rang::fg::cyan << "0x" << std::hex << raw() << std::dec << rang::fg::reset; + ss << rang::fg::cyan << "0x" << std::hex << raw() << std::dec + << rang::fg::reset; snprintf(buf, sizeof(buf), "%s:", ss.str().c_str()); } @@ -989,7 +1007,8 @@ std::string HeapNumber::ToString(bool whole, Error& err) { std::string HeapNumber::Inspect(Error& err) { std::stringstream ss; - ss << rang::fg::yellow << "" << rang::fg::reset; + ss << rang::fg::yellow << "" + << rang::fg::reset; return ss.str().c_str(); } @@ -1061,13 +1080,20 @@ std::string FixedArray::Inspect(InspectOptions* options, Error& err) { if (err.Fail()) return std::string(); if (options->detailed) { + std::stringstream ss; + ss << rang::fg::magenta << res; std::string contents = InspectContents(length_smi.GetValue(), err); - if (!contents.empty()) res += " contents={\n" + contents + "}"; + if (!contents.empty()) { + ss << " contents" << rang::fg::reset << "={\n" + contents + "}"; + res = ss.str(); + } + res += ">"; + } else { + std::stringstream ss; + ss << rang::fg::yellow << res + ">" << rang::fg::reset; + res = ss.str(); } - - std::stringstream ss; - ss << rang::fg::yellow << res + ">" << rang::fg::reset; - return ss.str().c_str(); + return res.c_str(); } @@ -1084,7 +1110,8 @@ std::string FixedArray::InspectContents(int length, Error& err) { char tmp[128]; std::stringstream ss; - ss << rang::style::bold << rang::fg::yellow << " [" << i << "]" << rang::fg::reset << rang::style::reset << "="; + ss << rang::style::bold << rang::fg::yellow << " [" << i << "]" + << rang::fg::reset << rang::style::reset << "="; snprintf(tmp, sizeof(tmp), "%s", ss.str().c_str()); res += tmp + value.Inspect(&options, err); if (err.Fail()) return std::string(); @@ -1156,12 +1183,12 @@ std::string Context::Inspect(InspectOptions* options, Error& err) { HeapObject heap_previous = HeapObject(previous); if (heap_previous.Check()) { - char tmp[128]; - snprintf( - tmp, sizeof(tmp), - (options->get_indent_spaces() + "(previous)=0x%016" PRIx64).c_str(), - previous.raw()); - res += std::string(tmp) + ":,"; + std::stringstream ss; + ss << rang::style::bold << rang::fg::yellow << options->get_indent_spaces() << "(previous)" + << rang::fg::reset << rang::style::reset << "=" << rang::fg::cyan + << "0x" << std::hex << previous.raw() << std::dec << rang::fg::reset; + + res += ss.str() + ":,"; } if (!res.empty()) res += "\n"; @@ -1169,12 +1196,12 @@ std::string Context::Inspect(InspectOptions* options, Error& err) { if (v8()->context()->hasClosure()) { JSFunction closure = Closure(err); if (err.Fail()) return std::string(); - char tmp[128]; - snprintf( - tmp, sizeof(tmp), - (options->get_indent_spaces() + "(closure)=0x%016" PRIx64 " {").c_str(), - closure.raw()); - res += tmp; + + std::stringstream ss; + ss << rang::style::bold << rang::fg::yellow << options->get_indent_spaces() << "(closure)" + << rang::fg::reset << rang::style::reset << "=" << rang::fg::cyan + << "0x" << std::hex << closure.raw() << std::dec << rang::fg::reset << " {"; + res += ss.str(); InspectOptions closure_options; res += closure.Inspect(&closure_options, err) + "}"; @@ -1208,7 +1235,9 @@ std::string Context::Inspect(InspectOptions* options, Error& err) { if (!res.empty()) res += ",\n"; - res += options->get_indent_spaces() + name.ToString(err) + "="; + ss << options->get_indent_spaces() << rang::style::bold << rang::fg::yellow << name.ToString(err) + << rang::fg::reset << rang::style::reset; + res += ss.str() + "="; if (err.Fail()) return std::string(); Value value = it.GetValue(err); @@ -1229,14 +1258,22 @@ std::string Oddball::Inspect(Error& err) { int64_t kind_val = kind.GetValue(); std::string str; - if (kind_val == v8()->oddball()->kException) str = ""; - else if (kind_val == v8()->oddball()->kFalse) str = ""; - else if (kind_val == v8()->oddball()->kTrue) str = ""; - else if (kind_val == v8()->oddball()->kUndefined) str = ""; - else if (kind_val == v8()->oddball()->kNull) str = ""; - else if (kind_val == v8()->oddball()->kTheHole) str = ""; - else if (kind_val == v8()->oddball()->kUninitialized) str = ""; - else str = ""; + if (kind_val == v8()->oddball()->kException) + str = ""; + else if (kind_val == v8()->oddball()->kFalse) + str = ""; + else if (kind_val == v8()->oddball()->kTrue) + str = ""; + else if (kind_val == v8()->oddball()->kUndefined) + str = ""; + else if (kind_val == v8()->oddball()->kNull) + str = ""; + else if (kind_val == v8()->oddball()->kTheHole) + str = ""; + else if (kind_val == v8()->oddball()->kUninitialized) + str = ""; + else + str = ""; std::stringstream ss; ss << rang::fg::yellow << str << rang::fg::reset; @@ -1372,13 +1409,25 @@ std::string Map::Inspect(InspectOptions* options, Error& err) { if (err.Fail()) return std::string(); char tmp[256]; - snprintf(tmp, sizeof(tmp), - "(own_descriptors_count), in_object_properties_or_constructor.c_str(), static_cast(in_object_properties_or_constructor_index), static_cast(instance_size), descriptors_obj.raw()); + + // snprintf(tmp, sizeof(tmp), + // "(own_descriptors_count), + // in_object_properties_or_constructor.c_str(), + // static_cast(in_object_properties_or_constructor_index), + // static_cast(instance_size), descriptors_obj.raw()); if (!options->detailed) { return std::string(tmp) + ">"; } @@ -1444,7 +1493,9 @@ std::string JSObject::Inspect(InspectOptions* options, Error& err) { if (!fields.empty()) { std::stringstream ss; - ss << rang::fg::magenta << "\n internal fields" << rang::fg::reset << " {" << std::endl << fields << "}>"; + ss << rang::fg::magenta << "\n internal fields" << rang::fg::reset + << " {" << std::endl + << fields << "}>"; res += ss.str().c_str(); } return res; @@ -1454,7 +1505,6 @@ std::string JSObject::Inspect(InspectOptions* options, Error& err) { res = ss.str().c_str(); return res; } - } @@ -1507,7 +1557,9 @@ std::string JSObject::InspectProperties(Error& err) { if (!elems.empty()) { std::stringstream ss; - ss << rang::fg::magenta << "elements" << rang::fg::reset << " {" << std::endl << elems << "}"; + ss << rang::fg::magenta << "elements" << rang::fg::reset << " {" + << std::endl + << elems << "}"; } HeapObject map_obj = GetMap(err); @@ -1529,7 +1581,9 @@ std::string JSObject::InspectProperties(Error& err) { if (!props.empty()) { if (!res.empty()) res += "\n "; std::stringstream ss; - ss << rang::fg::magenta << "properties" << rang::fg::reset << " {" << std::endl << props << "}"; + ss << rang::fg::magenta << "properties" << rang::fg::reset << " {" + << std::endl + << props << "}"; res += ss.str().c_str(); } @@ -1574,7 +1628,9 @@ std::string JSObject::InspectElements(int64_t length, Error& err) { char tmp[64]; std::stringstream ss; - ss << rang::style::bold << rang::fg::yellow << " [" << static_cast(i) << "]" << rang::fg::reset << rang::style::reset << "="; + ss << rang::style::bold << rang::fg::yellow << " [" + << static_cast(i) << "]" << rang::fg::reset << rang::style::reset + << "="; snprintf(tmp, sizeof(tmp), "%s", ss.str().c_str()); res += tmp; @@ -1616,7 +1672,8 @@ std::string JSObject::InspectDictionary(Error& err) { ss.str(""); ss.clear(); - ss << rang::style::bold << rang::fg::yellow << " ." + key.ToString(err) << rang::fg::reset << rang::style::reset; + ss << rang::style::bold << rang::fg::yellow << " ." + key.ToString(err) + << rang::fg::reset << rang::style::reset; res += ss.str() + "="; if (err.Fail()) return std::string(); @@ -1662,7 +1719,8 @@ std::string JSObject::InspectDescriptors(Map map, Error& err) { ss.str(""); ss.clear(); - ss << rang::style::bold << rang::fg::yellow << " ." + key.ToString(err) << rang::fg::reset << rang::style::reset; + ss << rang::style::bold << rang::fg::yellow << " ." + key.ToString(err) + << rang::fg::reset << rang::style::reset; res += ss.str() + "="; if (err.Fail()) return std::string(); @@ -2148,7 +2206,7 @@ std::string JSArray::Inspect(InspectOptions* options, Error& err) { return res; } else { std::stringstream ss; - ss << rang::fg::yellow << res << ">" << rang::fg::reset; + ss << rang::fg::yellow << res + ">" << rang::fg::reset; res = ss.str().c_str(); return res; } diff --git a/src/rang.hpp b/src/rang.hpp index 831eda4c..52415f20 100644 --- a/src/rang.hpp +++ b/src/rang.hpp @@ -17,14 +17,14 @@ #elif defined(OS_WIN) #if defined(_WIN32_WINNT) && (_WIN32_WINNT < 0x0600) -#error \ - "Please include rang.hpp before any windows system headers or set _WIN32_WINNT at least to _WIN32_WINNT_VISTA" +#error \ + "Please include rang.hpp before any windows system headers or set _WIN32_WINNT at least to _WIN32_WINNT_VISTA" #elif !defined(_WIN32_WINNT) #define _WIN32_WINNT _WIN32_WINNT_VISTA #endif -#include #include +#include #include // Only defined in windows 10 onwards, redefining in lower windows since it @@ -49,448 +49,429 @@ namespace rang { * Note that on Windows terminals bold style is same as fgB color. */ enum class style { - reset = 0, - bold = 1, - dim = 2, - italic = 3, - underline = 4, - blink = 5, - rblink = 6, - reversed = 7, - conceal = 8, - crossed = 9 + reset = 0, + bold = 1, + dim = 2, + italic = 3, + underline = 4, + blink = 5, + rblink = 6, + reversed = 7, + conceal = 8, + crossed = 9 }; enum class fg { - black = 30, - red = 31, - green = 32, - yellow = 33, - blue = 34, - magenta = 35, - cyan = 36, - gray = 37, - reset = 39 + black = 30, + red = 31, + green = 32, + yellow = 33, + blue = 34, + magenta = 35, + cyan = 36, + gray = 37, + reset = 39 }; enum class bg { - black = 40, - red = 41, - green = 42, - yellow = 43, - blue = 44, - magenta = 45, - cyan = 46, - gray = 47, - reset = 49 + black = 40, + red = 41, + green = 42, + yellow = 43, + blue = 44, + magenta = 45, + cyan = 46, + gray = 47, + reset = 49 }; enum class fgB { - black = 90, - red = 91, - green = 92, - yellow = 93, - blue = 94, - magenta = 95, - cyan = 96, - gray = 97 + black = 90, + red = 91, + green = 92, + yellow = 93, + blue = 94, + magenta = 95, + cyan = 96, + gray = 97 }; enum class bgB { - black = 100, - red = 101, - green = 102, - yellow = 103, - blue = 104, - magenta = 105, - cyan = 106, - gray = 107 + black = 100, + red = 101, + green = 102, + yellow = 103, + blue = 104, + magenta = 105, + cyan = 106, + gray = 107 }; enum class control { // Behaviour of rang function calls - Off = 0, // toggle off rang style/color calls - Auto = 1, // (Default) autodect terminal and colorize if needed - Force = 2 // force ansi color output to non terminal streams + Off = 0, // toggle off rang style/color calls + Auto = 1, // (Default) autodect terminal and colorize if needed + Force = 2 // force ansi color output to non terminal streams }; // Use rang::setControlMode to set rang control mode enum class winTerm { // Windows Terminal Mode - Auto = 0, // (Default) automatically detects wheter Ansi or Native API - Ansi = 1, // Force use Ansi API - Native = 2 // Force use Native API + Auto = 0, // (Default) automatically detects wheter Ansi or Native API + Ansi = 1, // Force use Ansi API + Native = 2 // Force use Native API }; // Use rang::setWinTermMode to explicitly set terminal API for Windows // Calling rang::setWinTermMode have no effect on other OS namespace rang_implementation { - inline std::atomic &controlMode() noexcept - { - static std::atomic value(control::Auto); - return value; - } +inline std::atomic &controlMode() noexcept { + static std::atomic value(control::Auto); + return value; +} - inline std::atomic &winTermMode() noexcept - { - static std::atomic termMode(winTerm::Auto); - return termMode; - } +inline std::atomic &winTermMode() noexcept { + static std::atomic termMode(winTerm::Auto); + return termMode; +} - inline bool supportsColor() noexcept - { +inline bool supportsColor() noexcept { #if defined(OS_LINUX) || defined(OS_MAC) - static const bool result = [] { - const char *Terms[] - = { "ansi", "color", "console", "cygwin", "gnome", - "konsole", "kterm", "linux", "msys", "putty", - "rxvt", "screen", "vt100", "xterm" }; - - const char *env_p = std::getenv("TERM"); - if (env_p == nullptr) { - return false; - } - return std::any_of(std::begin(Terms), std::end(Terms), - [&](const char *term) { - return std::strstr(env_p, term) != nullptr; - }); - }(); + static const bool result = [] { + const char *Terms[] = {"ansi", "color", "console", "cygwin", "gnome", + "konsole", "kterm", "linux", "msys", "putty", + "rxvt", "screen", "vt100", "xterm"}; + + const char *env_p = std::getenv("TERM"); + if (env_p == nullptr) { + return false; + } + return std::any_of( + std::begin(Terms), std::end(Terms), + [&](const char *term) { return std::strstr(env_p, term) != nullptr; }); + }(); #elif defined(OS_WIN) - // All windows versions support colors through native console methods - static constexpr bool result = true; + // All windows versions support colors through native console methods + static constexpr bool result = true; #endif - return result; - } + return result; +} #ifdef OS_WIN - inline bool isMsysPty(int fd) noexcept - { - // Dynamic load for binary compability with old Windows - const auto ptrGetFileInformationByHandleEx - = reinterpret_cast( - GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), - "GetFileInformationByHandleEx")); - if (!ptrGetFileInformationByHandleEx) { - return false; - } - - HANDLE h = reinterpret_cast(_get_osfhandle(fd)); - if (h == INVALID_HANDLE_VALUE) { - return false; - } - - // Check that it's a pipe: - if (GetFileType(h) != FILE_TYPE_PIPE) { - return false; - } - - // POD type is binary compatible with FILE_NAME_INFO from WinBase.h - // It have the same alignment and used to avoid UB in caller code - struct MY_FILE_NAME_INFO { - DWORD FileNameLength; - WCHAR FileName[MAX_PATH]; - }; - - auto pNameInfo = std::unique_ptr( - new (std::nothrow) MY_FILE_NAME_INFO()); - if (!pNameInfo) { - return false; - } - - // Check pipe name is template of - // {"cygwin-","msys-"}XXXXXXXXXXXXXXX-ptyX-XX - if (!ptrGetFileInformationByHandleEx(h, FileNameInfo, pNameInfo.get(), - sizeof(MY_FILE_NAME_INFO))) { - return false; - } - std::wstring name(pNameInfo->FileName, pNameInfo->FileNameLength / sizeof(WCHAR)); - if ((name.find(L"msys-") == std::wstring::npos - && name.find(L"cygwin-") == std::wstring::npos) - || name.find(L"-pty") == std::wstring::npos) { - return false; - } - - return true; - } +inline bool isMsysPty(int fd) noexcept { + // Dynamic load for binary compability with old Windows + const auto ptrGetFileInformationByHandleEx = + reinterpret_cast( + GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), + "GetFileInformationByHandleEx")); + if (!ptrGetFileInformationByHandleEx) { + return false; + } + + HANDLE h = reinterpret_cast(_get_osfhandle(fd)); + if (h == INVALID_HANDLE_VALUE) { + return false; + } + + // Check that it's a pipe: + if (GetFileType(h) != FILE_TYPE_PIPE) { + return false; + } + + // POD type is binary compatible with FILE_NAME_INFO from WinBase.h + // It have the same alignment and used to avoid UB in caller code + struct MY_FILE_NAME_INFO { + DWORD FileNameLength; + WCHAR FileName[MAX_PATH]; + }; + + auto pNameInfo = std::unique_ptr(new (std::nothrow) + MY_FILE_NAME_INFO()); + if (!pNameInfo) { + return false; + } + + // Check pipe name is template of + // {"cygwin-","msys-"}XXXXXXXXXXXXXXX-ptyX-XX + if (!ptrGetFileInformationByHandleEx(h, FileNameInfo, pNameInfo.get(), + sizeof(MY_FILE_NAME_INFO))) { + return false; + } + std::wstring name(pNameInfo->FileName, + pNameInfo->FileNameLength / sizeof(WCHAR)); + if ((name.find(L"msys-") == std::wstring::npos && + name.find(L"cygwin-") == std::wstring::npos) || + name.find(L"-pty") == std::wstring::npos) { + return false; + } + + return true; +} #endif - inline bool isTerminal(const std::streambuf *osbuf) noexcept - { - using std::cerr; - using std::clog; - using std::cout; +inline bool isTerminal(const std::streambuf *osbuf) noexcept { + using std::cerr; + using std::clog; + using std::cout; #if defined(OS_LINUX) || defined(OS_MAC) - if (osbuf == cout.rdbuf()) { - static const bool cout_term = isatty(fileno(stdout)) != 0; - return cout_term; - } else if (osbuf == cerr.rdbuf() || osbuf == clog.rdbuf()) { - static const bool cerr_term = isatty(fileno(stderr)) != 0; - return cerr_term; - } + if (osbuf == cout.rdbuf()) { + static const bool cout_term = isatty(fileno(stdout)) != 0; + return cout_term; + } else if (osbuf == cerr.rdbuf() || osbuf == clog.rdbuf()) { + static const bool cerr_term = isatty(fileno(stderr)) != 0; + return cerr_term; + } #elif defined(OS_WIN) - if (osbuf == cout.rdbuf()) { - static const bool cout_term - = (_isatty(_fileno(stdout)) || isMsysPty(_fileno(stdout))); - return cout_term; - } else if (osbuf == cerr.rdbuf() || osbuf == clog.rdbuf()) { - static const bool cerr_term - = (_isatty(_fileno(stderr)) || isMsysPty(_fileno(stderr))); - return cerr_term; - } + if (osbuf == cout.rdbuf()) { + static const bool cout_term = + (_isatty(_fileno(stdout)) || isMsysPty(_fileno(stdout))); + return cout_term; + } else if (osbuf == cerr.rdbuf() || osbuf == clog.rdbuf()) { + static const bool cerr_term = + (_isatty(_fileno(stderr)) || isMsysPty(_fileno(stderr))); + return cerr_term; + } #endif - return false; - } + return false; +} - template - using enableStd = typename std::enable_if< - std::is_same::value || std::is_same::value - || std::is_same::value || std::is_same::value - || std::is_same::value, - std::ostream &>::type; +template +using enableStd = typename std::enable_if< + std::is_same::value || std::is_same::value || + std::is_same::value || std::is_same::value || + std::is_same::value, + std::ostream &>::type; #ifdef OS_WIN - struct SGR { // Select Graphic Rendition parameters for Windows console - BYTE fgColor; // foreground color (0-15) lower 3 rgb bits + intense bit - BYTE bgColor; // background color (0-15) lower 3 rgb bits + intense bit - BYTE bold; // emulated as FOREGROUND_INTENSITY bit - BYTE underline; // emulated as BACKGROUND_INTENSITY bit - BOOLEAN inverse; // swap foreground/bold & background/underline - BOOLEAN conceal; // set foreground/bold to background/underline - }; - - enum class AttrColor : BYTE { // Color attributes for console screen buffer - black = 0, - red = 4, - green = 2, - yellow = 6, - blue = 1, - magenta = 5, - cyan = 3, - gray = 7 - }; - - inline HANDLE getConsoleHandle(const std::streambuf *osbuf) noexcept - { - if (osbuf == std::cout.rdbuf()) { - static const HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); - return hStdout; - } else if (osbuf == std::cerr.rdbuf() || osbuf == std::clog.rdbuf()) { - static const HANDLE hStderr = GetStdHandle(STD_ERROR_HANDLE); - return hStderr; - } - return INVALID_HANDLE_VALUE; - } +struct SGR { // Select Graphic Rendition parameters for Windows console + BYTE fgColor; // foreground color (0-15) lower 3 rgb bits + intense bit + BYTE bgColor; // background color (0-15) lower 3 rgb bits + intense bit + BYTE bold; // emulated as FOREGROUND_INTENSITY bit + BYTE underline; // emulated as BACKGROUND_INTENSITY bit + BOOLEAN inverse; // swap foreground/bold & background/underline + BOOLEAN conceal; // set foreground/bold to background/underline +}; - inline bool setWinTermAnsiColors(const std::streambuf *osbuf) noexcept - { - HANDLE h = getConsoleHandle(osbuf); - if (h == INVALID_HANDLE_VALUE) { - return false; - } - DWORD dwMode = 0; - if (!GetConsoleMode(h, &dwMode)) { - return false; - } - dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; - if (!SetConsoleMode(h, dwMode)) { - return false; - } - return true; - } +enum class AttrColor : BYTE { // Color attributes for console screen buffer + black = 0, + red = 4, + green = 2, + yellow = 6, + blue = 1, + magenta = 5, + cyan = 3, + gray = 7 +}; - inline bool supportsAnsi(const std::streambuf *osbuf) noexcept - { - using std::cerr; - using std::clog; - using std::cout; - if (osbuf == cout.rdbuf()) { - static const bool cout_ansi - = (isMsysPty(_fileno(stdout)) || setWinTermAnsiColors(osbuf)); - return cout_ansi; - } else if (osbuf == cerr.rdbuf() || osbuf == clog.rdbuf()) { - static const bool cerr_ansi - = (isMsysPty(_fileno(stderr)) || setWinTermAnsiColors(osbuf)); - return cerr_ansi; - } - return false; - } +inline HANDLE getConsoleHandle(const std::streambuf *osbuf) noexcept { + if (osbuf == std::cout.rdbuf()) { + static const HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); + return hStdout; + } else if (osbuf == std::cerr.rdbuf() || osbuf == std::clog.rdbuf()) { + static const HANDLE hStderr = GetStdHandle(STD_ERROR_HANDLE); + return hStderr; + } + return INVALID_HANDLE_VALUE; +} - inline const SGR &defaultState() noexcept - { - static const SGR defaultSgr = []() -> SGR { - CONSOLE_SCREEN_BUFFER_INFO info; - WORD attrib = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; - if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), - &info) - || GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), - &info)) { - attrib = info.wAttributes; - } - SGR sgr = { 0, 0, 0, 0, FALSE, FALSE }; - sgr.fgColor = attrib & 0x0F; - sgr.bgColor = (attrib & 0xF0) >> 4; - return sgr; - }(); - return defaultSgr; - } +inline bool setWinTermAnsiColors(const std::streambuf *osbuf) noexcept { + HANDLE h = getConsoleHandle(osbuf); + if (h == INVALID_HANDLE_VALUE) { + return false; + } + DWORD dwMode = 0; + if (!GetConsoleMode(h, &dwMode)) { + return false; + } + dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + if (!SetConsoleMode(h, dwMode)) { + return false; + } + return true; +} - inline BYTE ansi2attr(BYTE rgb) noexcept - { - static const AttrColor rev[8] - = { AttrColor::black, AttrColor::red, AttrColor::green, - AttrColor::yellow, AttrColor::blue, AttrColor::magenta, - AttrColor::cyan, AttrColor::gray }; - return static_cast(rev[rgb]); - } +inline bool supportsAnsi(const std::streambuf *osbuf) noexcept { + using std::cerr; + using std::clog; + using std::cout; + if (osbuf == cout.rdbuf()) { + static const bool cout_ansi = + (isMsysPty(_fileno(stdout)) || setWinTermAnsiColors(osbuf)); + return cout_ansi; + } else if (osbuf == cerr.rdbuf() || osbuf == clog.rdbuf()) { + static const bool cerr_ansi = + (isMsysPty(_fileno(stderr)) || setWinTermAnsiColors(osbuf)); + return cerr_ansi; + } + return false; +} - inline void setWinSGR(rang::bg col, SGR &state) noexcept - { - if (col != rang::bg::reset) { - state.bgColor = ansi2attr(static_cast(col) - 40); - } else { - state.bgColor = defaultState().bgColor; - } +inline const SGR &defaultState() noexcept { + static const SGR defaultSgr = []() -> SGR { + CONSOLE_SCREEN_BUFFER_INFO info; + WORD attrib = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; + if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info) || + GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), &info)) { + attrib = info.wAttributes; } + SGR sgr = {0, 0, 0, 0, FALSE, FALSE}; + sgr.fgColor = attrib & 0x0F; + sgr.bgColor = (attrib & 0xF0) >> 4; + return sgr; + }(); + return defaultSgr; +} - inline void setWinSGR(rang::fg col, SGR &state) noexcept - { - if (col != rang::fg::reset) { - state.fgColor = ansi2attr(static_cast(col) - 30); - } else { - state.fgColor = defaultState().fgColor; - } - } +inline BYTE ansi2attr(BYTE rgb) noexcept { + static const AttrColor rev[8] = { + AttrColor::black, AttrColor::red, AttrColor::green, AttrColor::yellow, + AttrColor::blue, AttrColor::magenta, AttrColor::cyan, AttrColor::gray}; + return static_cast(rev[rgb]); +} - inline void setWinSGR(rang::bgB col, SGR &state) noexcept - { - state.bgColor = (BACKGROUND_INTENSITY >> 4) - | ansi2attr(static_cast(col) - 100); - } +inline void setWinSGR(rang::bg col, SGR &state) noexcept { + if (col != rang::bg::reset) { + state.bgColor = ansi2attr(static_cast(col) - 40); + } else { + state.bgColor = defaultState().bgColor; + } +} - inline void setWinSGR(rang::fgB col, SGR &state) noexcept - { - state.fgColor - = FOREGROUND_INTENSITY | ansi2attr(static_cast(col) - 90); - } +inline void setWinSGR(rang::fg col, SGR &state) noexcept { + if (col != rang::fg::reset) { + state.fgColor = ansi2attr(static_cast(col) - 30); + } else { + state.fgColor = defaultState().fgColor; + } +} - inline void setWinSGR(rang::style style, SGR &state) noexcept - { - switch (style) { - case rang::style::reset: state = defaultState(); break; - case rang::style::bold: state.bold = FOREGROUND_INTENSITY; break; - case rang::style::underline: - case rang::style::blink: - state.underline = BACKGROUND_INTENSITY; - break; - case rang::style::reversed: state.inverse = TRUE; break; - case rang::style::conceal: state.conceal = TRUE; break; - default: break; - } - } +inline void setWinSGR(rang::bgB col, SGR &state) noexcept { + state.bgColor = + (BACKGROUND_INTENSITY >> 4) | ansi2attr(static_cast(col) - 100); +} - inline SGR ¤t_state() noexcept - { - static SGR state = defaultState(); - return state; - } +inline void setWinSGR(rang::fgB col, SGR &state) noexcept { + state.fgColor = FOREGROUND_INTENSITY | ansi2attr(static_cast(col) - 90); +} - inline WORD SGR2Attr(const SGR &state) noexcept - { - WORD attrib = 0; - if (state.conceal) { - if (state.inverse) { - attrib = (state.fgColor << 4) | state.fgColor; - if (state.bold) - attrib |= FOREGROUND_INTENSITY | BACKGROUND_INTENSITY; - } else { - attrib = (state.bgColor << 4) | state.bgColor; - if (state.underline) - attrib |= FOREGROUND_INTENSITY | BACKGROUND_INTENSITY; - } - } else if (state.inverse) { - attrib = (state.fgColor << 4) | state.bgColor; - if (state.bold) attrib |= BACKGROUND_INTENSITY; - if (state.underline) attrib |= FOREGROUND_INTENSITY; - } else { - attrib = state.fgColor | (state.bgColor << 4) | state.bold - | state.underline; - } - return attrib; - } +inline void setWinSGR(rang::style style, SGR &state) noexcept { + switch (style) { + case rang::style::reset: + state = defaultState(); + break; + case rang::style::bold: + state.bold = FOREGROUND_INTENSITY; + break; + case rang::style::underline: + case rang::style::blink: + state.underline = BACKGROUND_INTENSITY; + break; + case rang::style::reversed: + state.inverse = TRUE; + break; + case rang::style::conceal: + state.conceal = TRUE; + break; + default: + break; + } +} - template - inline void setWinColorAnsi(std::ostream &os, T const value) - { - os << "\033[" << static_cast(value) << "m"; - } +inline SGR ¤t_state() noexcept { + static SGR state = defaultState(); + return state; +} - template - inline void setWinColorNative(std::ostream &os, T const value) - { - const HANDLE h = getConsoleHandle(os.rdbuf()); - if (h != INVALID_HANDLE_VALUE) { - setWinSGR(value, current_state()); - // Out all buffered text to console with previous settings: - os.flush(); - SetConsoleTextAttribute(h, SGR2Attr(current_state())); - } +inline WORD SGR2Attr(const SGR &state) noexcept { + WORD attrib = 0; + if (state.conceal) { + if (state.inverse) { + attrib = (state.fgColor << 4) | state.fgColor; + if (state.bold) attrib |= FOREGROUND_INTENSITY | BACKGROUND_INTENSITY; + } else { + attrib = (state.bgColor << 4) | state.bgColor; + if (state.underline) + attrib |= FOREGROUND_INTENSITY | BACKGROUND_INTENSITY; } + } else if (state.inverse) { + attrib = (state.fgColor << 4) | state.bgColor; + if (state.bold) attrib |= BACKGROUND_INTENSITY; + if (state.underline) attrib |= FOREGROUND_INTENSITY; + } else { + attrib = + state.fgColor | (state.bgColor << 4) | state.bold | state.underline; + } + return attrib; +} + +template +inline void setWinColorAnsi(std::ostream &os, T const value) { + os << "\033[" << static_cast(value) << "m"; +} + +template +inline void setWinColorNative(std::ostream &os, T const value) { + const HANDLE h = getConsoleHandle(os.rdbuf()); + if (h != INVALID_HANDLE_VALUE) { + setWinSGR(value, current_state()); + // Out all buffered text to console with previous settings: + os.flush(); + SetConsoleTextAttribute(h, SGR2Attr(current_state())); + } +} - template - inline enableStd setColor(std::ostream &os, T const value) - { - if (winTermMode() == winTerm::Auto) { - if (supportsAnsi(os.rdbuf())) { - setWinColorAnsi(os, value); - } else { - setWinColorNative(os, value); - } - } else if (winTermMode() == winTerm::Ansi) { - setWinColorAnsi(os, value); - } else { - setWinColorNative(os, value); - } - return os; +template +inline enableStd setColor(std::ostream &os, T const value) { + if (winTermMode() == winTerm::Auto) { + if (supportsAnsi(os.rdbuf())) { + setWinColorAnsi(os, value); + } else { + setWinColorNative(os, value); } + } else if (winTermMode() == winTerm::Ansi) { + setWinColorAnsi(os, value); + } else { + setWinColorNative(os, value); + } + return os; +} #else - template - inline enableStd setColor(std::ostream &os, T const value) - { - return os << "\033[" << static_cast(value) << "m"; - } +template +inline enableStd setColor(std::ostream &os, T const value) { + return os << "\033[" << static_cast(value) << "m"; +} #endif } // namespace rang_implementation template inline rang_implementation::enableStd operator<<(std::ostream &os, - const T value) -{ - const control option = rang_implementation::controlMode(); - switch (option) { - case control::Auto: - return rang_implementation::supportsColor() - && rang_implementation::isTerminal(os.rdbuf()) - ? rang_implementation::setColor(os, value) - : os; - case control::Force: return rang_implementation::setColor(os, value); - default: return os; - } + const T value) { + const control option = rang_implementation::controlMode(); + switch (option) { + case control::Auto: + return rang_implementation::supportsColor() && + rang_implementation::isTerminal(os.rdbuf()) + ? rang_implementation::setColor(os, value) + : os; + case control::Force: + return rang_implementation::setColor(os, value); + default: + return os; + } } -inline void setWinTermMode(const rang::winTerm value) noexcept -{ - rang_implementation::winTermMode() = value; +inline void setWinTermMode(const rang::winTerm value) noexcept { + rang_implementation::winTermMode() = value; } -inline void setControlMode(const control value) noexcept -{ - rang_implementation::controlMode() = value; +inline void setControlMode(const control value) noexcept { + rang_implementation::controlMode() = value; } } // namespace rang From 2ab32e788985b6b84b5fb3de43d606afd982241d Mon Sep 17 00:00:00 2001 From: Daniel Beckert Date: Mon, 27 Aug 2018 14:00:42 -0300 Subject: [PATCH 3/4] src: finish basic colorization --- binding.gyp | 4 +- deps/rang/LICENSE | 24 ++++ deps/rang/README.md | 159 +++++++++++++++++++++++++ {src => deps/rang/include}/rang.hpp | 0 src/llnode.cc | 31 ++--- src/llnode.h | 24 ---- src/llscan.cc | 36 +----- src/llscan.h | 4 +- src/llv8.cc | 178 +++++++++++++++------------- src/settings.cc | 35 ++++++ src/settings.h | 32 +++++ 11 files changed, 371 insertions(+), 156 deletions(-) create mode 100644 deps/rang/LICENSE create mode 100644 deps/rang/README.md rename {src => deps/rang/include}/rang.hpp (100%) create mode 100644 src/settings.cc create mode 100644 src/settings.h diff --git a/binding.gyp b/binding.gyp index 8da0c457..3165af76 100644 --- a/binding.gyp +++ b/binding.gyp @@ -79,6 +79,7 @@ "src/llscan.cc", "src/node.cc", "src/node-constants.cc", + "src/settings.cc", ], "conditions": [ [ "OS == 'win'", { @@ -97,7 +98,7 @@ "include_dirs": [ " diff --git a/deps/rang/README.md b/deps/rang/README.md new file mode 100644 index 00000000..90a196a2 --- /dev/null +++ b/deps/rang/README.md @@ -0,0 +1,159 @@ +# rang [![Build Status](https://travis-ci.org/agauniyal/rang.svg?branch=master)](https://travis-ci.org/agauniyal/rang) [![Build status](https://ci.appveyor.com/api/projects/status/jqpdoelli38h2a7w?svg=true)](https://ci.appveyor.com/project/agauniyal/rang) [![codecov](https://codecov.io/gh/agauniyal/rang/branch/master/graph/badge.svg)](https://codecov.io/gh/agauniyal/rang) [ ![Download](https://api.bintray.com/packages/agauniyal/rang/rang%3Arang/images/download.svg) ](https://bintray.com/agauniyal/rang/rang%3Arang/_latestVersion) + +##### Colors for your Terminal. + +![rang-demo](https://cloud.githubusercontent.com/assets/7630575/13501282/0bd00074-e18c-11e5-9848-5bd1f20566d9.gif) +
+ Windows Demo + +![rang-windows-demo](https://cloud.githubusercontent.com/assets/11349690/19836886/8134975e-9ebe-11e6-9ee4-c4657784ff3b.gif) +
+ + +Example usage +------------- + +```c++ +#include "rang.hpp" + +using namespace std; +using namespace rang; + +int main() +{ + cout << "Plain old text" + << style::bold << "Rang styled text!!" + << style::reset << endl; +} +``` + +Dependencies +------------ +*rang* only depends on [C++ standard library](http://en.cppreference.com/w/cpp/header), `unistd.h` system header on unix and `windows.h` & `io.h` system headers on windows based systems. In other words, you don't need any 3rd party dependencies. + + +Installation +------------ + +*rang* is a single header-only library. Put `rang.hpp` in the [include](include) folder directly into the project source tree or somewhere reachable from your project. + +Or, if you use the [conan package manager](https://www.conan.io/), follow these steps: + +1. Add a reference to *rang* to the *requires* section of your project's `conanfile.txt` file: + + [requires] + rang/3.1.0@rang/stable + +2. Run conan's install command: + + conan install + + +## How to use + +*Rang* uses iostream objects - `cout`/`clog`/`cerr` to apply attributes to output text. Since *rang* aims to support both windows and unix like systems, it takes care of the os specific details and tries to provide a uniform interface. Due to incompatiblities b/w different OS versions, not all kinds of attributes are supported on every system so rang will try to skip the ones which might produce garbage(instead of pushing random ANSI escape codes on your streams). Detection of tty is also handled internally so you don't need to check if application user might redirect output to a file. + +> **Need support for non-ansi terminals? Check out [Termdb](https://github.com/agauniyal/termdb) which supports virtually all terminals and their capablities.** + +Apart from setting text attributes, you can also ask rang to override its default behaviour through these methods - +```cpp +void rang::setControlMode(rang::control); +``` +where `rang::control` takes + - `control::Auto` - Automatically detects whether terminal supports color or not(**Default**) + - `control::Off` - Turn off colors completely + - `control::Force` - Force colors even if terminal doesn't supports them or output is redirected to non-terminal + +```cpp +void rang::setWinTermMode(rang::winTerm); +``` +where `rang::winTerm` takes + - `winTerm::Auto` - Checks for newer windows and picks Ansi otherwise falls back to Native(**Default**) + - `winTerm::Native` - This method is supported in all versions of windows but supports less attributes + - `winTerm::Ansi` - This method is supported in newer versions of windows and supports rich variety of attributes + + +Supported attributes with their compatiblity are listed below - + +**Text Styles**: + +| Code | Linux/Win/Others | Old Win +| ---- | --------- | ------ | +| `rang::style::bold` | yes | yes | +| `rang::style::dim` | yes | no | +| `rang::style::italic` | yes | no | +| `rang::style::underline` | yes | no | +| `rang::style::blink` | no | no | +| `rang::style::rblink` | no | no | +| `rang::style::reversed` | yes | yes | +| `rang::style::conceal` | maybe | yes | +| `rang::style::crossed` | yes | no | + +**Text Color**: + +| Code | Linux/Win/Others | Old Win +| ---- | --------- | ------ | +| `rang::fg::black` | yes | yes | +| `rang::fg::red` | yes | yes | +| `rang::fg::green` | yes | yes | +| `rang::fg::yellow` | yes | yes | +| `rang::fg::blue` | yes | yes | +| `rang::fg::magenta` | yes | yes | +| `rang::fg::cyan` | yes | yes | +| `rang::fg::gray` | yes | yes | + +**Background Color**: + +| Code | Linux/Win/Others | Old Win +| ---- | --------- | ------ | +| `rang::bg::black` | yes | yes | +| `rang::bg::red` | yes | yes | +| `rang::bg::green` | yes | yes | +| `rang::bg::yellow` | yes | yes | +| `rang::bg::blue` | yes | yes | +| `rang::bg::magenta` | yes | yes | +| `rang::bg::cyan` | yes | yes | +| `rang::bg::gray` | yes | yes | + +**Bright Foreground Color**: + +| Code | Linux/Win/Others | Old Win +| ---- | --------- | ------ | +| `rang::fgB::black` | yes | yes | +| `rang::fgB::red` | yes | yes | +| `rang::fgB::green` | yes | yes | +| `rang::fgB::yellow` | yes | yes | +| `rang::fgB::blue` | yes | yes | +| `rang::fgB::magenta` | yes | yes | +| `rang::fgB::cyan` | yes | yes | +| `rang::fgB::gray` | yes | yes | + +**Bright Background Color**: + +| Code | Linux/Win/Others | Old Win +| ---- | --------- | ------ | +| `rang::bgB::black` | yes | yes | +| `rang::bgB::red` | yes | yes | +| `rang::bgB::green` | yes | yes | +| `rang::bgB::yellow` | yes | yes | +| `rang::bgB::blue` | yes | yes | +| `rang::bgB::magenta` | yes | yes | +| `rang::bgB::cyan` | yes | yes | +| `rang::bgB::gray` | yes | yes | + +**Reset Styles/Colors**: + +| Code | Linux/Win/Others | Old Win +| ---- | --------- | ------ | +| `rang::style::reset` | yes | yes | +| `rang::fg::reset` | yes | yes | +| `rang::bg::reset` | yes | yes | + +----- +## My terminal is not detected/gets garbage output! + +Check your env variable `TERM`'s value. Then open an issue [here](https://github.com/agauniyal/rang/issues/new) and make sure to mention `TERM`'s value along with your terminal name. + +## Redirecting `cout`/`cerr`/`clog` rdbuf? + +Rang doesn't interfere if you try to redirect `cout`/`cerr`/`clog` to somewhere else and leaves the decision to the library user. Make sure you've read this [conversation](https://github.com/agauniyal/rang/pull/77#issuecomment-360991652) and check out the example code [here](https://gist.github.com/kingseva/a918ec66079a9475f19642ec31276a21). diff --git a/src/rang.hpp b/deps/rang/include/rang.hpp similarity index 100% rename from src/rang.hpp rename to deps/rang/include/rang.hpp diff --git a/src/llnode.cc b/src/llnode.cc index e6e5090b..5f09c896 100644 --- a/src/llnode.cc +++ b/src/llnode.cc @@ -4,18 +4,18 @@ #include #include -#include #include #include #include +#include "src/node-inl.h" +#include "src/settings.h" #include "src/error.h" #include "src/llnode.h" #include "src/llscan.h" #include "src/llv8.h" -#include "src/node-inl.h" -#include "src/rang.hpp" +#include "deps/rang/include/rang.hpp" namespace llnode { @@ -33,22 +33,6 @@ using lldb::SBValue; using lldb::eReturnStatusFailed; using lldb::eReturnStatusSuccessFinishResult; -Settings Settings::instance; -Settings* Settings::GetSettings() { return &Settings::instance; } - -std::string Settings::SetColor(std::string option) { - if (option == "auto" || option == "always" || option == "never") - color = option; - return color; -} - -bool Settings::ShouldUseColor() { - if (color == "always" || - (color == "auto" && rang::rang_implementation::supportsColor() && - rang::rang_implementation::isTerminal(std::cout.rdbuf()))) - return true; - return false; -} bool BacktraceCmd::DoExecute(SBDebugger d, char** cmd, SBCommandReturnObject& result) { @@ -124,6 +108,10 @@ bool BacktraceCmd::DoExecute(SBDebugger d, char** cmd, bool SetPropertyColorCmd::DoExecute(SBDebugger d, char** cmd, SBCommandReturnObject& result) { + #ifdef NO_COLOR_OUTPUT + result.Printf("Color support is not available\n"); + return false; + #endif if (cmd != nullptr) { Settings* settings = Settings::GetSettings(); char* arg = cmd[0]; @@ -509,6 +497,11 @@ bool PluginInitialize(SBDebugger d) { "Print all pending requests in the queue. Equivalent to " "running process._getActiveRequests() on the living process.\n"); + // Set initial value for color support + llnode::Settings* settings = llnode::Settings::GetSettings(); + settings->SetColor("auto"); + + return true; } diff --git a/src/llnode.h b/src/llnode.h index a63ff377..6366365c 100644 --- a/src/llnode.h +++ b/src/llnode.h @@ -10,30 +10,6 @@ namespace llnode { - -// Use singleton pattern to avoid multiples instatiations -// of Settings -class Settings { - private: - static Settings instance; - - // Private constructors to prevent instantiations - Settings(){}; - Settings(const Settings&){}; - ~Settings(){}; - - // Override assignment operator to avoid copies - Settings& operator=(const Settings&){}; - - std::string color = "auto"; - - public: - static Settings* GetSettings(); - std::string SetColor(std::string option); - std::string GetColor() { return color; }; - bool ShouldUseColor(); -}; - class CommandBase : public lldb::SBCommandPluginInterface {}; class BacktraceCmd : public CommandBase { diff --git a/src/llscan.cc b/src/llscan.cc index b061edf5..6f90eadb 100644 --- a/src/llscan.cc +++ b/src/llscan.cc @@ -13,11 +13,11 @@ #include +#include "src/settings.h" #include "src/error.h" -#include "src/llnode.h" #include "src/llscan.h" #include "src/llv8-inl.h" -#include "src/rang.hpp" +#include "deps/rang/include/rang.hpp" namespace llnode { @@ -233,19 +233,13 @@ bool FindInstancesCmd::DoExecute(SBDebugger d, char** cmd, } } else { - Settings* settings = Settings::GetSettings(); - if (settings->ShouldUseColor()) { - rang::setControlMode(rang::control::Force); - } else { - rang::setControlMode(rang::control::Off); - } - + // "No objects found with type name %s", type_name std::stringstream ss; ss << rang::style::bold << rang::fg::red - << "No objects found with type name " << type_name.c_str() + << "No objects found with type name " << type_name << rang::fg::reset << rang::style::reset << std::endl; std::string str(ss.str()); - result.Printf(str.c_str()); + result.Printf("%s", str.c_str()); result.SetStatus(eReturnStatusFailed); return false; } @@ -432,12 +426,6 @@ bool NodeInfoCmd::DoExecute(SBDebugger d, char** cmd, bool FindReferencesCmd::DoExecute(SBDebugger d, char** cmd, SBCommandReturnObject& result) { - Settings* settings = Settings::GetSettings(); - if (settings->ShouldUseColor()) { - rang::setControlMode(rang::control::Force); - } else { - rang::setControlMode(rang::control::Off); - } if (cmd == nullptr || *cmd == nullptr) { result.SetError("USAGE: v8 findrefs expr\n"); @@ -718,12 +706,6 @@ void FindReferencesCmd::ReferenceScanner::PrintContextRefs( } std::string FindReferencesCmd::ObjectScanner::GetPropertyReferenceString() { - Settings* settings = Settings::GetSettings(); - if (settings->ShouldUseColor()) { - rang::setControlMode(rang::control::Force); - } else { - rang::setControlMode(rang::control::Off); - } std::stringstream ss; ss << rang::fg::cyan << "0x%" PRIx64 << rang::fg::reset << ": " @@ -734,12 +716,6 @@ std::string FindReferencesCmd::ObjectScanner::GetPropertyReferenceString() { } std::string FindReferencesCmd::ObjectScanner::GetArrayReferenceString() { - Settings* settings = Settings::GetSettings(); - if (settings->ShouldUseColor()) { - rang::setControlMode(rang::control::Force); - } else { - rang::setControlMode(rang::control::Off); - } std::stringstream ss; ss << rang::fg::cyan << "0x%" PRIx64 << rang::fg::reset << ": " @@ -1066,7 +1042,7 @@ void FindReferencesCmd::StringScanner::PrintRefs(SBCommandReturnObject& result, << key.c_str() << "=" << std::hex << entry.second.raw() << std::dec << " '" << value.c_str() << "'" << std::endl; - result.Printf(ss.str().c_str()); + result.Printf("%s", ss.str().c_str()); } } } diff --git a/src/llscan.h b/src/llscan.h index 99295225..9732debf 100644 --- a/src/llscan.h +++ b/src/llscan.h @@ -93,8 +93,8 @@ class FindReferencesCmd : public CommandBase { virtual void PrintContextRefs(lldb::SBCommandReturnObject& result, Error& err) {} - virtual std::string GetPropertyReferenceString(); - virtual std::string GetArrayReferenceString(); + std::string GetPropertyReferenceString(); + std::string GetArrayReferenceString(); }; void PrintReferences(lldb::SBCommandReturnObject& result, diff --git a/src/llv8.cc b/src/llv8.cc index 573a0ce8..0aa635ac 100644 --- a/src/llv8.cc +++ b/src/llv8.cc @@ -9,8 +9,8 @@ #include "llv8-inl.h" #include "llv8.h" -#include "src/llnode.h" -#include "src/rang.hpp" +#include "src/settings.h" +#include "deps/rang/include/rang.hpp" namespace llnode { namespace v8 { @@ -381,7 +381,6 @@ std::string JSFunction::GetDebugLine(std::string args, Error& err) { std::string JSFunction::Inspect(InspectOptions* options, Error& err) { - std::stringstream ss; std::string res = "" << rang::fg::reset; - res = ss.str().c_str(); + res = ss.str(); } return res; } @@ -517,11 +507,18 @@ std::string JSRegExp::Inspect(InspectOptions* options, Error& err) { // Print properties in detailed mode if (options->detailed) { + std::stringstream ss; + ss << rang::fg::magenta << res << rang::fg::reset; + res = ss.str(); + res += " " + InspectProperties(err); + res += ">"; if (err.Fail()) return std::string(); + } else { + std::stringstream ss; + ss << rang::fg::yellow << res + ">" << rang::fg::reset; + res = ss.str(); } - - res += ">"; return res; } @@ -789,12 +786,6 @@ std::string HeapObject::ToString(Error& err) { std::string HeapObject::Inspect(InspectOptions* options, Error& err) { - Settings* settings = Settings::GetSettings(); - if (settings->ShouldUseColor()) { - rang::setControlMode(rang::control::Force); - } else { - rang::setControlMode(rang::control::Off); - } int64_t type = GetType(err); if (err.Fail()) return std::string(); @@ -816,9 +807,21 @@ std::string HeapObject::Inspect(InspectOptions* options, Error& err) { std::string pre = buf; - if (type == v8()->types()->kGlobalObjectType) return pre + ""; - if (type == v8()->types()->kGlobalProxyType) return pre + ""; - if (type == v8()->types()->kCodeType) return pre + ""; + if (type == v8()->types()->kGlobalObjectType) { + std::stringstream ss; + ss << rang::fg::yellow << "" << rang::fg::reset; + return pre + ss.str(); + } + if (type == v8()->types()->kGlobalProxyType) { + std::stringstream ss; + ss << rang::fg::yellow << "" << rang::fg::reset; + return pre + ss.str(); + } + if (type == v8()->types()->kCodeType) { + std::stringstream ss; + ss << rang::fg::yellow << "" << rang::fg::reset; + return pre + ss.str(); + } if (type == v8()->types()->kMapType) { Map m(this); return pre + m.Inspect(options, err); @@ -992,7 +995,7 @@ std::string HeapObject::GetTypeName(Error& err) { std::string Smi::Inspect(Error& err) { std::stringstream ss; ss << rang::fg::yellow << "" << rang::fg::reset; - return ss.str().c_str(); + return ss.str(); } @@ -1009,7 +1012,7 @@ std::string HeapNumber::Inspect(Error& err) { std::stringstream ss; ss << rang::fg::yellow << "" << rang::fg::reset; - return ss.str().c_str(); + return ss.str(); } @@ -1068,7 +1071,7 @@ std::string String::Inspect(InspectOptions* options, Error& err) { std::stringstream ss; ss << rang::fg::yellow << "" << rang::fg::reset; - return ss.str().c_str(); + return ss.str(); } @@ -1093,7 +1096,7 @@ std::string FixedArray::Inspect(InspectOptions* options, Error& err) { ss << rang::fg::yellow << res + ">" << rang::fg::reset; res = ss.str(); } - return res.c_str(); + return res; } @@ -1112,8 +1115,7 @@ std::string FixedArray::InspectContents(int length, Error& err) { std::stringstream ss; ss << rang::style::bold << rang::fg::yellow << " [" << i << "]" << rang::fg::reset << rang::style::reset << "="; - snprintf(tmp, sizeof(tmp), "%s", ss.str().c_str()); - res += tmp + value.Inspect(&options, err); + res += ss.str() + value.Inspect(&options, err); if (err.Fail()) return std::string(); } @@ -1186,9 +1188,10 @@ std::string Context::Inspect(InspectOptions* options, Error& err) { std::stringstream ss; ss << rang::style::bold << rang::fg::yellow << options->get_indent_spaces() << "(previous)" << rang::fg::reset << rang::style::reset << "=" << rang::fg::cyan - << "0x" << std::hex << previous.raw() << std::dec << rang::fg::reset; + << "0x" << std::hex << previous.raw() << std::dec << rang::fg::reset + << ":" << rang::fg::yellow << "" << rang::fg::reset << ","; - res += ss.str() + ":,"; + res += ss.str(); } if (!res.empty()) res += "\n"; @@ -1207,13 +1210,14 @@ std::string Context::Inspect(InspectOptions* options, Error& err) { res += closure.Inspect(&closure_options, err) + "}"; if (err.Fail()) return std::string(); } else { - char tmp[128]; - snprintf( - tmp, sizeof(tmp), - (options->get_indent_spaces() + "(scope_info)=0x%016" PRIx64).c_str(), - scope.raw()); - - res += std::string(tmp) + ":get_indent_spaces() << "(scope_info)" + << rang::fg::reset << rang::style::reset << "=" << rang::fg::cyan << "0x" << std::hex << scope.raw() + << std::dec << rang::fg::yellow; + res += ss.str() + ":" << rang::fg::reset; - return ss.str().c_str(); + return ss.str(); } int64_t data = BackingStore(err); @@ -1306,7 +1316,11 @@ std::string JSArrayBuffer::Inspect(InspectOptions* options, Error& err) { std::string res; res += tmp; if (options->detailed) { - res += ": [\n "; + std::stringstream ss; + ss << rang::fg::magenta << res + ":" << rang::fg::yellow; + res = ss.str(); + + res += " [\n "; int display_length = std::min(byte_length, options->length); res += v8()->LoadBytes(data, display_length, err); @@ -1314,14 +1328,18 @@ std::string JSArrayBuffer::Inspect(InspectOptions* options, Error& err) { if (display_length < byte_length) { res += " ..."; } - res += "\n]>"; + + res += "\n]"; + ss.str(""); ss.clear(); + ss << res << rang::fg::reset; + + res = ss.str(); + return res + ">"; } else { - res += ">"; + std::stringstream ss; + ss << rang::fg::yellow << res + ">" << rang::fg::reset; + return ss.str(); } - - std::stringstream ss; - ss << rang::fg::yellow << res << rang::fg::reset; - return ss.str().c_str(); } @@ -1370,7 +1388,12 @@ std::string JSArrayBufferView::Inspect(InspectOptions* options, Error& err) { std::string res; res += tmp; if (options->detailed) { - res += ": [\n "; + + std::stringstream ss; + ss << rang::fg::magenta << res + ":" << rang::fg::yellow; + res = ss.str(); + + res += " [\n "; int display_length = std::min(byte_length, options->length); res += v8()->LoadBytes(data + byte_offset, display_length, err); @@ -1378,11 +1401,19 @@ std::string JSArrayBufferView::Inspect(InspectOptions* options, Error& err) { if (display_length < byte_length) { res += " ..."; } - res += "\n]>"; + + res += "\n]"; + + ss.str(""); ss.clear(); + ss << res << rang::fg::reset; + res = ss.str(); + + return res + ">"; } else { - res += ">"; + std::stringstream ss; + ss << rang::fg::yellow << res + ">" << rang::fg::reset; + return ss.str(); } - return res; } @@ -1421,13 +1452,6 @@ std::string Map::Inspect(InspectOptions* options, Error& err) { static_cast(in_object_properties_or_constructor_index), static_cast(instance_size), descriptors_obj.raw()); - // snprintf(tmp, sizeof(tmp), - // "(own_descriptors_count), - // in_object_properties_or_constructor.c_str(), - // static_cast(in_object_properties_or_constructor_index), - // static_cast(instance_size), descriptors_obj.raw()); if (!options->detailed) { return std::string(tmp) + ">"; } @@ -1495,10 +1519,10 @@ std::string JSObject::Inspect(InspectOptions* options, Error& err) { std::stringstream ss; ss << rang::fg::magenta << "\n internal fields" << rang::fg::reset << " {" << std::endl - << fields << "}>"; + << fields << "}"; res += ss.str().c_str(); } - return res; + return res + ">"; } else { std::stringstream ss; ss << rang::fg::yellow << res << ">" << rang::fg::reset; @@ -1533,6 +1557,7 @@ std::string JSObject::InspectInternalFields(Error& err) { instance_size -= in_object_props * v8()->common()->kPointerSize; std::string res; + std::stringstream ss; for (int64_t off = v8()->js_object()->kInternalFieldsOffset; off < instance_size; off += v8()->common()->kPointerSize) { int64_t field = LoadField(off, err); @@ -1542,7 +1567,11 @@ std::string JSObject::InspectInternalFields(Error& err) { snprintf(tmp, sizeof(tmp), " 0x%016" PRIx64, field); if (!res.empty()) res += ",\n "; - res += tmp; + + ss.str(""); ss.clear(); + ss << rang::fg::cyan << tmp << rang::fg::reset; + res += ss.str(); + } return res; @@ -1560,6 +1589,7 @@ std::string JSObject::InspectProperties(Error& err) { ss << rang::fg::magenta << "elements" << rang::fg::reset << " {" << std::endl << elems << "}"; + res = ss.str(); } HeapObject map_obj = GetMap(err); @@ -1631,8 +1661,7 @@ std::string JSObject::InspectElements(int64_t length, Error& err) { ss << rang::style::bold << rang::fg::yellow << " [" << static_cast(i) << "]" << rang::fg::reset << rang::style::reset << "="; - snprintf(tmp, sizeof(tmp), "%s", ss.str().c_str()); - res += tmp; + res += ss.str(); res += value.Inspect(&options, err); if (err.Fail()) return std::string(); @@ -1736,17 +1765,6 @@ std::string JSObject::InspectDescriptors(Map map, Error& err) { continue; } - // Skip non-fields for now - if (!descriptors.IsFieldDetails(details)) { - Error::PrintInDebugMode("Unknown field Type %" PRId64, - details.GetValue()); - ss.str(""); - ss.clear(); - ss << rang::fg::yellow << "" << rang::fg::reset; - res += ss.str(); - continue; - } - int64_t index = descriptors.FieldIndex(details) - in_object_count; if (descriptors.IsDoubleField(details)) { diff --git a/src/settings.cc b/src/settings.cc new file mode 100644 index 00000000..01811e9d --- /dev/null +++ b/src/settings.cc @@ -0,0 +1,35 @@ +#include "src/settings.h" +#include "deps/rang/include/rang.hpp" + +namespace llnode { + +Settings::Settings() {} +Settings::~Settings() {} + +Settings Settings::instance; +Settings* Settings::GetSettings() { return &Settings::instance; } + +std::string Settings::SetColor(std::string option) { + if (option == "auto" || option == "always" || option == "never") + color = option; + + if (ShouldUseColor()) + rang::setControlMode(rang::control::Force); + else + rang::setControlMode(rang::control::Off); + + return color; +} + +bool Settings::ShouldUseColor() { + #ifdef NO_COLOR_OUTPUT + return false; + #endif + if (color == "always" || + (color == "auto" && rang::rang_implementation::supportsColor() && + rang::rang_implementation::isTerminal(std::cout.rdbuf()))) + return true; + return false; +} + +} // namespace llnode diff --git a/src/settings.h b/src/settings.h new file mode 100644 index 00000000..a6720406 --- /dev/null +++ b/src/settings.h @@ -0,0 +1,32 @@ +#ifndef SRC_SETTINGS_H +#define SRC_SETTINGS_H + +#include + +namespace llnode { + +// Use singleton pattern to avoid multiples instatiations +// of Settings +class Settings { + private: + static Settings instance; + + // Private constructors to prevent instantiations + Settings(); + ~Settings(); + Settings(const Settings&) = delete; + + // Override assignment operator to avoid copies + Settings& operator=(const Settings&) = delete; + + std::string color = "auto"; + + public: + static Settings* GetSettings(); + std::string SetColor(std::string option); + std::string GetColor() { return color; }; + bool ShouldUseColor(); +}; + +} // namespace llnode +#endif // SRC_SETTINGS_H From 83eba131a5db4d711219223244bfa4c1fcd7899f Mon Sep 17 00:00:00 2001 From: Daniel Beckert Date: Wed, 19 Sep 2018 16:17:17 -0300 Subject: [PATCH 4/4] src: run `make format` --- src/llnode.cc | 10 ++++---- src/llscan.cc | 11 +++----- src/llv8.cc | 67 ++++++++++++++++++++++++++----------------------- src/settings.cc | 6 ++--- src/settings.h | 4 +-- 5 files changed, 49 insertions(+), 49 deletions(-) diff --git a/src/llnode.cc b/src/llnode.cc index 5f09c896..d1d8d8e9 100644 --- a/src/llnode.cc +++ b/src/llnode.cc @@ -9,13 +9,13 @@ #include -#include "src/node-inl.h" -#include "src/settings.h" +#include "deps/rang/include/rang.hpp" #include "src/error.h" #include "src/llnode.h" #include "src/llscan.h" #include "src/llv8.h" -#include "deps/rang/include/rang.hpp" +#include "src/node-inl.h" +#include "src/settings.h" namespace llnode { @@ -108,10 +108,10 @@ bool BacktraceCmd::DoExecute(SBDebugger d, char** cmd, bool SetPropertyColorCmd::DoExecute(SBDebugger d, char** cmd, SBCommandReturnObject& result) { - #ifdef NO_COLOR_OUTPUT +#ifdef NO_COLOR_OUTPUT result.Printf("Color support is not available\n"); return false; - #endif +#endif if (cmd != nullptr) { Settings* settings = Settings::GetSettings(); char* arg = cmd[0]; diff --git a/src/llscan.cc b/src/llscan.cc index 6f90eadb..7cc561ad 100644 --- a/src/llscan.cc +++ b/src/llscan.cc @@ -13,11 +13,11 @@ #include -#include "src/settings.h" +#include "deps/rang/include/rang.hpp" #include "src/error.h" #include "src/llscan.h" #include "src/llv8-inl.h" -#include "deps/rang/include/rang.hpp" +#include "src/settings.h" namespace llnode { @@ -236,8 +236,8 @@ bool FindInstancesCmd::DoExecute(SBDebugger d, char** cmd, // "No objects found with type name %s", type_name std::stringstream ss; ss << rang::style::bold << rang::fg::red - << "No objects found with type name " << type_name - << rang::fg::reset << rang::style::reset << std::endl; + << "No objects found with type name " << type_name << rang::fg::reset + << rang::style::reset << std::endl; std::string str(ss.str()); result.Printf("%s", str.c_str()); result.SetStatus(eReturnStatusFailed); @@ -426,7 +426,6 @@ bool NodeInfoCmd::DoExecute(SBDebugger d, char** cmd, bool FindReferencesCmd::DoExecute(SBDebugger d, char** cmd, SBCommandReturnObject& result) { - if (cmd == nullptr || *cmd == nullptr) { result.SetError("USAGE: v8 findrefs expr\n"); return false; @@ -706,7 +705,6 @@ void FindReferencesCmd::ReferenceScanner::PrintContextRefs( } std::string FindReferencesCmd::ObjectScanner::GetPropertyReferenceString() { - std::stringstream ss; ss << rang::fg::cyan << "0x%" PRIx64 << rang::fg::reset << ": " << rang::fg::magenta << "%s" << rang::style::bold << rang::fg::yellow @@ -716,7 +714,6 @@ std::string FindReferencesCmd::ObjectScanner::GetPropertyReferenceString() { } std::string FindReferencesCmd::ObjectScanner::GetArrayReferenceString() { - std::stringstream ss; ss << rang::fg::cyan << "0x%" PRIx64 << rang::fg::reset << ": " << rang::fg::magenta << "%s" << rang::style::bold << rang::fg::yellow diff --git a/src/llv8.cc b/src/llv8.cc index 0aa635ac..7d4443cd 100644 --- a/src/llv8.cc +++ b/src/llv8.cc @@ -7,10 +7,10 @@ #include #include +#include "deps/rang/include/rang.hpp" #include "llv8-inl.h" #include "llv8.h" #include "src/settings.h" -#include "deps/rang/include/rang.hpp" namespace llnode { namespace v8 { @@ -393,8 +393,9 @@ std::string JSFunction::Inspect(InspectOptions* options, Error& err) { std::stringstream ss; ss << rang::fg::magenta << res << rang::fg::reset << rang::style::bold - << rang::fg::yellow << "\n context" << rang::fg::reset << rang::style::reset - << "=" << rang::fg::cyan << "0x%016" PRIx64 << rang::fg::reset; + << rang::fg::yellow << "\n context" << rang::fg::reset + << rang::style::reset << "=" << rang::fg::cyan << "0x%016" PRIx64 + << rang::fg::reset; res = ss.str(); { @@ -786,7 +787,6 @@ std::string HeapObject::ToString(Error& err) { std::string HeapObject::Inspect(InspectOptions* options, Error& err) { - int64_t type = GetType(err); if (err.Fail()) return std::string(); @@ -808,19 +808,19 @@ std::string HeapObject::Inspect(InspectOptions* options, Error& err) { std::string pre = buf; if (type == v8()->types()->kGlobalObjectType) { - std::stringstream ss; - ss << rang::fg::yellow << "" << rang::fg::reset; - return pre + ss.str(); + std::stringstream ss; + ss << rang::fg::yellow << "" << rang::fg::reset; + return pre + ss.str(); } if (type == v8()->types()->kGlobalProxyType) { - std::stringstream ss; - ss << rang::fg::yellow << "" << rang::fg::reset; - return pre + ss.str(); + std::stringstream ss; + ss << rang::fg::yellow << "" << rang::fg::reset; + return pre + ss.str(); } if (type == v8()->types()->kCodeType) { - std::stringstream ss; - ss << rang::fg::yellow << "" << rang::fg::reset; - return pre + ss.str(); + std::stringstream ss; + ss << rang::fg::yellow << "" << rang::fg::reset; + return pre + ss.str(); } if (type == v8()->types()->kMapType) { Map m(this); @@ -1186,10 +1186,11 @@ std::string Context::Inspect(InspectOptions* options, Error& err) { HeapObject heap_previous = HeapObject(previous); if (heap_previous.Check()) { std::stringstream ss; - ss << rang::style::bold << rang::fg::yellow << options->get_indent_spaces() << "(previous)" - << rang::fg::reset << rang::style::reset << "=" << rang::fg::cyan - << "0x" << std::hex << previous.raw() << std::dec << rang::fg::reset - << ":" << rang::fg::yellow << "" << rang::fg::reset << ","; + ss << rang::style::bold << rang::fg::yellow << options->get_indent_spaces() + << "(previous)" << rang::fg::reset << rang::style::reset << "=" + << rang::fg::cyan << "0x" << std::hex << previous.raw() << std::dec + << rang::fg::reset << ":" << rang::fg::yellow << "" + << rang::fg::reset << ","; res += ss.str(); } @@ -1201,9 +1202,10 @@ std::string Context::Inspect(InspectOptions* options, Error& err) { if (err.Fail()) return std::string(); std::stringstream ss; - ss << rang::style::bold << rang::fg::yellow << options->get_indent_spaces() << "(closure)" - << rang::fg::reset << rang::style::reset << "=" << rang::fg::cyan - << "0x" << std::hex << closure.raw() << std::dec << rang::fg::reset << " {"; + ss << rang::style::bold << rang::fg::yellow << options->get_indent_spaces() + << "(closure)" << rang::fg::reset << rang::style::reset << "=" + << rang::fg::cyan << "0x" << std::hex << closure.raw() << std::dec + << rang::fg::reset << " {"; res += ss.str(); InspectOptions closure_options; @@ -1213,9 +1215,10 @@ std::string Context::Inspect(InspectOptions* options, Error& err) { // Scope for string stream { std::stringstream ss; - ss << rang::style::bold << rang::fg::yellow << options->get_indent_spaces() << "(scope_info)" - << rang::fg::reset << rang::style::reset << "=" << rang::fg::cyan << "0x" << std::hex << scope.raw() - << std::dec << rang::fg::yellow; + ss << rang::style::bold << rang::fg::yellow + << options->get_indent_spaces() << "(scope_info)" << rang::fg::reset + << rang::style::reset << "=" << rang::fg::cyan << "0x" << std::hex + << scope.raw() << std::dec << rang::fg::yellow; res += ss.str() + ":get_indent_spaces() << rang::style::bold << rang::fg::yellow << name.ToString(err) - << rang::fg::reset << rang::style::reset; + std::stringstream ss; + ss << options->get_indent_spaces() << rang::style::bold << rang::fg::yellow + << name.ToString(err) << rang::fg::reset << rang::style::reset; res += ss.str() + "="; if (err.Fail()) return std::string(); @@ -1330,7 +1332,8 @@ std::string JSArrayBuffer::Inspect(InspectOptions* options, Error& err) { } res += "\n]"; - ss.str(""); ss.clear(); + ss.str(""); + ss.clear(); ss << res << rang::fg::reset; res = ss.str(); @@ -1388,7 +1391,6 @@ std::string JSArrayBufferView::Inspect(InspectOptions* options, Error& err) { std::string res; res += tmp; if (options->detailed) { - std::stringstream ss; ss << rang::fg::magenta << res + ":" << rang::fg::yellow; res = ss.str(); @@ -1404,7 +1406,8 @@ std::string JSArrayBufferView::Inspect(InspectOptions* options, Error& err) { res += "\n]"; - ss.str(""); ss.clear(); + ss.str(""); + ss.clear(); ss << res << rang::fg::reset; res = ss.str(); @@ -1568,10 +1571,10 @@ std::string JSObject::InspectInternalFields(Error& err) { if (!res.empty()) res += ",\n "; - ss.str(""); ss.clear(); + ss.str(""); + ss.clear(); ss << rang::fg::cyan << tmp << rang::fg::reset; res += ss.str(); - } return res; diff --git a/src/settings.cc b/src/settings.cc index 01811e9d..b27a01df 100644 --- a/src/settings.cc +++ b/src/settings.cc @@ -22,9 +22,9 @@ std::string Settings::SetColor(std::string option) { } bool Settings::ShouldUseColor() { - #ifdef NO_COLOR_OUTPUT +#ifdef NO_COLOR_OUTPUT return false; - #endif +#endif if (color == "always" || (color == "auto" && rang::rang_implementation::supportsColor() && rang::rang_implementation::isTerminal(std::cout.rdbuf()))) @@ -32,4 +32,4 @@ bool Settings::ShouldUseColor() { return false; } -} // namespace llnode +} // namespace llnode diff --git a/src/settings.h b/src/settings.h index a6720406..5fcc8e02 100644 --- a/src/settings.h +++ b/src/settings.h @@ -28,5 +28,5 @@ class Settings { bool ShouldUseColor(); }; -} // namespace llnode -#endif // SRC_SETTINGS_H +} // namespace llnode +#endif // SRC_SETTINGS_H