| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| |
|
| | #if defined(__clang__) |
| | # pragma clang diagnostic push |
| | # pragma clang diagnostic ignored "-Wexit-time-destructors" |
| | #endif |
| |
|
| |
|
| | #include "catch_console_colour.h" |
| | #include "catch_enforce.h" |
| | #include "catch_errno_guard.h" |
| | #include "catch_interfaces_config.h" |
| | #include "catch_stream.h" |
| | #include "catch_context.h" |
| | #include "catch_platform.h" |
| | #include "catch_debugger.h" |
| | #include "catch_windows_h_proxy.h" |
| |
|
| | #include <sstream> |
| |
|
| | namespace Catch { |
| | namespace { |
| |
|
| | struct IColourImpl { |
| | virtual ~IColourImpl() = default; |
| | virtual void use( Colour::Code _colourCode ) = 0; |
| | }; |
| |
|
| | struct NoColourImpl : IColourImpl { |
| | void use( Colour::Code ) override {} |
| |
|
| | static IColourImpl* instance() { |
| | static NoColourImpl s_instance; |
| | return &s_instance; |
| | } |
| | }; |
| |
|
| | } |
| | } |
| |
|
| | #if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI ) |
| | # ifdef CATCH_PLATFORM_WINDOWS |
| | # define CATCH_CONFIG_COLOUR_WINDOWS |
| | # else |
| | # define CATCH_CONFIG_COLOUR_ANSI |
| | # endif |
| | #endif |
| |
|
| |
|
| | #if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) |
| |
|
| | namespace Catch { |
| | namespace { |
| |
|
| | class Win32ColourImpl : public IColourImpl { |
| | public: |
| | Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) |
| | { |
| | CONSOLE_SCREEN_BUFFER_INFO csbiInfo; |
| | GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); |
| | originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY ); |
| | originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY ); |
| | } |
| |
|
| | void use( Colour::Code _colourCode ) override { |
| | switch( _colourCode ) { |
| | case Colour::None: return setTextAttribute( originalForegroundAttributes ); |
| | case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); |
| | case Colour::Red: return setTextAttribute( FOREGROUND_RED ); |
| | case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); |
| | case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE ); |
| | case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN ); |
| | case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN ); |
| | case Colour::Grey: return setTextAttribute( 0 ); |
| |
|
| | case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY ); |
| | case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED ); |
| | case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); |
| | case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); |
| | case Colour::BrightYellow: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN ); |
| |
|
| | case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" ); |
| |
|
| | default: |
| | CATCH_ERROR( "Unknown colour requested" ); |
| | } |
| | } |
| |
|
| | private: |
| | void setTextAttribute( WORD _textAttribute ) { |
| | SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes ); |
| | } |
| | HANDLE stdoutHandle; |
| | WORD originalForegroundAttributes; |
| | WORD originalBackgroundAttributes; |
| | }; |
| |
|
| | IColourImpl* platformColourInstance() { |
| | static Win32ColourImpl s_instance; |
| |
|
| | IConfigPtr config = getCurrentContext().getConfig(); |
| | UseColour::YesOrNo colourMode = config |
| | ? config->useColour() |
| | : UseColour::Auto; |
| | if( colourMode == UseColour::Auto ) |
| | colourMode = UseColour::Yes; |
| | return colourMode == UseColour::Yes |
| | ? &s_instance |
| | : NoColourImpl::instance(); |
| | } |
| |
|
| | } |
| | } |
| |
|
| | #elif defined( CATCH_CONFIG_COLOUR_ANSI ) |
| |
|
| | #include <unistd.h> |
| |
|
| | namespace Catch { |
| | namespace { |
| |
|
| | |
| | |
| | |
| | |
| | class PosixColourImpl : public IColourImpl { |
| | public: |
| | void use( Colour::Code _colourCode ) override { |
| | switch( _colourCode ) { |
| | case Colour::None: |
| | case Colour::White: return setColour( "[0m" ); |
| | case Colour::Red: return setColour( "[0;31m" ); |
| | case Colour::Green: return setColour( "[0;32m" ); |
| | case Colour::Blue: return setColour( "[0;34m" ); |
| | case Colour::Cyan: return setColour( "[0;36m" ); |
| | case Colour::Yellow: return setColour( "[0;33m" ); |
| | case Colour::Grey: return setColour( "[1;30m" ); |
| |
|
| | case Colour::LightGrey: return setColour( "[0;37m" ); |
| | case Colour::BrightRed: return setColour( "[1;31m" ); |
| | case Colour::BrightGreen: return setColour( "[1;32m" ); |
| | case Colour::BrightWhite: return setColour( "[1;37m" ); |
| | case Colour::BrightYellow: return setColour( "[1;33m" ); |
| |
|
| | case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" ); |
| | default: CATCH_INTERNAL_ERROR( "Unknown colour requested" ); |
| | } |
| | } |
| | static IColourImpl* instance() { |
| | static PosixColourImpl s_instance; |
| | return &s_instance; |
| | } |
| |
|
| | private: |
| | void setColour( const char* _escapeCode ) { |
| | getCurrentContext().getConfig()->stream() |
| | << '\033' << _escapeCode; |
| | } |
| | }; |
| |
|
| | bool useColourOnPlatform() { |
| | return |
| | #if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE) |
| | !isDebuggerActive() && |
| | #endif |
| | #if !(defined(__DJGPP__) && defined(__STRICT_ANSI__)) |
| | isatty(STDOUT_FILENO) |
| | #else |
| | false |
| | #endif |
| | ; |
| | } |
| | IColourImpl* platformColourInstance() { |
| | ErrnoGuard guard; |
| | IConfigPtr config = getCurrentContext().getConfig(); |
| | UseColour::YesOrNo colourMode = config |
| | ? config->useColour() |
| | : UseColour::Auto; |
| | if( colourMode == UseColour::Auto ) |
| | colourMode = useColourOnPlatform() |
| | ? UseColour::Yes |
| | : UseColour::No; |
| | return colourMode == UseColour::Yes |
| | ? PosixColourImpl::instance() |
| | : NoColourImpl::instance(); |
| | } |
| |
|
| | } |
| | } |
| |
|
| | #else |
| |
|
| | namespace Catch { |
| |
|
| | static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); } |
| |
|
| | } |
| |
|
| | #endif |
| |
|
| | namespace Catch { |
| |
|
| | Colour::Colour( Code _colourCode ) { use( _colourCode ); } |
| | Colour::Colour( Colour&& other ) noexcept { |
| | m_moved = other.m_moved; |
| | other.m_moved = true; |
| | } |
| | Colour& Colour::operator=( Colour&& other ) noexcept { |
| | m_moved = other.m_moved; |
| | other.m_moved = true; |
| | return *this; |
| | } |
| |
|
| | Colour::~Colour(){ if( !m_moved ) use( None ); } |
| |
|
| | void Colour::use( Code _colourCode ) { |
| | static IColourImpl* impl = platformColourInstance(); |
| | |
| | |
| | |
| | |
| | if (impl != nullptr) { |
| | impl->use( _colourCode ); |
| | } |
| | } |
| |
|
| | std::ostream& operator << ( std::ostream& os, Colour const& ) { |
| | return os; |
| | } |
| |
|
| | } |
| |
|
| | #if defined(__clang__) |
| | # pragma clang diagnostic pop |
| | #endif |
| |
|
| |
|