| /* |
| * Created by Phil on 25/2/2012. |
| * Copyright 2012 Two Blue Cubes Ltd. All rights reserved. |
| * |
| * Distributed under the Boost Software License, Version 1.0. (See accompanying |
| * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
| */ |
| |
| |
| #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 ) {} |
| |
| static IColourImpl* instance() { |
| static NoColourImpl s_instance; |
| return &s_instance; |
| } |
| }; |
| |
| } // anon namespace |
| } // namespace Catch |
| |
| #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 ); |
| } |
| |
| virtual 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(); |
| } |
| |
| } // end anon namespace |
| } // end namespace Catch |
| |
| #elif defined( CATCH_CONFIG_COLOUR_ANSI ) ////////////////////////////////////// |
| |
| #include <unistd.h> |
| |
| namespace Catch { |
| namespace { |
| |
| // use POSIX/ ANSI console terminal codes |
| // Thanks to Adam Strzelecki for original contribution |
| // (http://github.com/nanoant) |
| // https://github.com/philsquared/Catch/pull/131 |
| class PosixColourImpl : public IColourImpl { |
| public: |
| virtual 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 ) { |
| Catch::cout() << '\033' << _escapeCode; |
| } |
| }; |
| |
| bool useColourOnPlatform() { |
| return |
| #ifdef CATCH_PLATFORM_MAC |
| !isDebuggerActive() && |
| #endif |
| isatty(STDOUT_FILENO); |
| } |
| 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(); |
| } |
| |
| } // end anon namespace |
| } // end namespace Catch |
| |
| #else // not Windows or ANSI /////////////////////////////////////////////// |
| |
| namespace Catch { |
| |
| static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); } |
| |
| } // end namespace Catch |
| |
| #endif // Windows/ ANSI/ None |
| |
| namespace Catch { |
| |
| Colour::Colour( Code _colourCode ) { use( _colourCode ); } |
| Colour::Colour( Colour&& rhs ) noexcept { |
| m_moved = rhs.m_moved; |
| rhs.m_moved = true; |
| } |
| Colour& Colour::operator=( Colour&& rhs ) noexcept { |
| m_moved = rhs.m_moved; |
| rhs.m_moved = true; |
| return *this; |
| } |
| |
| Colour::~Colour(){ if( !m_moved ) use( None ); } |
| |
| void Colour::use( Code _colourCode ) { |
| static IColourImpl* impl = platformColourInstance(); |
| impl->use( _colourCode ); |
| } |
| |
| std::ostream& operator << ( std::ostream& os, Colour const& ) { |
| return os; |
| } |
| |
| } // end namespace Catch |
| |
| #if defined(__clang__) |
| # pragma clang diagnostic pop |
| #endif |
| |