From 4df5b7a8cecf374f2e16c1f19576d1fa4c2bb828 Mon Sep 17 00:00:00 2001 From: Heath Stewart Date: Tue, 14 Sep 2021 19:36:55 -0700 Subject: [PATCH] Colorize vswhere output (#244) * Refactor formatters to consolidate arguments * Colorize output by default unless piped * Opt into color and add tests Fails in PowerShell if you do something like `[xml](vswhere -format xml)` if color is enabled, so had to add -color switch. Not ideal since it otherwise disables color when piped, but still easier to read if colorized explicitly. * Enable colors by default, add -nocolor switch * Resolve PR feedback * Ensure console is initialized Could simply call Initialize wherever it needs to be called, but would rather be explicit. --- src/vswhere.lib/CommandArgs.cpp | 4 + src/vswhere.lib/CommandArgs.h | 8 ++ src/vswhere.lib/Console.cpp | 43 +++++- src/vswhere.lib/Console.h | 30 ++++- src/vswhere.lib/Formatter.cpp | 138 ++++++++++---------- src/vswhere.lib/Formatter.h | 65 +++++---- src/vswhere.lib/JsonFormatter.cpp | 61 +++++---- src/vswhere.lib/JsonFormatter.h | 33 ++--- src/vswhere.lib/JsonScope.cpp | 36 ++--- src/vswhere.lib/JsonScope.h | 14 +- src/vswhere.lib/Scope.h | 27 ++-- src/vswhere.lib/TextFormatter.cpp | 15 ++- src/vswhere.lib/TextFormatter.h | 16 +-- src/vswhere.lib/ValueFormatter.cpp | 4 +- src/vswhere.lib/ValueFormatter.h | 10 +- src/vswhere.lib/XmlFormatter.cpp | 52 +++++--- src/vswhere.lib/XmlFormatter.h | 26 ++-- src/vswhere.lib/XmlScope.cpp | 20 +++ src/vswhere.lib/XmlScope.h | 19 +-- src/vswhere.lib/vswhere.lib.rc | Bin 11606 -> 12044 bytes src/vswhere.lib/vswhere.lib.vcxproj | 1 + src/vswhere.lib/vswhere.lib.vcxproj.filters | 3 + src/vswhere/Program.cpp | 7 +- test/vswhere.test/CommandArgsTests.cpp | 10 ++ test/vswhere.test/JsonFormatterTests.cpp | 87 ++++++++---- test/vswhere.test/TestConsole.h | 22 +++- test/vswhere.test/TextFormatterTests.cpp | 85 +++++++----- test/vswhere.test/ValueFormatterTests.cpp | 81 ++++++++---- test/vswhere.test/XmlFormatterTests.cpp | 88 +++++++++---- version.json | 2 +- 30 files changed, 646 insertions(+), 361 deletions(-) create mode 100644 src/vswhere.lib/XmlScope.cpp diff --git a/src/vswhere.lib/CommandArgs.cpp b/src/vswhere.lib/CommandArgs.cpp index 3beb048..c99e302 100644 --- a/src/vswhere.lib/CommandArgs.cpp +++ b/src/vswhere.lib/CommandArgs.cpp @@ -161,6 +161,10 @@ void CommandArgs::Parse(_In_ vector args) m_find = ParseArgument(it, args.end(), arg); } + else if (ArgumentEquals(arg.Value, L"nocolor")) + { + m_nocolor = true; + } else if (ArgumentEquals(arg.Value, L"nologo")) { m_nologo = true; diff --git a/src/vswhere.lib/CommandArgs.h b/src/vswhere.lib/CommandArgs.h index 649bf65..e9e3ddc 100644 --- a/src/vswhere.lib/CommandArgs.h +++ b/src/vswhere.lib/CommandArgs.h @@ -17,6 +17,7 @@ class CommandArgs m_legacy(false), m_prerelease(false), m_includePackages(false), + m_nocolor(false), m_nologo(false), m_utf8(false), m_help(false) @@ -39,6 +40,7 @@ class CommandArgs m_property(obj.m_property), m_includePackages(obj.m_includePackages), m_find(obj.m_find), + m_nocolor(obj.m_nocolor), m_nologo(obj.m_nologo), m_utf8(obj.m_utf8), m_help(obj.m_help) @@ -130,6 +132,11 @@ class CommandArgs return m_find; } + const bool get_Color() const noexcept + { + return !m_nocolor; + } + const bool get_Logo() const noexcept { return !m_nologo; @@ -172,6 +179,7 @@ class CommandArgs std::wstring m_property; bool m_includePackages; std::wstring m_find; + bool m_nocolor; bool m_nologo; bool m_utf8; bool m_help; diff --git a/src/vswhere.lib/Console.cpp b/src/vswhere.lib/Console.cpp index 8cc47b6..d2d1d85 100644 --- a/src/vswhere.lib/Console.cpp +++ b/src/vswhere.lib/Console.cpp @@ -27,10 +27,31 @@ void Console::Initialize() noexcept ::setlocale(LC_CTYPE, sz); } + m_fColorSupported = IsVirtualTerminal(stdout); m_fInitialized = true; } } +LPCWSTR Console::Color(_In_ LPCWSTR wzColor) const +{ + if (IsColorSupported()) + { + return wzColor; + } + + return L""; +} + +LPCWSTR Console::ResetColor() const +{ + if (IsColorSupported()) + { + return L"\033[0m"; + } + + return L""; +} + void __cdecl Console::Write(_In_ LPCWSTR wzFormat, ...) { va_list args; @@ -66,12 +87,11 @@ void __cdecl Console::WriteLine(_In_ const std::wstring& value) void Console::Write(_In_ LPCWSTR wzFormat, va_list args) { - Initialize(); - + _ASSERTE(m_fInitialized); ::_vwprintf_p(wzFormat, args); } -bool Console::IsConsole(_In_ FILE* f) const noexcept +bool Console::IsConsole(_In_ FILE* f) noexcept { auto fno = ::_fileno(f); auto hFile = (HANDLE)::_get_osfhandle(fno); @@ -92,3 +112,20 @@ bool Console::IsConsole(_In_ FILE* f) const noexcept return true; } + +bool Console::IsVirtualTerminal(_In_ FILE* f) noexcept +{ + auto fno = ::_fileno(f); + auto hFile = (HANDLE)::_get_osfhandle(fno); + + DWORD dwMode; + if (::GetConsoleMode(hFile, &dwMode)) + { + // Defined in newer SDK but can try to enable on older platforms. + const DWORD ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x4; + + return 0 != ::SetConsoleMode(hFile, dwMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING); + } + + return false; +} \ No newline at end of file diff --git a/src/vswhere.lib/Console.h b/src/vswhere.lib/Console.h index afb671d..0520273 100644 --- a/src/vswhere.lib/Console.h +++ b/src/vswhere.lib/Console.h @@ -10,28 +10,48 @@ class Console public: Console(_In_ const CommandArgs& args) : m_args(args), - m_fInitialized(false) + m_fInitialized(false), + m_fColorSupported(false) { } Console(_In_ const Console& obj) : m_args(obj.m_args), - m_fInitialized(obj.m_fInitialized) + m_fInitialized(obj.m_fInitialized), + m_fColorSupported(obj.m_fColorSupported) { } + virtual void Initialize() noexcept; + + LPCWSTR Color(_In_ LPCWSTR wzColor) const; + LPCWSTR ResetColor() const; + void __cdecl Write(_In_ LPCWSTR wzFormat, ...); void __cdecl Write(_In_ const std::wstring& value); void __cdecl WriteLine(_In_ LPCWSTR wzFormat = NULL, ...); void __cdecl WriteLine(_In_ const std::wstring& value); + virtual bool IsColorSupported() const + { + _ASSERTE(m_fInitialized); + return m_fColorSupported && m_args.get_Color(); + } + protected: - virtual void Initialize() noexcept; virtual void Write(_In_ LPCWSTR wzFormat, va_list args); + const CommandArgs& Args() const noexcept + { + return m_args; + } + + bool m_fInitialized; + private: - bool IsConsole(_In_ FILE* f) const noexcept; + bool static IsConsole(_In_ FILE* f) noexcept; + bool static IsVirtualTerminal(_In_ FILE* f) noexcept; const CommandArgs& m_args; - bool m_fInitialized; + bool m_fColorSupported; }; \ No newline at end of file diff --git a/src/vswhere.lib/Formatter.cpp b/src/vswhere.lib/Formatter.cpp index 05f8480..e5a0312 100644 --- a/src/vswhere.lib/Formatter.cpp +++ b/src/vswhere.lib/Formatter.cpp @@ -10,7 +10,9 @@ using namespace std::placeholders; const std::wstring Formatter::empty_wstring; -Formatter::Formatter() +Formatter::Formatter(_In_ CommandArgs& args, _In_ ::Console& console) : + m_args(args), + m_console(console) { m_properties = { @@ -39,10 +41,14 @@ Formatter::FormatterMap Formatter::Formatters = { L"xml", make_tuple(IDS_FORMAT_XML, XmlFormatter::Create) }, }; +// Colors from Visual Studio Code's Dark+ theme. +const LPCWSTR Formatter::ColorName = L"\033[38;2;156;220;254m"; +const LPCWSTR Formatter::ColorValue = L"\033[38;2;206;145;120m"; + const wstring Formatter::s_delims(L"./_"); ci_equal Formatter::s_comparer; -std::unique_ptr Formatter::Create(const wstring& type) +std::unique_ptr Formatter::Create(_In_ const wstring& type, _In_ CommandArgs& args, _In_ ::Console& console) { auto it = Formatters.find(type); if (it != Formatters.end()) @@ -50,55 +56,55 @@ std::unique_ptr Formatter::Create(const wstring& type) FormatterFactory factory; tie(ignore, factory) = it->second; - return factory(); + return factory(args, console); } throw win32_error(ERROR_NOT_SUPPORTED); } -void Formatter::Write(_In_ Console& console, _In_ const std::wstring& root, _In_ const std::wstring& name, _In_ const std::vector values) +void Formatter::Write(const std::wstring& root, _In_ const std::wstring& name, _In_ const std::vector values) { - StartDocument(console); - StartArray(console, root); + StartDocument(); + StartArray(root); for (const auto& value : values) { - WriteProperty(console, name, value); + WriteProperty(name, value); } - EndArray(console); - EndDocument(console); + EndArray(); + EndDocument(); } -void Formatter::Write(_In_ const CommandArgs& args, _In_ Console& console, _In_ ISetupInstance* pInstance) +void Formatter::Write(_In_ ISetupInstance* pInstance) { - StartDocument(console); - StartArray(console); + StartDocument(); + StartArray(); - WriteInternal(args, console, pInstance); + WriteInternal(pInstance); - EndArray(console); - EndDocument(console); + EndArray(); + EndDocument(); } -void Formatter::Write(_In_ const CommandArgs& args, _In_ Console& console, _In_ vector instances) +void Formatter::Write(_In_ vector instances) { - StartDocument(console); - StartArray(console); + StartDocument(); + StartArray(); for (const auto& instance : instances) { - WriteInternal(args, console, instance); + WriteInternal(instance); } - EndArray(console); - EndDocument(console); + EndArray(); + EndDocument(); } -void Formatter::WriteFiles(_In_ const CommandArgs& args, _In_ Console& console, vector instances) +void Formatter::WriteFiles(vector instances) { - StartDocument(console); - StartArray(console, L"files"); + StartDocument(); + StartArray(L"files"); bstr_t bstrInstallationPath; for (const auto& instance : instances) @@ -106,18 +112,18 @@ void Formatter::WriteFiles(_In_ const CommandArgs& args, _In_ Console& console, auto hr = instance->GetInstallationPath(bstrInstallationPath.GetAddress()); if (SUCCEEDED(hr)) { - Glob glob(static_cast(bstrInstallationPath), args.get_Find()); + Glob glob(static_cast(bstrInstallationPath), Args().get_Find()); - auto entries = glob.Entries(args.get_Sort()); + auto entries = glob.Entries(Args().get_Sort()); for (const auto& entry : entries) { - WriteProperty(console, L"file", entry); + WriteProperty(L"file", entry); } } } - EndArray(console); - EndDocument(console); + EndArray(); + EndDocument(); } wstring Formatter::FormatDateISO8601(_In_ const FILETIME& value) @@ -185,13 +191,13 @@ wstring Formatter::FormatDate(_In_ const FILETIME& value) return date + L" " + time; } -void Formatter::WriteInternal(_In_ const CommandArgs& args, _In_ Console& console, _In_ ISetupInstance* pInstance) +void Formatter::WriteInternal(_In_ ISetupInstance* pInstance) { _ASSERTE(pInstance); - StartObject(console); + StartObject(); - wstring specified = args.get_Property(); + wstring specified = Args().get_Property(); variant_t vtValue; bool found = false; @@ -204,14 +210,14 @@ void Formatter::WriteInternal(_In_ const CommandArgs& args, _In_ Console& consol auto hr = property.second(pInstance, vtValue.GetAddress()); if (SUCCEEDED(hr)) { - WriteProperty(console, property.first, vtValue); + WriteProperty(property.first, vtValue); } } } if (specified.empty() || !found) { - found = WriteProperties(args, console, pInstance); + found = WriteProperties(pInstance); // Output catalog information. if (specified.empty() || !found) @@ -227,11 +233,11 @@ void Formatter::WriteInternal(_In_ const CommandArgs& args, _In_ Console& consol if (SUCCEEDED(hr) && !!store) { wstring name(L"catalog"); - StartObject(console, name); + StartObject(name); - found = WriteProperties(args, console, store, name); + found = WriteProperties(store, name); - EndObject(console); + EndObject(); } } } @@ -250,79 +256,79 @@ void Formatter::WriteInternal(_In_ const CommandArgs& args, _In_ Console& consol if (SUCCEEDED(hr) && !!store) { wstring name(L"properties"); - StartObject(console, name); + StartObject(name); - found = WriteProperties(args, console, store, name); + found = WriteProperties(store, name); - EndObject(console); + EndObject(); } } } - if (args.get_IncludePackages() && SupportsPackages()) + if (Args().get_IncludePackages() && SupportsPackages()) { if (specified.empty() || s_comparer(specified, L"packages")) { - WritePackages(args, console, pInstance); + WritePackages(pInstance); } } } - EndObject(console); + EndObject(); } -void Formatter::WritePackage(_In_ Console& console, _In_ ISetupPackageReference* pPackage) +void Formatter::WritePackage(_In_ ISetupPackageReference* pPackage) { - StartObject(console, L"package"); + StartObject(L"package"); bstr_t bstr; auto hr = pPackage->GetId(bstr.GetAddress()); if (SUCCEEDED(hr)) { - WriteProperty(console, L"id", bstr); + WriteProperty(L"id", bstr); } hr = pPackage->GetVersion(bstr.GetAddress()); if (SUCCEEDED(hr) && bstr.length()) { - WriteProperty(console, L"version", bstr); + WriteProperty(L"version", bstr); } hr = pPackage->GetChip(bstr.GetAddress()); if (SUCCEEDED(hr) && bstr.length()) { - WriteProperty(console, L"chip", bstr); + WriteProperty(L"chip", bstr); } hr = pPackage->GetLanguage(bstr.GetAddress()); if (SUCCEEDED(hr) && bstr.length()) { - WriteProperty(console, L"language", bstr); + WriteProperty(L"language", bstr); } hr = pPackage->GetBranch(bstr.GetAddress()); if (SUCCEEDED(hr) && bstr.length()) { - WriteProperty(console, L"branch", bstr); + WriteProperty(L"branch", bstr); } hr = pPackage->GetType(bstr.GetAddress()); if (SUCCEEDED(hr)) { - WriteProperty(console, L"type", bstr); + WriteProperty(L"type", bstr); } VARIANT_BOOL vtBool; hr = pPackage->GetIsExtension(&vtBool); if (SUCCEEDED(hr) && VARIANT_TRUE == vtBool) { - WriteProperty(console, L"extension", true); + WriteProperty(L"extension", true); } - EndObject(console); + EndObject(); } -void Formatter::WritePackages(_In_ const CommandArgs& args, _In_ Console& console, _In_ ISetupInstance* pInstance) +void Formatter::WritePackages(_In_ ISetupInstance* pInstance) { ISetupInstance2Ptr instance2; LPSAFEARRAY psaPackages; @@ -333,31 +339,31 @@ void Formatter::WritePackages(_In_ const CommandArgs& args, _In_ Console& consol hr = instance2->GetPackages(&psaPackages); if (SUCCEEDED(hr) && psaPackages->rgsabound[0].cElements) { - StartArray(console, L"packages"); + StartArray(L"packages"); SafeArray saPackages(psaPackages); const auto packages = saPackages.Elements(); for (const auto& package : packages) { - WritePackage(console, package); + WritePackage(package); } - EndArray(console); + EndArray(); } } } -void Formatter::WriteProperty(_In_ Console& console, _In_ const wstring& name, _In_ const variant_t& value) +void Formatter::WriteProperty(_In_ const wstring& name, _In_ const variant_t& value) { switch (value.vt) { case VT_BOOL: - WriteProperty(console, name, VARIANT_TRUE == value.boolVal); + WriteProperty(name, VARIANT_TRUE == value.boolVal); break; case VT_BSTR: - WriteProperty(console, name, wstring(value.bstrVal)); + WriteProperty(name, wstring(value.bstrVal)); break; case VT_I1: @@ -367,12 +373,12 @@ void Formatter::WriteProperty(_In_ Console& console, _In_ const wstring& name, _ case VT_UI1: case VT_UI2: case VT_UI4: - WriteProperty(console, name, value.llVal); + WriteProperty(name, value.llVal); break; } } -bool Formatter::WriteProperties(_In_ const CommandArgs& args, _In_ Console& console, _In_ ISetupInstance* pInstance) +bool Formatter::WriteProperties(_In_ ISetupInstance* pInstance) { _ASSERTE(pInstance); @@ -389,10 +395,10 @@ bool Formatter::WriteProperties(_In_ const CommandArgs& args, _In_ Console& cons return false; } - return WriteProperties(args, console, store); + return WriteProperties(store); } -bool Formatter::WriteProperties(_In_ const CommandArgs& args, _In_ Console& console, _In_ ISetupPropertyStore* pProperties, _In_opt_ const wstring& prefix) +bool Formatter::WriteProperties(_In_ ISetupPropertyStore* pProperties, _In_opt_ const wstring& prefix) { _ASSERTE(pProperties); @@ -408,7 +414,7 @@ bool Formatter::WriteProperties(_In_ const CommandArgs& args, _In_ Console& cons } // Trim optional nested object name from specified property if matching current scope. - wstring specified = args.get_Property(); + wstring specified = Args().get_Property(); if (prefix.size() > 0) { auto pos = specified.find_first_of(s_delims); @@ -448,7 +454,7 @@ bool Formatter::WriteProperties(_In_ const CommandArgs& args, _In_ Console& cons hr = pProperties->GetValue(bstrName, vtValue.GetAddress()); if (SUCCEEDED(hr)) { - WriteProperty(console, name, vtValue); + WriteProperty(name, vtValue); } } diff --git a/src/vswhere.lib/Formatter.h b/src/vswhere.lib/Formatter.h index cd8afdf..58ec944 100644 --- a/src/vswhere.lib/Formatter.h +++ b/src/vswhere.lib/Formatter.h @@ -8,21 +8,23 @@ class Formatter { public: - typedef std::function()> FormatterFactory; + typedef std::function(CommandArgs&, Console&)> FormatterFactory; typedef std::map, ci_less> FormatterMap; - static std::unique_ptr Create(const std::wstring& type); + static std::unique_ptr Create(_In_ const std::wstring& type, _In_ CommandArgs& args, _In_ Console& console); static FormatterMap Formatters; Formatter(_In_ const Formatter& obj) : + m_args(obj.m_args), + m_console(obj.m_console), m_properties(obj.m_properties) { } - void Write(_In_ Console& console, _In_ const std::wstring& root, _In_ const std::wstring& name, _In_ const std::vector values); - void Write(_In_ const CommandArgs& args, _In_ Console& console, _In_ ISetupInstance* pInstance); - void Write(_In_ const CommandArgs& args, _In_ Console& console, _In_ std::vector instances); - void WriteFiles(_In_ const CommandArgs& args, _In_ Console& console, std::vector instances); + void Write(_In_ const std::wstring& root, _In_ const std::wstring& name, _In_ const std::vector values); + void Write(_In_ ISetupInstance* pInstance); + void Write(_In_ std::vector instances); + void WriteFiles(_In_ std::vector instances); virtual bool ShowLogo() const { @@ -34,36 +36,49 @@ class Formatter return false; } + static const LPCWSTR ColorName; + static const LPCWSTR ColorValue; + protected: typedef std::function PropertyFunction; typedef std::vector> PropertyArray; static const std::wstring empty_wstring; - Formatter(); + Formatter(_In_ CommandArgs& args, _In_ Console& console); static std::wstring FormatDateISO8601(_In_ const FILETIME& value); - virtual void StartDocument(_In_ Console& console) {} - virtual void StartArray(_In_ Console& console, _In_opt_ const std::wstring& name = empty_wstring) {} - virtual void StartObject(_In_ Console& console, _In_opt_ const std::wstring& name = empty_wstring) {} - virtual void WriteProperty(_In_ Console& console, _In_ const std::wstring& name, _In_ const std::wstring& value) {} - virtual void EndObject(_In_ Console& console) {} - virtual void EndArray(_In_ Console& console) {} - virtual void EndDocument(_In_ Console& console) {} + virtual void StartDocument() {} + virtual void StartArray(_In_opt_ const std::wstring& name = empty_wstring) {} + virtual void StartObject(_In_opt_ const std::wstring& name = empty_wstring) {} + virtual void WriteProperty(_In_ const std::wstring& name, _In_ const std::wstring& value) {} + virtual void EndObject() {} + virtual void EndArray() {} + virtual void EndDocument() {} - virtual void WriteProperty(_In_ Console& console, _In_ const std::wstring& name, _In_ bool value) + virtual void WriteProperty(_In_ const std::wstring& name, _In_ bool value) { - WriteProperty(console, name, std::to_wstring(value)); + WriteProperty(name, std::to_wstring(value)); } - virtual void WriteProperty(_In_ Console& console, _In_ const std::wstring& name, _In_ long long value) + virtual void WriteProperty(_In_ const std::wstring& name, _In_ long long value) { - WriteProperty(console, name, std::to_wstring(value)); + WriteProperty(name, std::to_wstring(value)); } virtual std::wstring FormatDate(_In_ const FILETIME& value); + CommandArgs& Args() const noexcept + { + return m_args; + } + + Console& Console() const noexcept + { + return m_console; + } + private: static bool PropertyEqual(_In_ const std::wstring& name, _In_ PropertyArray::const_reference property); static HRESULT GetStringProperty(_In_ std::function pfn, _Out_ VARIANT* pvt); @@ -86,12 +101,14 @@ class Formatter HRESULT GetDisplayName(_In_ ISetupInstance* pInstance, _Out_ VARIANT* pvtDisplayName); HRESULT GetDescription(_In_ ISetupInstance* pInstance, _Out_ VARIANT* pvtDescription); - void WriteInternal(_In_ const CommandArgs& args, _In_ Console& console, _In_ ISetupInstance* pInstance); - void WritePackage(_In_ Console& console, _In_ ISetupPackageReference* pPackage); - void WritePackages(_In_ const CommandArgs& args, _In_ Console& console, _In_ ISetupInstance* pInstance); - void WriteProperty(_In_ Console& console, _In_ const std::wstring& name, _In_ const variant_t& value); - bool WriteProperties(_In_ const CommandArgs& args, _In_ Console& console, _In_ ISetupInstance* pInstance); - bool WriteProperties(_In_ const CommandArgs& args, _In_ Console& console, _In_ ISetupPropertyStore* pProperties, _In_opt_ const std::wstring& prefix = empty_wstring); + void WriteInternal(_In_ ISetupInstance* pInstance); + void WritePackage(_In_ ISetupPackageReference* pPackage); + void WritePackages(_In_ ISetupInstance* pInstance); + void WriteProperty(_In_ const std::wstring& name, _In_ const variant_t& value); + bool WriteProperties(_In_ ISetupInstance* pInstance); + bool WriteProperties(_In_ ISetupPropertyStore* pProperties, _In_opt_ const std::wstring& prefix = empty_wstring); + CommandArgs& m_args; + ::Console& m_console; PropertyArray m_properties; }; diff --git a/src/vswhere.lib/JsonFormatter.cpp b/src/vswhere.lib/JsonFormatter.cpp index 8bf45af..bdbcd85 100644 --- a/src/vswhere.lib/JsonFormatter.cpp +++ b/src/vswhere.lib/JsonFormatter.cpp @@ -7,6 +7,9 @@ using namespace std; +const LPCWSTR JsonFormatter::ColorBool = L"\033[38;2;86;156;214m"; +const LPCWSTR JsonFormatter::ColorNumber = L"\033[38;2;181;206;168m"; + wstring JsonFormatter::Escape(_In_ const wstring& value) { wstring buffer; @@ -26,49 +29,49 @@ wstring JsonFormatter::Escape(_In_ const wstring& value) return buffer; } -void JsonFormatter::StartArray(_In_ Console& console, _In_opt_ const std::wstring& name) +void JsonFormatter::StartArray(_In_opt_ const std::wstring& name) { - StartScope(console, JsonScope::Type::array, name); + StartScope(JsonScope::Type::array, name); } -void JsonFormatter::StartObject(_In_ Console& console, _In_opt_ const wstring& name) +void JsonFormatter::StartObject(_In_opt_ const wstring& name) { - StartScope(console, JsonScope::Type::object, name); + StartScope(JsonScope::Type::object, name); } -void JsonFormatter::WriteProperty(_In_ Console& console, _In_ const wstring& name, _In_ const wstring& value) +void JsonFormatter::WriteProperty(_In_ const wstring& name, _In_ const wstring& value) { - StartProperty(console, name); + StartProperty(name); auto escaped = Escape(value); - console.Write(L"\"%ls\"",escaped.c_str()); + Console().Write(L"%ls\"%ls\"%ls", Console().Color(ColorValue), escaped.c_str(), Console().ResetColor()); } -void JsonFormatter::WriteProperty(_In_ Console& console, _In_ const wstring& name, _In_ bool value) +void JsonFormatter::WriteProperty(_In_ const wstring& name, _In_ bool value) { - StartProperty(console, name); - console.Write(value ? L"true" : L"false"); + StartProperty(name); + Console().Write(L"%ls%ls%ls", Console().Color(ColorBool), value ? L"true" : L"false", Console().ResetColor()); } -void JsonFormatter::WriteProperty(_In_ Console& console, _In_ const wstring& name, _In_ long long value) +void JsonFormatter::WriteProperty(_In_ const wstring& name, _In_ long long value) { - StartProperty(console, name); - console.Write(L"%I64d", value); + StartProperty(name); + Console().Write(L"%ls%I64d%ls", Console().Color(ColorNumber), value, Console().ResetColor()); } -void JsonFormatter::EndObject(_In_ Console& console) +void JsonFormatter::EndObject() { - EndScope(console); + EndScope(); } -void JsonFormatter::EndArray(_In_ Console& console) +void JsonFormatter::EndArray() { - EndScope(console); + EndScope(); } -void JsonFormatter::EndDocument(_In_ Console& console) +void JsonFormatter::EndDocument() { - console.WriteLine(); + Console().WriteLine(); } wstring JsonFormatter::FormatDate(_In_ const FILETIME& value) @@ -89,43 +92,43 @@ void JsonFormatter::Pop() } } -void JsonFormatter::StartScope(_In_ Console& console, _In_ JsonScope::Type type, _In_ const std::wstring& name) +void JsonFormatter::StartScope(_In_ JsonScope::Type type, _In_ const std::wstring& name) { JsonScope* pParent = nullptr; if (m_scopes.size()) { auto& top = m_scopes.top(); - top.StartScope(console); + top.StartScope(); pParent = ⊤ } - m_scopes.push(JsonScope(pParent, m_padding, type, name)); + m_scopes.push(JsonScope(pParent, Console(), m_padding, type, name)); // Always write the root scope. if (m_scopes.size() == 1) { - m_scopes.top().WriteStart(console); + m_scopes.top().WriteStart(); } Push(); } -void JsonFormatter::StartProperty(_In_ Console& console, _In_ const std::wstring& name) +void JsonFormatter::StartProperty(_In_ const std::wstring& name) { - m_scopes.top().StartProperty(console); + m_scopes.top().StartProperty(); - console.Write(L"\n%ls", m_padding.c_str()); + Console().Write(L"\n%ls", m_padding.c_str()); if (m_scopes.top().IsObject()) { - console.Write(L"\"%ls\": ", name.c_str()); + Console().Write(L"%ls\"%ls\"%ls: ", Console().Color(ColorName), name.c_str(), Console().ResetColor()); } } -void JsonFormatter::EndScope(_In_ Console& console) +void JsonFormatter::EndScope() { Pop(); - m_scopes.top().WriteEnd(console); + m_scopes.top().WriteEnd(); m_scopes.pop(); } diff --git a/src/vswhere.lib/JsonFormatter.h b/src/vswhere.lib/JsonFormatter.h index 893bbf5..40278e3 100644 --- a/src/vswhere.lib/JsonFormatter.h +++ b/src/vswhere.lib/JsonFormatter.h @@ -9,13 +9,13 @@ class JsonFormatter : public Formatter { public: - static std::unique_ptr Create() + static std::unique_ptr Create(_In_ CommandArgs& args, _In_ ::Console& console) { - return std::unique_ptr(new JsonFormatter()); + return std::unique_ptr(new JsonFormatter(args, console)); } - JsonFormatter() : - Formatter() + JsonFormatter(_In_ CommandArgs& args, _In_ ::Console& console) : + Formatter(args, console) { } @@ -38,15 +38,18 @@ class JsonFormatter : return true; } + static const LPCWSTR ColorBool; + static const LPCWSTR ColorNumber; + protected: - void StartArray(_In_ Console& console, _In_opt_ const std::wstring& name = empty_wstring) override; - void StartObject(_In_ Console& console, _In_opt_ const std::wstring& name = empty_wstring) override; - void WriteProperty(_In_ Console& console, _In_ const std::wstring& name, _In_ const std::wstring& value) override; - void WriteProperty(_In_ Console& console, _In_ const std::wstring& name, _In_ bool value) override; - void WriteProperty(_In_ Console& console, _In_ const std::wstring& name, _In_ long long value) override; - void EndObject(_In_ Console& console) override; - void EndArray(_In_ Console& console) override; - void EndDocument(_In_ Console& console) override; + void StartArray(_In_opt_ const std::wstring& name = empty_wstring) override; + void StartObject(_In_opt_ const std::wstring& name = empty_wstring) override; + void WriteProperty(_In_ const std::wstring& name, _In_ const std::wstring& value) override; + void WriteProperty(_In_ const std::wstring& name, _In_ bool value) override; + void WriteProperty(_In_ const std::wstring& name, _In_ long long value) override; + void EndObject() override; + void EndArray() override; + void EndDocument() override; std::wstring FormatDate(_In_ const FILETIME& value) override; private: @@ -55,9 +58,9 @@ class JsonFormatter : void Push(); void Pop(); - void StartScope(_In_ Console& console, _In_ JsonScope::Type type, _In_ const std::wstring& name); - void StartProperty(_In_ Console& console, _In_ const std::wstring& name); - void EndScope(_In_ Console& console); + void StartScope(_In_ JsonScope::Type type, _In_ const std::wstring& name); + void StartProperty(_In_ const std::wstring& name); + void EndScope(); std::wstring m_padding; std::stack m_scopes; diff --git a/src/vswhere.lib/JsonScope.cpp b/src/vswhere.lib/JsonScope.cpp index fb987a5..df352ed 100644 --- a/src/vswhere.lib/JsonScope.cpp +++ b/src/vswhere.lib/JsonScope.cpp @@ -7,25 +7,25 @@ using namespace std; -void JsonScope::StartScope(_In_ Console& console) +void JsonScope::StartScope() { - WriteSeparator(console); + WriteSeparator(); } -void JsonScope::StartProperty(_In_ Console& console) +void JsonScope::StartProperty() { // Delay writing the parent scope until we write a property. - WriteStart(console); + WriteStart(); - WriteSeparator(console); + WriteSeparator(); RequireSeparator(); } -void JsonScope::WriteStartImpl(_In_ Console& console) +void JsonScope::WriteStartImpl() { bool writeKey = false; - WriteSeparator(console); + WriteSeparator(); if (Parent()) { @@ -35,29 +35,35 @@ void JsonScope::WriteStartImpl(_In_ Console& console) } // Write new line if not the root scope. - console.WriteLine(); + Console().WriteLine(); } if (writeKey && Name().length()) { - console.Write(L"%ls\"%ls\": %lc", Padding().c_str(), Name().c_str(), StartChar()); + Console().Write( + L"%ls%ls\"%ls\"%ls: %lc", + Padding().c_str(), + Console().Color(JsonFormatter::ColorName), + Name().c_str(), + Console().ResetColor(), + StartChar()); } else { - console.Write(L"%ls%lc", Padding().c_str(), StartChar()); + Console().Write(L"%ls%lc", Padding().c_str(), StartChar()); } } -void JsonScope::WriteEndImpl(_In_ Console& console) +void JsonScope::WriteEndImpl() { if (m_requireSep) { // Write new line and padding only if elements were written. // This keeps empty arrays and objects looking like [] and {}. - console.Write(L"\n%ls", Padding().c_str()); + Console().Write(L"\n%ls", Padding().c_str()); } - console.Write(L"%lc", EndChar()); + Console().Write(L"%lc", EndChar()); } void JsonScope::RequireSeparator() noexcept @@ -70,10 +76,10 @@ void JsonScope::RequireSeparator() noexcept } } -void JsonScope::WriteSeparator(_In_ Console& console) +void JsonScope::WriteSeparator() { if (m_requireSep) { - console.Write(L","); + Console().Write(L","); } } diff --git a/src/vswhere.lib/JsonScope.h b/src/vswhere.lib/JsonScope.h index 66f88cb..8e1b510 100644 --- a/src/vswhere.lib/JsonScope.h +++ b/src/vswhere.lib/JsonScope.h @@ -11,8 +11,8 @@ class JsonScope : public: typedef enum { array, object } Type; - JsonScope(_In_opt_ JsonScope* pParent, _In_ const std::wstring& padding, _In_ Type type, _In_ const std::wstring& name) : - Scope(pParent, padding, name), + JsonScope(_In_opt_ JsonScope* pParent, _In_ ::Console& console, _In_ const std::wstring& padding, _In_ Type type, _In_ const std::wstring& name) : + Scope(pParent, console, padding, name), m_type(type), m_requireSep(false) { @@ -35,16 +35,16 @@ class JsonScope : return m_type == Type::object; } - void StartScope(_In_ Console& console); - void StartProperty(_In_ Console& console); + void StartScope(); + void StartProperty(); protected: - void WriteStartImpl(_In_ Console& console) override; - void WriteEndImpl(_In_ Console& console) override; + void WriteStartImpl() override; + void WriteEndImpl() override; private: void RequireSeparator() noexcept; - void WriteSeparator(_In_ Console& console); + void WriteSeparator(); wchar_t StartChar() const noexcept { diff --git a/src/vswhere.lib/Scope.h b/src/vswhere.lib/Scope.h index 446cecd..f98011b 100644 --- a/src/vswhere.lib/Scope.h +++ b/src/vswhere.lib/Scope.h @@ -9,8 +9,9 @@ template class Scope { public: - Scope(_In_opt_ _Type* pParent, _In_ const std::wstring& padding, _In_ const std::wstring& name) : + Scope(_In_opt_ _Type* pParent, _In_ ::Console& console, _In_ const std::wstring& padding, _In_ const std::wstring& name) : m_pParent(pParent), + m_console(console), m_padding(padding), m_name(name), m_writeStart(true), @@ -18,8 +19,9 @@ class Scope { } - Scope(_In_opt_ _Type* pParent, _In_ std::wstring& padding, _In_ std::wstring::const_pointer name) : + Scope(_In_opt_ _Type* pParent, _In_ ::Console& console, _In_ std::wstring& padding, _In_ std::wstring::const_pointer name) : m_pParent(pParent), + m_console(console), m_padding(padding), m_name(name), m_writeStart(true), @@ -29,6 +31,7 @@ class Scope Scope(_In_ const Scope& obj) : m_pParent(obj.m_pParent), + m_console(obj.m_console), m_padding(obj.m_padding), m_name(obj.m_name), m_writeStart(obj.m_writeStart), @@ -36,27 +39,27 @@ class Scope { } - void WriteStart(_In_ Console& console) + void WriteStart() { if (m_writeStart) { // Write the parent scope first (may have already been written to console). if (m_pParent) { - m_pParent->WriteStart(console); + m_pParent->WriteStart(); } - WriteStartImpl(console); + WriteStartImpl(); m_writeStart = false; m_writeEnd = true; } } - void WriteEnd(_In_ Console& console) + void WriteEnd() { if (m_writeEnd) { - WriteEndImpl(console); + WriteEndImpl(); } } @@ -66,6 +69,11 @@ class Scope return m_pParent; } + ::Console& Console() const noexcept + { + return m_console; + } + const std::wstring& Padding() const noexcept { return m_padding; @@ -76,11 +84,12 @@ class Scope return m_name; } - virtual void WriteStartImpl(_In_ Console& console) = 0; - virtual void WriteEndImpl(_In_ Console& console) = 0; + virtual void WriteStartImpl() = 0; + virtual void WriteEndImpl() = 0; private: _Type* m_pParent; + ::Console& m_console; const std::wstring m_padding; const std::wstring m_name; bool m_writeStart; diff --git a/src/vswhere.lib/TextFormatter.cpp b/src/vswhere.lib/TextFormatter.cpp index 1134121..cd76645 100644 --- a/src/vswhere.lib/TextFormatter.cpp +++ b/src/vswhere.lib/TextFormatter.cpp @@ -7,16 +7,16 @@ using namespace std; -void TextFormatter::StartArray(_In_ Console& console, _In_opt_ const std::wstring& name) +void TextFormatter::StartArray(_In_opt_ const std::wstring& name) { m_first = true; } -void TextFormatter::StartObject(_In_ Console& console, _In_opt_ const wstring& name) +void TextFormatter::StartObject(_In_opt_ const wstring& name) { if (!m_first && m_scopes.empty()) { - console.WriteLine(); + Console().WriteLine(); } m_first = false; @@ -35,7 +35,7 @@ void TextFormatter::StartObject(_In_ Console& console, _In_opt_ const wstring& n } } -void TextFormatter::WriteProperty(_In_ Console& console, _In_ const std::wstring& name, _In_ const std::wstring& value) +void TextFormatter::WriteProperty(_In_ const std::wstring& name, _In_ const std::wstring& value) { wstring prefix = L""; if (!m_scopes.empty()) @@ -43,10 +43,11 @@ void TextFormatter::WriteProperty(_In_ Console& console, _In_ const std::wstring prefix = m_scopes.top(); } - console.WriteLine(L"%ls%ls: %ls", prefix.c_str(), name.c_str(), value.c_str()); + Console().Write(L"%ls%ls%ls%ls: ", Console().Color(ColorName), prefix.c_str(), name.c_str(), Console().ResetColor()); + Console().WriteLine(L"%ls%ls%ls", Console().Color(ColorValue), value.c_str(), Console().ResetColor()); } -void TextFormatter::EndObject(_In_ Console& console) +void TextFormatter::EndObject() { m_scopes.pop(); -} +} \ No newline at end of file diff --git a/src/vswhere.lib/TextFormatter.h b/src/vswhere.lib/TextFormatter.h index 442a925..3b45aa4 100644 --- a/src/vswhere.lib/TextFormatter.h +++ b/src/vswhere.lib/TextFormatter.h @@ -9,13 +9,13 @@ class TextFormatter : public Formatter { public: - static std::unique_ptr Create() + static std::unique_ptr Create(_In_ CommandArgs& args, _In_ ::Console& console) { - return std::unique_ptr(new TextFormatter()); + return std::unique_ptr(new TextFormatter(args, console)); } - TextFormatter() : - Formatter(), + TextFormatter(_In_ CommandArgs& args, _In_ ::Console& console) : + Formatter(args, console), m_first(false) { } @@ -28,10 +28,10 @@ class TextFormatter : } protected: - void StartArray(_In_ Console& console, _In_opt_ const std::wstring& name = empty_wstring) override; - void StartObject(_In_ Console& console, _In_opt_ const std::wstring& name = empty_wstring) override; - void WriteProperty(_In_ Console& console, _In_ const std::wstring& name, _In_ const std::wstring& value) override; - void EndObject(_In_ Console& console) override; + void StartArray(_In_opt_ const std::wstring& name = empty_wstring) override; + void StartObject(_In_opt_ const std::wstring& name = empty_wstring) override; + void WriteProperty(_In_ const std::wstring& name, _In_ const std::wstring& value) override; + void EndObject() override; private: bool m_first; diff --git a/src/vswhere.lib/ValueFormatter.cpp b/src/vswhere.lib/ValueFormatter.cpp index 012fd3f..f100a4e 100644 --- a/src/vswhere.lib/ValueFormatter.cpp +++ b/src/vswhere.lib/ValueFormatter.cpp @@ -7,7 +7,7 @@ using namespace std; -void ValueFormatter::WriteProperty(_In_ Console& console, _In_ const std::wstring& name, _In_ const std::wstring& value) +void ValueFormatter::WriteProperty(_In_ const std::wstring& name, _In_ const std::wstring& value) { - console.WriteLine(value); + Console().WriteLine(value); } diff --git a/src/vswhere.lib/ValueFormatter.h b/src/vswhere.lib/ValueFormatter.h index 6b36d56..7bdfe25 100644 --- a/src/vswhere.lib/ValueFormatter.h +++ b/src/vswhere.lib/ValueFormatter.h @@ -9,13 +9,13 @@ class ValueFormatter : public Formatter { public: - static std::unique_ptr Create() + static std::unique_ptr Create(_In_ CommandArgs& args, _In_ ::Console& console) { - return std::unique_ptr(new ValueFormatter()); + return std::unique_ptr(new ValueFormatter(args, console)); } - ValueFormatter() : - Formatter() + ValueFormatter(_In_ CommandArgs& args, _In_ ::Console& console) : + Formatter(args, console) { } @@ -30,5 +30,5 @@ class ValueFormatter : } protected: - void WriteProperty(_In_ Console& console, _In_ const std::wstring& name, _In_ const std::wstring& value) override; + void WriteProperty(_In_ const std::wstring& name, _In_ const std::wstring& value) override; }; diff --git a/src/vswhere.lib/XmlFormatter.cpp b/src/vswhere.lib/XmlFormatter.cpp index e5e0703..f3c09d9 100644 --- a/src/vswhere.lib/XmlFormatter.cpp +++ b/src/vswhere.lib/XmlFormatter.cpp @@ -7,35 +7,49 @@ using namespace std; -void XmlFormatter::StartDocument(_In_ Console& console) +const LPCWSTR XmlFormatter::ColorTag = L"\033[38;2;86;156;214m"; + +void XmlFormatter::StartDocument() { - console.WriteLine(L""); + Console().WriteLine( + L"%1$ls%4$ls", + Console().Color(ColorTag), + Console().Color(ColorName), + Console().Color(ColorValue), + Console().ResetColor()); } -void XmlFormatter::StartArray(_In_ Console& console, _In_opt_ const wstring& name) +void XmlFormatter::StartArray(_In_opt_ const wstring& name) { - StartScope(console, name, L"instances"); + StartScope(name, L"instances"); } -void XmlFormatter::StartObject(_In_ Console& console, _In_opt_ const wstring& name) +void XmlFormatter::StartObject(_In_opt_ const wstring& name) { - StartScope(console, name, L"instance"); + StartScope(name, L"instance"); } -void XmlFormatter::WriteProperty(_In_ Console& console, _In_ const wstring& name, _In_ const wstring& value) +void XmlFormatter::WriteProperty(_In_ const wstring& name, _In_ const wstring& value) { - m_scopes.top().WriteStart(console); - console.WriteLine(L"%1$ls<%2$ls>%3$ls", m_padding.c_str(), name.c_str(), value.c_str()); + m_scopes.top().WriteStart(); + + Console().WriteLine( + L"%1$ls%4$ls<%2$ls>%5$ls%3$ls%4$ls%5$ls", + m_padding.c_str(), + name.c_str(), + value.c_str(), + Console().Color(ColorTag), + Console().ResetColor()); } -void XmlFormatter::EndObject(_In_ Console& console) +void XmlFormatter::EndObject() { - EndScope(console); + EndScope(); } -void XmlFormatter::EndArray(_In_ Console& console) +void XmlFormatter::EndArray() { - EndScope(console); + EndScope(); } wstring XmlFormatter::FormatDate(_In_ const FILETIME& value) @@ -56,7 +70,7 @@ void XmlFormatter::Pop() } } -void XmlFormatter::StartScope(_In_ Console& console, _In_opt_ const wstring& name, _In_ std::wstring::const_pointer fallback) +void XmlFormatter::StartScope(_In_opt_ const wstring& name, _In_ std::wstring::const_pointer fallback) { XmlScope* pParent = nullptr; if (m_scopes.size()) @@ -66,26 +80,26 @@ void XmlFormatter::StartScope(_In_ Console& console, _In_opt_ const wstring& nam if (name.empty()) { - m_scopes.push(XmlScope(pParent, m_padding, fallback)); + m_scopes.push(XmlScope(pParent, Console(), m_padding, fallback)); } else { - m_scopes.push(XmlScope(pParent, m_padding, name)); + m_scopes.push(XmlScope(pParent, Console(), m_padding, name)); } // Always write the root scope. if (m_scopes.size() == 1) { - m_scopes.top().WriteStart(console); + m_scopes.top().WriteStart(); } Push(); } -void XmlFormatter::EndScope(_In_ Console& console) +void XmlFormatter::EndScope() { Pop(); - m_scopes.top().WriteEnd(console); + m_scopes.top().WriteEnd(); m_scopes.pop(); } diff --git a/src/vswhere.lib/XmlFormatter.h b/src/vswhere.lib/XmlFormatter.h index 7157903..163c052 100644 --- a/src/vswhere.lib/XmlFormatter.h +++ b/src/vswhere.lib/XmlFormatter.h @@ -9,13 +9,13 @@ class XmlFormatter : public Formatter { public: - static std::unique_ptr Create() + static std::unique_ptr Create(_In_ CommandArgs& args, _In_ ::Console& console) { - return std::unique_ptr(new XmlFormatter()); + return std::unique_ptr(new XmlFormatter(args, console)); } - XmlFormatter() : - Formatter() + XmlFormatter(_In_ CommandArgs& args, _In_ ::Console& console) : + Formatter(args, console) { } @@ -36,13 +36,15 @@ class XmlFormatter : return true; } + static const LPCWSTR ColorTag; + protected: - void StartDocument(_In_ Console& console) override; - void StartArray(_In_ Console& console, _In_opt_ const std::wstring& name = empty_wstring) override; - void StartObject(_In_ Console& console, _In_opt_ const std::wstring& name = empty_wstring) override; - void WriteProperty(_In_ Console& console, _In_ const std::wstring& name, _In_ const std::wstring& value) override; - void EndObject(_In_ Console& console) override; - void EndArray(_In_ Console& console) override; + void StartDocument() override; + void StartArray(_In_opt_ const std::wstring& name = empty_wstring) override; + void StartObject(_In_opt_ const std::wstring& name = empty_wstring) override; + void WriteProperty(_In_ const std::wstring& name, _In_ const std::wstring& value) override; + void EndObject() override; + void EndArray() override; std::wstring FormatDate(_In_ const FILETIME& value) override; private: @@ -51,8 +53,8 @@ class XmlFormatter : void Push(); void Pop(); - void StartScope(_In_ Console& console, _In_opt_ const std::wstring& name, _In_ std::wstring::const_pointer fallback); - void EndScope(_In_ Console& console); + void StartScope(_In_opt_ const std::wstring& name, _In_ std::wstring::const_pointer fallback); + void EndScope(); std::wstring m_padding; std::stack m_scopes; diff --git a/src/vswhere.lib/XmlScope.cpp b/src/vswhere.lib/XmlScope.cpp new file mode 100644 index 0000000..c50a4d5 --- /dev/null +++ b/src/vswhere.lib/XmlScope.cpp @@ -0,0 +1,20 @@ +// +// Copyright (C) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE.txt in the project root for license information. +// + +#include "stdafx.h" + +using namespace std; + +void XmlScope::WriteStartImpl() +{ + Console().Write(Padding()); + Console().WriteLine(L"%ls<%ls>%ls", Console().Color(XmlFormatter::ColorTag), Name().c_str(), Console().ResetColor()); +} + +void XmlScope::WriteEndImpl() +{ + Console().Write(Padding()); + Console().WriteLine(L"%ls%ls", Console().Color(XmlFormatter::ColorTag), Name().c_str(), Console().ResetColor()); +} diff --git a/src/vswhere.lib/XmlScope.h b/src/vswhere.lib/XmlScope.h index 24c8aa9..f53eb97 100644 --- a/src/vswhere.lib/XmlScope.h +++ b/src/vswhere.lib/XmlScope.h @@ -9,13 +9,13 @@ class XmlScope : public Scope { public: - XmlScope(_In_opt_ XmlScope* pParent, _In_ const std::wstring& padding, _In_ const std::wstring& name) : - Scope(pParent, padding, name) + XmlScope(_In_opt_ XmlScope* pParent, _In_ ::Console& console, _In_ const std::wstring& padding, _In_ const std::wstring& name) : + Scope(pParent, console, padding, name) { } - XmlScope(_In_opt_ XmlScope* pParent, _In_ std::wstring& padding, _In_ std::wstring::const_pointer name) : - Scope(pParent, padding, name) + XmlScope(_In_opt_ XmlScope* pParent, _In_ ::Console& console, _In_ std::wstring& padding, _In_ std::wstring::const_pointer name) : + Scope(pParent, console, padding, name) { } @@ -25,13 +25,6 @@ class XmlScope : } protected: - void WriteStartImpl(_In_ Console& console) override - { - console.WriteLine(L"%ls<%ls>", Padding().c_str(), Name().c_str()); - } - - void WriteEndImpl(_In_ Console& console) override - { - console.WriteLine(L"%ls", Padding().c_str(), Name().c_str()); - } + void WriteStartImpl() override; + void WriteEndImpl() override; }; diff --git a/src/vswhere.lib/vswhere.lib.rc b/src/vswhere.lib/vswhere.lib.rc index 46fb06531be55e99210e039f44a4394592b81bdc..63aa4a2d437ab5085d0e33025bca9f5f43d7332a 100644 GIT binary patch delta 355 zcmZ8dI|{-;5PhH`mZAt2%0e0g#zS}v3n6O!V1C36VimNukzB%3$tmo`^Y~^JMOiXT z-n`H3K1Rp!DC2s + diff --git a/src/vswhere.lib/vswhere.lib.vcxproj.filters b/src/vswhere.lib/vswhere.lib.vcxproj.filters index 23a1f89..f7a5820 100644 --- a/src/vswhere.lib/vswhere.lib.vcxproj.filters +++ b/src/vswhere.lib/vswhere.lib.vcxproj.filters @@ -152,6 +152,9 @@ Source Files + + Source Files + diff --git a/src/vswhere/Program.cpp b/src/vswhere/Program.cpp index f9a4f30..6ec7eab 100644 --- a/src/vswhere/Program.cpp +++ b/src/vswhere/Program.cpp @@ -17,6 +17,7 @@ int wmain(_In_ int argc, _In_ LPCWSTR argv[]) Console console(args); Module queryModule; + console.Initialize(); try { CoInitializer init; @@ -78,7 +79,7 @@ int wmain(_In_ int argc, _In_ LPCWSTR argv[]) } // Create the formatter and optionally show the logo. - auto formatter = Formatter::Create(args.get_Format()); + auto formatter = Formatter::Create(args.get_Format(), args, console); if (formatter->ShowLogo()) { WriteLogo(args, console, queryModule); @@ -86,11 +87,11 @@ int wmain(_In_ int argc, _In_ LPCWSTR argv[]) if (args.get_Find().length()) { - formatter->WriteFiles(args, console, instances); + formatter->WriteFiles(instances); } else { - formatter->Write(args, console, instances); + formatter->Write(instances); } return ERROR_SUCCESS; diff --git a/test/vswhere.test/CommandArgsTests.cpp b/test/vswhere.test/CommandArgsTests.cpp index ccd329b..49352ec 100644 --- a/test/vswhere.test/CommandArgsTests.cpp +++ b/test/vswhere.test/CommandArgsTests.cpp @@ -28,6 +28,7 @@ TEST_CLASS(CommandArgsTests) Assert::IsFalse(args.get_Help()); Assert::IsFalse(args.get_UTF8()); Assert::IsTrue(args.get_Logo()); + Assert::IsTrue(args.get_Color()); auto& products = args.get_Products(); Assert::AreEqual(3, products.size()); @@ -164,6 +165,15 @@ TEST_CLASS(CommandArgsTests) Assert::ExpectException([&] { args.Parse(L"vswhere.exe -format invalid"); }); } + TEST_METHOD(Parse_NoColor) + { + CommandArgs args; + Assert::IsTrue(args.get_Color()); + + args.Parse(L"vswhere.exe -nocolor"); + Assert::IsFalse(args.get_Color()); + } + TEST_METHOD(Parse_NoLogo) { CommandArgs args; diff --git a/test/vswhere.test/JsonFormatterTests.cpp b/test/vswhere.test/JsonFormatterTests.cpp index 29462c0..dd56394 100644 --- a/test/vswhere.test/JsonFormatterTests.cpp +++ b/test/vswhere.test/JsonFormatterTests.cpp @@ -23,8 +23,8 @@ TEST_CLASS(JsonFormatterTests) { L"Description", L"This description contains \"quotes\"." }, }; - JsonFormatter sut; - sut.Write(args, console, &instance); + JsonFormatter sut(args, console); + sut.Write(&instance); auto expected = L"[\n" @@ -62,8 +62,8 @@ TEST_CLASS(JsonFormatterTests) &instance2, }; - JsonFormatter sut; - sut.Write(args, console, instances); + JsonFormatter sut(args, console); + sut.Write(instances); auto expected = L"[\n" @@ -87,8 +87,8 @@ TEST_CLASS(JsonFormatterTests) TestConsole console(args); vector instances; - JsonFormatter sut; - sut.Write(args, console, instances); + JsonFormatter sut(args, console); + sut.Write(instances); auto expected = L"[]\n"; @@ -118,8 +118,8 @@ TEST_CLASS(JsonFormatterTests) instance.AssignAdditionalProperties(properties); - JsonFormatter sut; - sut.Write(args, console, &instance); + JsonFormatter sut(args, console); + sut.Write(&instance); auto expected = L"[\n" @@ -161,8 +161,8 @@ TEST_CLASS(JsonFormatterTests) instance.AssignAdditionalProperties(properties); - JsonFormatter sut; - sut.Write(args, console, &instance); + JsonFormatter sut(args, console); + sut.Write(&instance); auto expected = L"[\n" @@ -202,8 +202,8 @@ TEST_CLASS(JsonFormatterTests) instance.AssignAdditionalProperties(properties); - JsonFormatter sut; - sut.Write(args, console, &instance); + JsonFormatter sut(args, console); + sut.Write(&instance); auto expected = L"[\n" @@ -241,8 +241,8 @@ TEST_CLASS(JsonFormatterTests) instance.AssignAdditionalProperties(properties); - JsonFormatter sut; - sut.Write(args, console, &instance); + JsonFormatter sut(args, console); + sut.Write(&instance); auto expected = L"[\n" @@ -292,8 +292,8 @@ TEST_CLASS(JsonFormatterTests) &instance2, }; - JsonFormatter sut; - sut.Write(args, console, instances); + JsonFormatter sut(args, console); + sut.Write(instances); auto expected = L"[\n" @@ -351,8 +351,8 @@ TEST_CLASS(JsonFormatterTests) instance.AssignAdditionalProperties(properties); - JsonFormatter sut; - sut.Write(args, console, &instance); + JsonFormatter sut(args, console); + sut.Write(&instance); auto expected = L"[]\n"; @@ -393,8 +393,8 @@ TEST_CLASS(JsonFormatterTests) instance.AssignAdditionalProperties(properties); - JsonFormatter sut; - sut.Write(args, console, &instance); + JsonFormatter sut(args, console); + sut.Write(&instance); auto expected = L"[\n" @@ -433,8 +433,8 @@ TEST_CLASS(JsonFormatterTests) { L"IsLaunchable", L"false" }, }; - JsonFormatter sut; - sut.Write(args, console, &instance); + JsonFormatter sut(args, console); + sut.Write(&instance); auto expected = L"[\n" @@ -465,8 +465,8 @@ TEST_CLASS(JsonFormatterTests) { L"IsLaunchable", L"true" }, }; - JsonFormatter sut; - sut.Write(args, console, &instance); + JsonFormatter sut(args, console); + sut.Write(&instance); auto expected = L"[\n" @@ -496,8 +496,8 @@ TEST_CLASS(JsonFormatterTests) L"c", }; - JsonFormatter sut; - sut.Write(console, L"values", L"value", values); + JsonFormatter sut(args, console); + sut.Write(L"values", L"value", values); auto expected = L"[\n" @@ -606,8 +606,8 @@ TEST_CLASS(JsonFormatterTests) TestConsole console(args); - JsonFormatter sut; - sut.Write(args, console, instances); + JsonFormatter sut(args, console); + sut.Write(instances); auto expected = L"[\n" @@ -649,4 +649,35 @@ TEST_CLASS(JsonFormatterTests) Assert::AreEqual(expected, console); } + + TEST_METHOD(Write_Instance_With_Color) + { + CommandArgs args; + TestConsole console(args); + console.SetColorSupported(true); + + TestInstance instance = + { + { L"InstanceId", L"a1b2c3" }, + { L"InstallDate", L"2017-02-23T01:22:35Z"}, + { L"State", L"4294967295" }, + { L"IsComplete", L"true"}, + }; + + JsonFormatter sut(args, console); + sut.Write(&instance); + + auto expected = + L"[\n" + L" {\n" + L" \033[38;2;156;220;254m\"instanceId\"\033[0m: \033[38;2;206;145;120m\"a1b2c3\"\033[0m,\n" + L" \033[38;2;156;220;254m\"installDate\"\033[0m: \033[38;2;206;145;120m\"2017-02-23T01:22:35Z\"\033[0m,\n" + L" \033[38;2;156;220;254m\"state\"\033[0m: \033[38;2;181;206;168m4294967295\033[0m,\n" + L" \033[38;2;156;220;254m\"isComplete\"\033[0m: \033[38;2;86;156;214mtrue\033[0m,\n" + L" \033[38;2;156;220;254m\"isRebootRequired\"\033[0m: \033[38;2;86;156;214mfalse\033[0m\n" + L" }\n" + L"]\n"; + + Assert::AreEqual(expected, console); + } }; diff --git a/test/vswhere.test/TestConsole.h b/test/vswhere.test/TestConsole.h index 90d2ff3..0c131da 100644 --- a/test/vswhere.test/TestConsole.h +++ b/test/vswhere.test/TestConsole.h @@ -10,28 +10,42 @@ class TestConsole : { public: TestConsole(_In_ const CommandArgs& args) : - Console(args) + Console(args), + m_color(false) { } TestConsole(_In_ const TestConsole& obj) : Console(obj), - m_output(obj.m_output) + m_output(obj.m_output), + m_color(obj.m_color) { } + void Initialize() noexcept override + { + m_fInitialized = true; + } + operator const wchar_t*() const { return m_output.c_str(); } -protected: - void Initialize() noexcept override + void SetColorSupported(bool enable) noexcept { + m_color = enable; } + bool IsColorSupported() const override + { + return m_color; + } + +protected: void Write(_In_ LPCWSTR wzFormat, va_list args) override; private: std::wstring m_output; + bool m_color; }; diff --git a/test/vswhere.test/TextFormatterTests.cpp b/test/vswhere.test/TextFormatterTests.cpp index b1ecc09..f5a53a3 100644 --- a/test/vswhere.test/TextFormatterTests.cpp +++ b/test/vswhere.test/TextFormatterTests.cpp @@ -22,8 +22,8 @@ TEST_CLASS(TextFormatterTests) { L"Description", L"This description contains \"quotes\"." }, }; - TextFormatter sut; - sut.Write(args, console, &instance); + TextFormatter sut(args, console); + sut.Write(&instance); auto expected = L"instanceId: a1b2c3\n" @@ -56,8 +56,8 @@ TEST_CLASS(TextFormatterTests) &instance2, }; - TextFormatter sut; - sut.Write(args, console, instances); + TextFormatter sut(args, console); + sut.Write(instances); auto expected = L"instanceId: a1b2c3\n" @@ -90,8 +90,8 @@ TEST_CLASS(TextFormatterTests) TestInstance instance(&product, {}, properties); - TextFormatter sut; - sut.Write(args, console, &instance); + TextFormatter sut(args, console); + sut.Write(&instance); auto expected = L"instanceId: a1b2c3\n" @@ -114,8 +114,8 @@ TEST_CLASS(TextFormatterTests) { L"ProductPath", L"Common7\\IDE\\devenv.exe" }, }; - TextFormatter sut; - sut.Write(args, console, &instance); + TextFormatter sut(args, console); + sut.Write(&instance); auto expected = L"instanceId: a1b2c3\n" @@ -146,8 +146,8 @@ TEST_CLASS(TextFormatterTests) instance.AssignAdditionalProperties(properties); - TextFormatter sut; - sut.Write(args, console, &instance); + TextFormatter sut(args, console); + sut.Write(&instance); auto expected = L"instanceId: a1b2c3\n" @@ -182,8 +182,8 @@ TEST_CLASS(TextFormatterTests) instance.AssignAdditionalProperties(properties); - TextFormatter sut; - sut.Write(args, console, &instance); + TextFormatter sut(args, console); + sut.Write(&instance); auto expected = L"properties_campaignId: abcd1234\n" @@ -217,8 +217,8 @@ TEST_CLASS(TextFormatterTests) instance.AssignAdditionalProperties(properties); - TextFormatter sut; - sut.Write(args, console, &instance); + TextFormatter sut(args, console); + sut.Write(&instance); auto expected = L"properties_nickname: test\n"; @@ -250,8 +250,8 @@ TEST_CLASS(TextFormatterTests) instance.AssignAdditionalProperties(properties); - TextFormatter sut; - sut.Write(args, console, &instance); + TextFormatter sut(args, console); + sut.Write(&instance); auto expected = L"properties_nickname: test\n"; @@ -295,8 +295,8 @@ TEST_CLASS(TextFormatterTests) &instance2, }; - TextFormatter sut; - sut.Write(args, console, instances); + TextFormatter sut(args, console); + sut.Write(instances); auto expected = L"instanceId: a1b2c3\n" @@ -346,8 +346,8 @@ TEST_CLASS(TextFormatterTests) instance.AssignAdditionalProperties(properties); - TextFormatter sut; - sut.Write(args, console, &instance); + TextFormatter sut(args, console); + sut.Write(&instance); auto expected = L""; @@ -386,8 +386,8 @@ TEST_CLASS(TextFormatterTests) instance.AssignAdditionalProperties(properties); - TextFormatter sut; - sut.Write(args, console, &instance); + TextFormatter sut(args, console); + sut.Write(&instance); auto expected = L"instanceId: a1b2c3\n" @@ -417,8 +417,8 @@ TEST_CLASS(TextFormatterTests) { L"IsLaunchable", L"false" }, }; - TextFormatter sut; - sut.Write(args, console, &instance); + TextFormatter sut(args, console); + sut.Write(&instance); auto expected = L"instanceId: a1b2c3\n" @@ -445,8 +445,8 @@ TEST_CLASS(TextFormatterTests) { L"IsLaunchable", L"true" }, }; - TextFormatter sut; - sut.Write(args, console, &instance); + TextFormatter sut(args, console); + sut.Write(&instance); auto expected = L"instanceId: a1b2c3\n" @@ -472,8 +472,8 @@ TEST_CLASS(TextFormatterTests) L"c", }; - TextFormatter sut; - sut.Write(console, L"values", L"value", values); + TextFormatter sut(args, console); + sut.Write(L"values", L"value", values); auto expected = L"value: a\n" @@ -557,8 +557,8 @@ TEST_CLASS(TextFormatterTests) TestConsole console(args); - TextFormatter sut; - sut.Write(args, console, instances); + TextFormatter sut(args, console); + sut.Write(instances); auto expected = L"instanceId: a1b2c3\n" @@ -571,4 +571,29 @@ TEST_CLASS(TextFormatterTests) Assert::AreEqual(expected, console); } + + TEST_METHOD(Write_Instance_With_Color) + { + CommandArgs args; + TestConsole console(args); + console.SetColorSupported(true); + + TestInstance instance = + { + { L"InstanceId", L"a1b2c3" }, + { L"State", L"4294967295" }, + { L"IsComplete", L"true"}, + }; + + TextFormatter sut(args, console); + sut.Write(&instance); + + auto expected = + L"\033[38;2;156;220;254minstanceId\033[0m: \033[38;2;206;145;120ma1b2c3\033[0m\n" + L"\033[38;2;156;220;254mstate\033[0m: \033[38;2;206;145;120m4294967295\033[0m\n" + L"\033[38;2;156;220;254misComplete\033[0m: \033[38;2;206;145;120m1\033[0m\n" + L"\033[38;2;156;220;254misRebootRequired\033[0m: \033[38;2;206;145;120m0\033[0m\n"; + + Assert::AreEqual(expected, console); + } }; diff --git a/test/vswhere.test/ValueFormatterTests.cpp b/test/vswhere.test/ValueFormatterTests.cpp index 33875ab..50a36cd 100644 --- a/test/vswhere.test/ValueFormatterTests.cpp +++ b/test/vswhere.test/ValueFormatterTests.cpp @@ -24,8 +24,8 @@ TEST_CLASS(ValueFormatterTests) { L"Description", L"This description contains \"quotes\"." }, }; - ValueFormatter sut; - sut.Write(args, console, &instance); + ValueFormatter sut(args, console); + sut.Write(&instance); auto expected = L"a1b2c3\n" L"test\n" @@ -59,8 +59,8 @@ TEST_CLASS(ValueFormatterTests) &instance2, }; - ValueFormatter sut; - sut.Write(args, console, instances); + ValueFormatter sut(args, console); + sut.Write(instances); auto expected = L"C:\\ShouldNotExist\n"; @@ -92,8 +92,8 @@ TEST_CLASS(ValueFormatterTests) &instance2, }; - ValueFormatter sut; - sut.Write(args, console, instances); + ValueFormatter sut(args, console); + sut.Write(instances); auto expected = L"a1b2c3\n" @@ -123,8 +123,8 @@ TEST_CLASS(ValueFormatterTests) instance.AssignAdditionalProperties(properties); - ValueFormatter sut; - sut.Write(args, console, &instance); + ValueFormatter sut(args, console); + sut.Write(&instance); auto expected = L"a1b2c3\n" @@ -159,8 +159,8 @@ TEST_CLASS(ValueFormatterTests) instance.AssignAdditionalProperties(properties); - ValueFormatter sut; - sut.Write(args, console, &instance); + ValueFormatter sut(args, console); + sut.Write(&instance); auto expected = L"abcd1234\n" @@ -193,8 +193,8 @@ TEST_CLASS(ValueFormatterTests) instance.AssignAdditionalProperties(properties); - ValueFormatter sut; - sut.Write(args, console, &instance); + ValueFormatter sut(args, console); + sut.Write(&instance); auto expected = L"test\n"; @@ -226,8 +226,8 @@ TEST_CLASS(ValueFormatterTests) instance.AssignAdditionalProperties(properties); - ValueFormatter sut; - sut.Write(args, console, &instance); + ValueFormatter sut(args, console); + sut.Write(&instance); auto expected = L"test\n"; @@ -271,8 +271,8 @@ TEST_CLASS(ValueFormatterTests) &instance2, }; - ValueFormatter sut; - sut.Write(args, console, instances); + ValueFormatter sut(args, console); + sut.Write(instances); auto expected = L"a1b2c3\n" @@ -320,8 +320,8 @@ TEST_CLASS(ValueFormatterTests) instance.AssignAdditionalProperties(properties); - ValueFormatter sut; - sut.Write(args, console, &instance); + ValueFormatter sut(args, console); + sut.Write(&instance); auto expected = L""; @@ -360,8 +360,8 @@ TEST_CLASS(ValueFormatterTests) instance.AssignAdditionalProperties(properties); - ValueFormatter sut; - sut.Write(args, console, &instance); + ValueFormatter sut(args, console); + sut.Write(&instance); auto expected = L"a1b2c3\n" @@ -391,8 +391,8 @@ TEST_CLASS(ValueFormatterTests) { L"IsLaunchable", L"false" }, }; - ValueFormatter sut; - sut.Write(args, console, &instance); + ValueFormatter sut(args, console); + sut.Write(&instance); auto expected = L"a1b2c3\n" @@ -419,8 +419,8 @@ TEST_CLASS(ValueFormatterTests) { L"IsLaunchable", L"true" }, }; - ValueFormatter sut; - sut.Write(args, console, &instance); + ValueFormatter sut(args, console); + sut.Write(&instance); auto expected = L"a1b2c3\n" @@ -446,8 +446,8 @@ TEST_CLASS(ValueFormatterTests) L"c", }; - ValueFormatter sut; - sut.Write(console, L"values", L"value", values); + ValueFormatter sut(args, console); + sut.Write(L"values", L"value", values); auto expected = L"a\n" @@ -531,8 +531,8 @@ TEST_CLASS(ValueFormatterTests) TestConsole console(args); - ValueFormatter sut; - sut.Write(args, console, instances); + ValueFormatter sut(args, console); + sut.Write(instances); auto expected = L"a1b2c3\n" @@ -544,4 +544,29 @@ TEST_CLASS(ValueFormatterTests) Assert::AreEqual(expected, console); } + + TEST_METHOD(Write_Instance_With_Color) + { + CommandArgs args; + TestConsole console(args); + console.SetColorSupported(true); + + TestInstance instance = + { + { L"InstanceId", L"a1b2c3" }, + { L"State", L"4294967295" }, + { L"IsComplete", L"true"}, + }; + + ValueFormatter sut(args, console); + sut.Write(&instance); + + auto expected = + L"a1b2c3\n" + L"4294967295\n" + L"1\n" + L"0\n"; + + Assert::AreEqual(expected, console); + } }; diff --git a/test/vswhere.test/XmlFormatterTests.cpp b/test/vswhere.test/XmlFormatterTests.cpp index 9b68f0c..cb6c258 100644 --- a/test/vswhere.test/XmlFormatterTests.cpp +++ b/test/vswhere.test/XmlFormatterTests.cpp @@ -23,8 +23,8 @@ TEST_CLASS(XmlFormatterTests) { L"Description", L"This description contains \"quotes\"." }, }; - XmlFormatter sut; - sut.Write(args, console, &instance); + XmlFormatter sut(args, console); + sut.Write(&instance); auto expected = L"\n" @@ -63,8 +63,8 @@ TEST_CLASS(XmlFormatterTests) &instance2, }; - XmlFormatter sut; - sut.Write(args, console, instances); + XmlFormatter sut(args, console); + sut.Write(instances); auto expected = L"\n" @@ -89,8 +89,8 @@ TEST_CLASS(XmlFormatterTests) TestConsole console(args); vector instances; - XmlFormatter sut; - sut.Write(args, console, instances); + XmlFormatter sut(args, console); + sut.Write(instances); auto expected = L"\n" @@ -122,8 +122,8 @@ TEST_CLASS(XmlFormatterTests) instance.AssignAdditionalProperties(properties); - XmlFormatter sut; - sut.Write(args, console, &instance); + XmlFormatter sut(args, console); + sut.Write(&instance); auto expected = L"\n" @@ -166,8 +166,8 @@ TEST_CLASS(XmlFormatterTests) instance.AssignAdditionalProperties(properties); - XmlFormatter sut; - sut.Write(args, console, &instance); + XmlFormatter sut(args, console); + sut.Write(&instance); auto expected = L"\n" @@ -208,8 +208,8 @@ TEST_CLASS(XmlFormatterTests) instance.AssignAdditionalProperties(properties); - XmlFormatter sut; - sut.Write(args, console, &instance); + XmlFormatter sut(args, console); + sut.Write(&instance); auto expected = L"\n" @@ -248,8 +248,8 @@ TEST_CLASS(XmlFormatterTests) instance.AssignAdditionalProperties(properties); - XmlFormatter sut; - sut.Write(args, console, &instance); + XmlFormatter sut(args, console); + sut.Write(&instance); auto expected = L"\n" @@ -300,8 +300,8 @@ TEST_CLASS(XmlFormatterTests) &instance2, }; - XmlFormatter sut; - sut.Write(args, console, instances); + XmlFormatter sut(args, console); + sut.Write(instances); auto expected = L"\n" @@ -360,8 +360,8 @@ TEST_CLASS(XmlFormatterTests) instance.AssignAdditionalProperties(properties); - XmlFormatter sut; - sut.Write(args, console, &instance); + XmlFormatter sut(args, console); + sut.Write(&instance); auto expected = L"\n" @@ -404,8 +404,8 @@ TEST_CLASS(XmlFormatterTests) instance.AssignAdditionalProperties(properties); - XmlFormatter sut; - sut.Write(args, console, &instance); + XmlFormatter sut(args, console); + sut.Write(&instance); auto expected = L"\n" @@ -445,8 +445,8 @@ TEST_CLASS(XmlFormatterTests) { L"IsLaunchable", L"false" }, }; - XmlFormatter sut; - sut.Write(args, console, &instance); + XmlFormatter sut(args, console); + sut.Write(&instance); auto expected = L"\n" @@ -478,8 +478,8 @@ TEST_CLASS(XmlFormatterTests) { L"IsLaunchable", L"true" }, }; - XmlFormatter sut; - sut.Write(args, console, &instance); + XmlFormatter sut(args, console); + sut.Write(&instance); auto expected = L"\n" @@ -510,8 +510,8 @@ TEST_CLASS(XmlFormatterTests) L"c", }; - XmlFormatter sut; - sut.Write(console, L"values", L"value", values); + XmlFormatter sut(args, console); + sut.Write(L"values", L"value", values); auto expected = L"\n" @@ -598,8 +598,8 @@ TEST_CLASS(XmlFormatterTests) TestConsole console(args); - XmlFormatter sut; - sut.Write(args, console, instances); + XmlFormatter sut(args, console); + sut.Write(instances); auto expected = L"\n" @@ -642,4 +642,36 @@ TEST_CLASS(XmlFormatterTests) Assert::AreEqual(expected, console); } + + TEST_METHOD(Write_Instance_With_Color) + { + CommandArgs args; + TestConsole console(args); + console.SetColorSupported(true); + + TestInstance instance = + { + { L"InstanceId", L"a1b2c3" }, + { L"InstallDate", L"2017-02-23T01:22:35Z"}, + { L"State", L"4294967295" }, + { L"IsComplete", L"true"}, + }; + + XmlFormatter sut(args, console); + sut.Write(&instance); + + auto expected = + L"\033[38;2;86;156;214m\033[0m\n" + L"\033[38;2;86;156;214m\033[0m\n" + L" \033[38;2;86;156;214m\033[0m\n" + L" \033[38;2;86;156;214m\033[0ma1b2c3\033[38;2;86;156;214m\033[0m\n" + L" \033[38;2;86;156;214m\033[0m2017-02-23T01:22:35Z\033[38;2;86;156;214m\033[0m\n" + L" \033[38;2;86;156;214m\033[0m4294967295\033[38;2;86;156;214m\033[0m\n" + L" \033[38;2;86;156;214m\033[0m1\033[38;2;86;156;214m\033[0m\n" + L" \033[38;2;86;156;214m\033[0m0\033[38;2;86;156;214m\033[0m\n" + L" \033[38;2;86;156;214m\033[0m\n" + L"\033[38;2;86;156;214m\033[0m\n"; + + Assert::AreEqual(expected, console); + } }; diff --git a/version.json b/version.json index 9e435c4..c837a4e 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/AArnott/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", - "version": "2.8", + "version": "2.9", "publicReleaseRefSpec": [ "^refs/heads/master$", "^refs/tags/v\\d+\\.\\d+"