Skip to content

Commit

Permalink
Colorize vswhere output (#244)
Browse files Browse the repository at this point in the history
* 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.
  • Loading branch information
heaths authored Sep 15, 2021
1 parent f18bd64 commit 4df5b7a
Show file tree
Hide file tree
Showing 30 changed files with 646 additions and 361 deletions.
4 changes: 4 additions & 0 deletions src/vswhere.lib/CommandArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,10 @@ void CommandArgs::Parse(_In_ vector<CommandParser::Token> 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;
Expand Down
8 changes: 8 additions & 0 deletions src/vswhere.lib/CommandArgs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
43 changes: 40 additions & 3 deletions src/vswhere.lib/Console.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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;
}
30 changes: 25 additions & 5 deletions src/vswhere.lib/Console.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Loading

0 comments on commit 4df5b7a

Please sign in to comment.