diff --git a/CMakeLists.txt b/CMakeLists.txt index ac559eca..cfa364d7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,6 +12,7 @@ find_package(Core REQUIRED) find_package(Blaze REQUIRED) find_package(JSONBinPack REQUIRED) find_package(Hydra REQUIRED) +find_package(TermColor REQUIRED) add_subdirectory(src) if(JSONSCHEMA_DEVELOPMENT) diff --git a/DEPENDENCIES b/DEPENDENCIES index aa680198..b50d31b8 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -3,3 +3,4 @@ core https://github.com/sourcemeta/core 32f08ad1e4d3e39097eda3fdd44e58ad0b5d59ec hydra https://github.com/sourcemeta/hydra a67b879df800e834ed8a2d056f98398f7211d870 jsonbinpack https://github.com/sourcemeta/jsonbinpack d0f111b04fc4d252e278bafd66c382a9db3d3057 blaze https://github.com/sourcemeta/blaze ee117240f8399831001cb1c764d8b08503fc9112 +termcolor https://github.com/ikalnytskyi/termcolor v2.1.0 diff --git a/cmake/FindTermColor.cmake b/cmake/FindTermColor.cmake new file mode 100644 index 00000000..a422124a --- /dev/null +++ b/cmake/FindTermColor.cmake @@ -0,0 +1,13 @@ +if(TARGET termcolor::termcolor) + return() +endif() + +add_library(termcolor INTERFACE) +add_library(termcolor::termcolor ALIAS termcolor) + +target_include_directories(termcolor INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/../vendor/termcolor/include) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(TermColor + REQUIRED_VARS CMAKE_CURRENT_LIST_DIR) \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a9b9af6a..026b38e9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -25,6 +25,7 @@ target_link_libraries(jsonschema_cli PRIVATE sourcemeta::jsonbinpack::compiler) target_link_libraries(jsonschema_cli PRIVATE sourcemeta::jsonbinpack::runtime) target_link_libraries(jsonschema_cli PRIVATE sourcemeta::blaze::compiler) target_link_libraries(jsonschema_cli PRIVATE sourcemeta::blaze::evaluator) +target_link_libraries(jsonschema_cli PRIVATE termcolor::termcolor) configure_file(configure.h.in configure.h @ONLY) target_include_directories(jsonschema_cli PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") diff --git a/src/command_validate.cc b/src/command_validate.cc index cd095442..81cdbd90 100644 --- a/src/command_validate.cc +++ b/src/command_validate.cc @@ -105,8 +105,7 @@ auto sourcemeta::jsonschema::cli::validate( log_verbose(options) << "ok: " << std::filesystem::weakly_canonical(instance_path).string() - << " (entry #" << index << ")" - << "\n matches " + << " (entry #" << index << ")" << "\n matches " << std::filesystem::weakly_canonical(schema_path).string() << "\n"; } else { diff --git a/src/main.cc b/src/main.cc index ade9700f..81c57656 100644 --- a/src/main.cc +++ b/src/main.cc @@ -1,5 +1,8 @@ #include +#include "command.h" +#include "configure.h" +#include "utils.h" #include // std::min #include // EXIT_FAILURE, EXIT_SUCCESS #include // std::filesystem @@ -8,14 +11,19 @@ #include // std::string #include // std::string_view #include // std::vector - -#include "command.h" -#include "configure.h" - +#ifdef _WIN32 +#include +#define isatty _isatty +#define fileno _fileno +#else +#include +#endif +#include constexpr std::string_view USAGE_DETAILS{R"EOF( Global Options: --verbose, -v Enable verbose output + --no-color, -n Disable colored output --resolve, -r Import the given JSON Schema (or directory of schemas) into the resolution context @@ -75,6 +83,11 @@ For more documentation, visit https://github.com/sourcemeta/jsonschema auto jsonschema_main(const std::string &program, const std::string &command, const std::span &arguments) -> int { + const std::set flags{"no-color", "n", "verbose", "v"}; + const auto options = + sourcemeta::jsonschema::cli::parse_options(arguments, flags); + const bool use_colors = !options.contains("no-color") && + !options.contains("n") && isatty(fileno(stdout)); if (command == "fmt") { return sourcemeta::jsonschema::cli::fmt(arguments); } else if (command == "frame") { @@ -94,11 +107,18 @@ auto jsonschema_main(const std::string &program, const std::string &command, } else if (command == "decode") { return sourcemeta::jsonschema::cli::decode(arguments); } else { - std::cout << "JSON Schema CLI - v" - << sourcemeta::jsonschema::cli::PROJECT_VERSION << "\n"; - std::cout << "Usage: " << std::filesystem::path{program}.filename().string() - << " [arguments...]\n"; - std::cout << USAGE_DETAILS; + std::cout << "JSON Schema CLI - "; + if (use_colors) { + std::cout << termcolor::yellow << "v" + << sourcemeta::jsonschema::cli::PROJECT_VERSION + << termcolor::reset; + } else { + std::cout << "v" << sourcemeta::jsonschema::cli::PROJECT_VERSION; + } + std::cout << "\nUsage: " + << std::filesystem::path{program}.filename().string() + << " [arguments...]\n" + << USAGE_DETAILS; return EXIT_SUCCESS; } } diff --git a/src/utils.cc b/src/utils.cc index 689bc305..256ac781 100644 --- a/src/utils.cc +++ b/src/utils.cc @@ -142,6 +142,8 @@ auto parse_options(const std::span &arguments, std::set effective_flags{flags}; effective_flags.insert("v"); effective_flags.insert("verbose"); + effective_flags.insert("n"); + effective_flags.insert("no-color"); options.insert({"", {}}); std::optional current_option; diff --git a/vendor/termcolor/.mailmap b/vendor/termcolor/.mailmap new file mode 100644 index 00000000..ace13db6 --- /dev/null +++ b/vendor/termcolor/.mailmap @@ -0,0 +1 @@ +Ihor Kalnytskyi diff --git a/vendor/termcolor/CMakeLists.txt b/vendor/termcolor/CMakeLists.txt new file mode 100644 index 00000000..e0bfcd6b --- /dev/null +++ b/vendor/termcolor/CMakeLists.txt @@ -0,0 +1,58 @@ +cmake_minimum_required(VERSION 3.0) +project(termcolor) + +# +# target +# + +add_library(${PROJECT_NAME} INTERFACE) +add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) + +target_include_directories(${PROJECT_NAME} INTERFACE + $ + $) +target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_11) + +# +# tests +# + +option(TERMCOLOR_TESTS "Build termcolor tests." OFF) + +if(TERMCOLOR_TESTS) + add_executable(test_${PROJECT_NAME} test/test.cpp test/subtest.cpp) + target_link_libraries( + test_${PROJECT_NAME} ${PROJECT_NAME}::${PROJECT_NAME}) +endif() + +# +# install +# + +include(CMakePackageConfigHelpers) + +# Installation paths +include(GNUInstallDirs) + +configure_package_config_file( + cmake/config.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/generated/${PROJECT_NAME}-config.cmake + INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}) + +install( + FILES ${CMAKE_CURRENT_BINARY_DIR}/generated/${PROJECT_NAME}-config.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}) + +install( + DIRECTORY include/ + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) + +install( + TARGETS ${PROJECT_NAME} + EXPORT ${PROJECT_NAME}-targets + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) + +install( + EXPORT ${PROJECT_NAME}-targets + NAMESPACE ${PROJECT_NAME}:: + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}) diff --git a/vendor/termcolor/LICENSE b/vendor/termcolor/LICENSE new file mode 100644 index 00000000..e2a9f532 --- /dev/null +++ b/vendor/termcolor/LICENSE @@ -0,0 +1,31 @@ +Copyright (c) 2013, Ihor Kalnytskyi. +All rights reserved. + +Redistribution and use in source and binary forms of the software as well +as documentation, with or without modification, are permitted provided +that the following conditions are met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + +* The names of the contributors may not be used to endorse or + promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT +NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. diff --git a/vendor/termcolor/README.rst b/vendor/termcolor/README.rst new file mode 100644 index 00000000..2c621755 --- /dev/null +++ b/vendor/termcolor/README.rst @@ -0,0 +1,236 @@ +Termcolor +========= + +.. image:: docs/_static/example.png + :alt: termcolor in action + :align: left + +.. -*- inclusion-marker-for-sphinx-docs -*- + +Termcolor_ is a header-only C++ library for printing colored messages to the +terminal. Written just for fun with a help of `the Force`_. Termcolor uses +`ANSI color formatting`_, so you can use it on every system that is used such +terminals (most \*nix systems, including Linux and Mac OS). + +.. note:: + + On Windows, `Windows API`_ is used instead of escape codes but some + limitations are applied (not everything is supported). That's why it's + recommended to enter `virtual terminal processing`_ mode and set + ``TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES`` macro to trick termcolor to use + ANSI color codes. + + .. _virtual terminal processing: https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences + +It's licensed under the BSD (3-clause) License. That basically means: do +whatever you want as long as copyright sticks around. + +.. _Termcolor: https://github.com/ikalnytskyi/termcolor +.. _the Force: https://starwars.wikia.com/wiki/The_Force +.. _ANSI color formatting: https://en.wikipedia.org/wiki/ANSI_escape_code#Colors +.. _Windows API: https://docs.microsoft.com/en-us/windows/console/setconsoletextattribute + + +Installation +------------ + +* Add ``termcolor.hpp`` (grab it from ``include/termcolor/termcolor.hpp``) to + the project and use stream manipulators from the ``termcolor`` namespace. + +* You can also use vcpkg_ to install the library: + + .. code:: sh + + $ vcpkg install termcolor + + .. _vcpkg: https://github.com/microsoft/vcpkg + +* Or if you are on macOS, you can use Homebrew_ for that purpose: + + .. code:: sh + + $ brew install termcolor + + .. _Homebrew: https://brew.sh/ + +* For up-to-date information about existing packages, refer to the the following + picture: + + .. image:: https://repology.org/badge/vertical-allrepos/termcolor.svg + :target: https://repology.org/project/termcolor/versions + :alt: Packaging Status + + +How to use? +----------- + +It's very easy to use. The idea is built upon C++ stream manipulators. +Typical «Hello World» application looks like this: + +.. code:: c++ + + #include + #include + + int main(int /*argc*/, char** /*argv*/) + { + std::cout << termcolor::red << "Hello, "; // 16 colors + std::cout << termcolor::color<100> << "Colorful "; // 256 colors + std::cout << termcolor::color<211, 54, 130> << "World!"; // true colors + std::cout << std::endl; + return 0; + } + +The application above prints a string using different colors. There is one +caveat though. You must not forget to reset colors, otherwise they will be +applied to other prints as well. + +.. code:: c++ + + std::cout << termcolor::red << "Hello, Colorful World!" << std::endl; + std::cout << "I'm RED too!" << std::endl; + +Correct version of the code above should look like this: + +.. code:: c++ + + std::cout << termcolor::red << "Hello, Colorful World!" << termcolor::reset << std::endl; + std::cout << termcolor::reset << "Here I'm!" << std::endl; + +By default, Termcolor ignores any colors for non-tty streams (e.g. +``std::stringstream``), so the following snippet + +.. code:: c++ + + std::stringstream ss; + ss << termcolor::red << "unicorn"; + std::cout << ss.str(); + +will print «unicorn» using default color, not red. In order to change this +behaviour one can use ``termcolor::colorize`` manipulator that enforce colors +no matter what. + + +What manipulators are supported? +-------------------------------- + +The manipulators are divided into four groups: + +* *foreground*, which changes text color; +* *background*, which changes text background color; +* *attributes*, which changes some text style (bold, underline, etc); +* *control*, which changes termcolor's behaviour. + +Also, there are color manipulators for `16 colors`_, `256 colors`_ and +`true colors`_ palettes. + +.. note:: + + While ``termcolor`` supports true color, it's required for the terminal + emulator you use to run your software to support true color too. So please + ensure it's supported before filing an issue. + +.. _16 colors: https://en.wikipedia.org/wiki/Color_depth#4-bit_color +.. _256 colors: https://en.wikipedia.org/wiki/Color_depth#8-bit_color +.. _true colors: https://en.wikipedia.org/wiki/Color_depth#True_color_(24-bit) + + +Foreground manipulators +....................... + +16 colors +````````` + +#. ``termcolor::grey`` +#. ``termcolor::red`` +#. ``termcolor::green`` +#. ``termcolor::yellow`` +#. ``termcolor::blue`` +#. ``termcolor::magenta`` +#. ``termcolor::cyan`` +#. ``termcolor::white`` +#. ``termcolor::bright_grey`` +#. ``termcolor::bright_red`` +#. ``termcolor::bright_green`` +#. ``termcolor::bright_yellow`` +#. ``termcolor::bright_blue`` +#. ``termcolor::bright_magenta`` +#. ``termcolor::bright_cyan`` +#. ``termcolor::bright_white`` + +256 colors +`````````` + +#. ``termcolor::color<256_COLOR_CODE>`` + +true colors +``````````` + +#. ``termcolor::color`` + + +Background manipulators +....................... + +16 colors +````````` + +#. ``termcolor::on_grey`` +#. ``termcolor::on_red`` +#. ``termcolor::on_green`` +#. ``termcolor::on_yellow`` +#. ``termcolor::on_blue`` +#. ``termcolor::on_magenta`` +#. ``termcolor::on_cyan`` +#. ``termcolor::on_white`` +#. ``termcolor::on_bright_grey`` +#. ``termcolor::on_bright_red`` +#. ``termcolor::on_bright_green`` +#. ``termcolor::on_bright_yellow`` +#. ``termcolor::on_bright_blue`` +#. ``termcolor::on_bright_magenta`` +#. ``termcolor::on_bright_cyan`` +#. ``termcolor::on_bright_white`` + +256 colors +`````````` + +#. ``termcolor::on_color<256_COLOR_CODE>`` + + +true colors +``````````` + +#. ``termcolor::on_color`` + + +Attribute manipulators +...................... + +(Windows API does not support these manipulators except for ``underline``) + +#. ``termcolor::bold`` +#. ``termcolor::dark`` +#. ``termcolor::italic`` +#. ``termcolor::underline`` +#. ``termcolor::blink`` +#. ``termcolor::reverse`` +#. ``termcolor::concealed`` +#. ``termcolor::crossed`` + +Control manipulators +.................... + +(Windows API does not support these manipulators) + +#. ``termcolor::colorize`` +#. ``termcolor::nocolorize`` + + +Caveats +------- + +#. On Windows, due to internal usage of ````, global namespace could + be polluted with `min`/`max` macros. If such effect is desireable, please + consider using ``#define NOMINMAX`` before ``#include ``. + diff --git a/vendor/termcolor/cmake/config.cmake.in b/vendor/termcolor/cmake/config.cmake.in new file mode 100644 index 00000000..a3086e85 --- /dev/null +++ b/vendor/termcolor/cmake/config.cmake.in @@ -0,0 +1,4 @@ +@PACKAGE_INIT@ + +include("${CMAKE_CURRENT_LIST_DIR}/@CMAKE_PROJECT_NAME@-targets.cmake") +check_required_components("@CMAKE_PROJECT_NAME@") diff --git a/vendor/termcolor/docs/_static/example.png b/vendor/termcolor/docs/_static/example.png new file mode 100644 index 00000000..9643c696 Binary files /dev/null and b/vendor/termcolor/docs/_static/example.png differ diff --git a/vendor/termcolor/docs/conf.py b/vendor/termcolor/docs/conf.py new file mode 100644 index 00000000..2b3167f2 --- /dev/null +++ b/vendor/termcolor/docs/conf.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +""" +termcolor's documentation settings +""" +from __future__ import unicode_literals + +import os + + +# project information +project = 'termcolor' +copyright = '2013, Ihor Kalnytskyi' +version = '0.1' +release = '0.1' + +# sphinx settings +extensions = [] +templates_path = ['_templates'] +source_suffix = '.rst' +master_doc = 'index' +exclude_patterns = ['_build'] +pygments_style = 'sphinx' +highlight_language = 'c++' + +# html output settings +html_theme = 'default' +html_static_path = ['_static'] + +# Unfortunately, Sphinx doesn't support code highlighting for standard +# reStructuredText `code` directive. So let's register 'code' directive +# as alias for Sphinx's own implementation. +# +# https://github.com/sphinx-doc/sphinx/issues/2155 +from docutils.parsers.rst import directives +from sphinx.directives.code import CodeBlock +directives.register_directive('code', CodeBlock) diff --git a/vendor/termcolor/docs/index.rst b/vendor/termcolor/docs/index.rst new file mode 100644 index 00000000..7664f61c --- /dev/null +++ b/vendor/termcolor/docs/index.rst @@ -0,0 +1,11 @@ +:orphan: + +Welcome to Termcolor C++ library +================================ + +.. image:: _static/example.png + :alt: termcolor in action + :align: center + +.. include:: ../README.rst + :start-after: -*- inclusion-marker-for-sphinx-docs -*- diff --git a/vendor/termcolor/examples/cmake-external/CMakeLists.txt b/vendor/termcolor/examples/cmake-external/CMakeLists.txt new file mode 100644 index 00000000..525b2a85 --- /dev/null +++ b/vendor/termcolor/examples/cmake-external/CMakeLists.txt @@ -0,0 +1,23 @@ +cmake_minimum_required(VERSION 3.0) +project(example) + +include(ExternalProject) + +ExternalProject_Add(termcolor_project + GIT_REPOSITORY git://github.com/ikalnytskyi/termcolor.git + GIT_TAG origin/master + + # Termcolor is a header-only library which means we need to + # neither configure nor build nor install it. Thus, noop + # the hooks. + CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "") +ExternalProject_Get_Property(termcolor_project SOURCE_DIR) + +set(CMAKE_CXX_STANDARD 11) + +include_directories(${SOURCE_DIR}/include) +add_library(termcolor INTERFACE IMPORTED) +add_dependencies(termcolor termcolor_project) + +add_executable(${CMAKE_PROJECT_NAME} example.cpp) +target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE termcolor) diff --git a/vendor/termcolor/examples/cmake-external/example.cpp b/vendor/termcolor/examples/cmake-external/example.cpp new file mode 100644 index 00000000..65ee2a3f --- /dev/null +++ b/vendor/termcolor/examples/cmake-external/example.cpp @@ -0,0 +1,10 @@ +#include +#include + +int main(int /* argc */, char** /* argv */) { + std::cout + << termcolor::yellow << "Warm welcome to " + << termcolor::blue << termcolor::underline << "TERMCOLOR" + << termcolor::reset << std::endl; + return 0; +} diff --git a/vendor/termcolor/examples/cmake-fetch/CMakeLists.txt b/vendor/termcolor/examples/cmake-fetch/CMakeLists.txt new file mode 100644 index 00000000..545184f7 --- /dev/null +++ b/vendor/termcolor/examples/cmake-fetch/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 3.11) +project(example) + +include(FetchContent) + +FetchContent_Declare(termcolor + GIT_REPOSITORY git://github.com/ikalnytskyi/termcolor.git + GIT_TAG origin/master) +FetchContent_GetProperties(termcolor) + +if(NOT termcolor_POPULATED) + FetchContent_Populate(termcolor) + add_subdirectory(${termcolor_SOURCE_DIR} ${termcolor_BINARY_DIR} EXCLUDE_FROM_ALL) +endif() + +add_executable(${CMAKE_PROJECT_NAME} example.cpp) +target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE termcolor) diff --git a/vendor/termcolor/examples/cmake-fetch/example.cpp b/vendor/termcolor/examples/cmake-fetch/example.cpp new file mode 100644 index 00000000..65ee2a3f --- /dev/null +++ b/vendor/termcolor/examples/cmake-fetch/example.cpp @@ -0,0 +1,10 @@ +#include +#include + +int main(int /* argc */, char** /* argv */) { + std::cout + << termcolor::yellow << "Warm welcome to " + << termcolor::blue << termcolor::underline << "TERMCOLOR" + << termcolor::reset << std::endl; + return 0; +} diff --git a/vendor/termcolor/examples/cmake-package/CMakeLists.txt b/vendor/termcolor/examples/cmake-package/CMakeLists.txt new file mode 100644 index 00000000..3f78a57e --- /dev/null +++ b/vendor/termcolor/examples/cmake-package/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.0) +project(example) + +find_package(termcolor REQUIRED) + +add_executable(${CMAKE_PROJECT_NAME} example.cpp) +target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE termcolor::termcolor) diff --git a/vendor/termcolor/examples/cmake-package/example.cpp b/vendor/termcolor/examples/cmake-package/example.cpp new file mode 100644 index 00000000..65ee2a3f --- /dev/null +++ b/vendor/termcolor/examples/cmake-package/example.cpp @@ -0,0 +1,10 @@ +#include +#include + +int main(int /* argc */, char** /* argv */) { + std::cout + << termcolor::yellow << "Warm welcome to " + << termcolor::blue << termcolor::underline << "TERMCOLOR" + << termcolor::reset << std::endl; + return 0; +} diff --git a/vendor/termcolor/examples/cmake-submodule/CMakeLists.txt b/vendor/termcolor/examples/cmake-submodule/CMakeLists.txt new file mode 100644 index 00000000..5673372b --- /dev/null +++ b/vendor/termcolor/examples/cmake-submodule/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.0) +project(example) + +add_subdirectory(../.. ${CMAKE_CURRENT_BINARY_DIR}/termcolor EXCLUDE_FROM_ALL) + +add_executable(${CMAKE_PROJECT_NAME} example.cpp) +target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE termcolor::termcolor) diff --git a/vendor/termcolor/examples/cmake-submodule/example.cpp b/vendor/termcolor/examples/cmake-submodule/example.cpp new file mode 100644 index 00000000..65ee2a3f --- /dev/null +++ b/vendor/termcolor/examples/cmake-submodule/example.cpp @@ -0,0 +1,10 @@ +#include +#include + +int main(int /* argc */, char** /* argv */) { + std::cout + << termcolor::yellow << "Warm welcome to " + << termcolor::blue << termcolor::underline << "TERMCOLOR" + << termcolor::reset << std::endl; + return 0; +} diff --git a/vendor/termcolor/include/termcolor/termcolor.hpp b/vendor/termcolor/include/termcolor/termcolor.hpp new file mode 100644 index 00000000..d94e991b --- /dev/null +++ b/vendor/termcolor/include/termcolor/termcolor.hpp @@ -0,0 +1,939 @@ +//! +//! termcolor +//! ~~~~~~~~~ +//! +//! termcolor is a header-only c++ library for printing colored messages +//! to the terminal. Written just for fun with a help of the Force. +//! +//! :copyright: (c) 2013 by Ihor Kalnytskyi +//! :license: BSD, see LICENSE for details +//! + +#ifndef TERMCOLOR_HPP_ +#define TERMCOLOR_HPP_ + +#include + +// Detect target's platform and set some macros in order to wrap platform +// specific code this library depends on. +#if defined(_WIN32) || defined(_WIN64) +# define TERMCOLOR_TARGET_WINDOWS +#elif defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)) +# define TERMCOLOR_TARGET_POSIX +#endif + +// If implementation has not been explicitly set, try to choose one based on +// target platform. +#if !defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) && !defined(TERMCOLOR_USE_WINDOWS_API) && !defined(TERMCOLOR_USE_NOOP) +# if defined(TERMCOLOR_TARGET_POSIX) +# define TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES +# define TERMCOLOR_AUTODETECTED_IMPLEMENTATION +# elif defined(TERMCOLOR_TARGET_WINDOWS) +# define TERMCOLOR_USE_WINDOWS_API +# define TERMCOLOR_AUTODETECTED_IMPLEMENTATION +# endif +#endif + +// These headers provide isatty()/fileno() functions, which are used for +// testing whether a standard stream refers to the terminal. +#if defined(TERMCOLOR_TARGET_POSIX) +# include +#elif defined(TERMCOLOR_TARGET_WINDOWS) +# include +# include +#endif + + +namespace termcolor +{ + // Forward declaration of the `_internal` namespace. + // All comments are below. + namespace _internal + { + inline int colorize_index(); + inline FILE* get_standard_stream(const std::ostream& stream); + inline FILE* get_standard_stream(const std::wostream& stream); + template + bool is_colorized(std::basic_ostream& stream); + template + bool is_atty(const std::basic_ostream& stream); + + #if defined(TERMCOLOR_TARGET_WINDOWS) + template + void win_change_attributes(std::basic_ostream& stream, int foreground, int background = -1); + #endif + } + + template + std::basic_ostream& colorize(std::basic_ostream& stream) + { + stream.iword(_internal::colorize_index()) = 1L; + return stream; + } + + template + std::basic_ostream& nocolorize(std::basic_ostream& stream) + { + stream.iword(_internal::colorize_index()) = 0L; + return stream; + } + + template + std::basic_ostream& reset(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[00m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, -1, -1); + #endif + } + return stream; + } + + template + std::basic_ostream& bold(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[1m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + #endif + } + return stream; + } + + template + std::basic_ostream& dark(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[2m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + #endif + } + return stream; + } + + template + std::basic_ostream& italic(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[3m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + #endif + } + return stream; + } + + template + std::basic_ostream& underline(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[4m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, -1, COMMON_LVB_UNDERSCORE); + #endif + } + return stream; + } + + template + std::basic_ostream& blink(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[5m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + #endif + } + return stream; + } + + template + std::basic_ostream& reverse(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[7m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + #endif + } + return stream; + } + + template + std::basic_ostream& concealed(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[8m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + #endif + } + return stream; + } + + template + std::basic_ostream& crossed(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[9m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + #endif + } + return stream; + } + + template + std::basic_ostream& color(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[38;5;" << +code << "m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + #endif + } + return stream; + } + + template + std::basic_ostream& on_color(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[48;5;" << +code << "m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + #endif + } + return stream; + } + + template + std::basic_ostream& color(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[38;2;" << +r << ";" << +g << ";" << +b << "m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + #endif + } + return stream; + } + + template + std::basic_ostream& on_color(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[48;2;" << +r << ";" << +g << ";" << +b << "m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + #endif + } + return stream; + } + + template + std::basic_ostream& grey(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[30m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, + 0 // grey (black) + ); + #endif + } + return stream; + } + + template + std::basic_ostream& red(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[31m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, + FOREGROUND_RED + ); + #endif + } + return stream; + } + + template + std::basic_ostream& green(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[32m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, + FOREGROUND_GREEN + ); + #endif + } + return stream; + } + + template + std::basic_ostream& yellow(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[33m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, + FOREGROUND_GREEN | FOREGROUND_RED + ); + #endif + } + return stream; + } + + template + std::basic_ostream& blue(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[34m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, + FOREGROUND_BLUE + ); + #endif + } + return stream; + } + + template + std::basic_ostream& magenta(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[35m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, + FOREGROUND_BLUE | FOREGROUND_RED + ); + #endif + } + return stream; + } + + template + std::basic_ostream& cyan(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[36m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, + FOREGROUND_BLUE | FOREGROUND_GREEN + ); + #endif + } + return stream; + } + + template + std::basic_ostream& white(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[37m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, + FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED + ); + #endif + } + return stream; + } + + + template + std::basic_ostream& bright_grey(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[90m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, + 0 | FOREGROUND_INTENSITY // grey (black) + ); + #endif + } + return stream; + } + + template + std::basic_ostream& bright_red(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[91m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, + FOREGROUND_RED | FOREGROUND_INTENSITY + ); + #endif + } + return stream; + } + + template + std::basic_ostream& bright_green(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[92m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, + FOREGROUND_GREEN | FOREGROUND_INTENSITY + ); + #endif + } + return stream; + } + + template + std::basic_ostream& bright_yellow(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[93m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, + FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY + ); + #endif + } + return stream; + } + + template + std::basic_ostream& bright_blue(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[94m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, + FOREGROUND_BLUE | FOREGROUND_INTENSITY + ); + #endif + } + return stream; + } + + template + std::basic_ostream& bright_magenta(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[95m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, + FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY + ); + #endif + } + return stream; + } + + template + std::basic_ostream& bright_cyan(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[96m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, + FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY + ); + #endif + } + return stream; + } + + template + std::basic_ostream& bright_white(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[97m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, + FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY + ); + #endif + } + return stream; + } + + + template + std::basic_ostream& on_grey(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[40m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, -1, + 0 // grey (black) + ); + #endif + } + return stream; + } + + template + std::basic_ostream& on_red(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[41m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, -1, + BACKGROUND_RED + ); + #endif + } + return stream; + } + + template + std::basic_ostream& on_green(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[42m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, -1, + BACKGROUND_GREEN + ); + #endif + } + return stream; + } + + template + std::basic_ostream& on_yellow(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[43m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, -1, + BACKGROUND_GREEN | BACKGROUND_RED + ); + #endif + } + return stream; + } + + template + std::basic_ostream& on_blue(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[44m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, -1, + BACKGROUND_BLUE + ); + #endif + } + return stream; + } + + template + std::basic_ostream& on_magenta(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[45m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, -1, + BACKGROUND_BLUE | BACKGROUND_RED + ); + #endif + } + return stream; + } + + template + std::basic_ostream& on_cyan(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[46m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, -1, + BACKGROUND_GREEN | BACKGROUND_BLUE + ); + #endif + } + return stream; + } + + template + std::basic_ostream& on_white(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[47m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, -1, + BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED + ); + #endif + } + + return stream; + } + + + template + std::basic_ostream& on_bright_grey(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[100m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, -1, + 0 | BACKGROUND_INTENSITY // grey (black) + ); + #endif + } + return stream; + } + + template + std::basic_ostream& on_bright_red(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[101m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, -1, + BACKGROUND_RED | BACKGROUND_INTENSITY + ); + #endif + } + return stream; + } + + template + std::basic_ostream& on_bright_green(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[102m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, -1, + BACKGROUND_GREEN | BACKGROUND_INTENSITY + ); + #endif + } + return stream; + } + + template + std::basic_ostream& on_bright_yellow(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[103m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, -1, + BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY + ); + #endif + } + return stream; + } + + template + std::basic_ostream& on_bright_blue(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[104m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, -1, + BACKGROUND_BLUE | BACKGROUND_INTENSITY + ); + #endif + } + return stream; + } + + template + std::basic_ostream& on_bright_magenta(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[105m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, -1, + BACKGROUND_BLUE | BACKGROUND_RED | BACKGROUND_INTENSITY + ); + #endif + } + return stream; + } + + template + std::basic_ostream& on_bright_cyan(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[106m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, -1, + BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY + ); + #endif + } + return stream; + } + + template + std::basic_ostream& on_bright_white(std::basic_ostream& stream) + { + if (_internal::is_colorized(stream)) + { + #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) + stream << "\033[107m"; + #elif defined(TERMCOLOR_USE_WINDOWS_API) + _internal::win_change_attributes(stream, -1, + BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED | BACKGROUND_INTENSITY + ); + #endif + } + + return stream; + } + + + + //! Since C++ hasn't a way to hide something in the header from + //! the outer access, I have to introduce this namespace which + //! is used for internal purpose and should't be access from + //! the user code. + namespace _internal + { + // An index to be used to access a private storage of I/O streams. See + // colorize / nocolorize I/O manipulators for details. Due to the fact + // that static variables ain't shared between translation units, inline + // function with local static variable is used to do the trick and share + // the variable value between translation units. + inline int colorize_index() + { + static int colorize_index = std::ios_base::xalloc(); + return colorize_index; + } + + //! Since C++ hasn't a true way to extract stream handler + //! from the a given `std::ostream` object, I have to write + //! this kind of hack. + inline + FILE* get_standard_stream(const std::ostream& stream) + { + if (&stream == &std::cout) + return stdout; + else if (&stream == &std::cerr || &stream == &std::clog) + return stderr; + + return nullptr; + } + + //! Since C++ hasn't a true way to extract stream handler + //! from the a given `std::wostream` object, I have to write + //! this kind of hack. + inline + FILE* get_standard_stream(const std::wostream& stream) + { + if (&stream == &std::wcout) + return stdout; + else if (&stream == &std::wcerr || &stream == &std::wclog) + return stderr; + + return nullptr; + } + + // Say whether a given stream should be colorized or not. It's always + // true for ATTY streams and may be true for streams marked with + // colorize flag. + template + bool is_colorized(std::basic_ostream& stream) + { + return is_atty(stream) || static_cast(stream.iword(colorize_index())); + } + + //! Test whether a given `std::ostream` object refers to + //! a terminal. + template + bool is_atty(const std::basic_ostream& stream) + { + FILE* std_stream = get_standard_stream(stream); + + // Unfortunately, fileno() ends with segmentation fault + // if invalid file descriptor is passed. So we need to + // handle this case gracefully and assume it's not a tty + // if standard stream is not detected, and 0 is returned. + if (!std_stream) + return false; + + #if defined(TERMCOLOR_TARGET_POSIX) + return ::isatty(fileno(std_stream)); + #elif defined(TERMCOLOR_TARGET_WINDOWS) + return ::_isatty(_fileno(std_stream)); + #else + return false; + #endif + } + + #if defined(TERMCOLOR_TARGET_WINDOWS) + + //! same hack as used in get_standard_stream function, but for Windows with `std::ostream` + inline HANDLE get_terminal_handle(std::ostream& stream) + { + if (&stream == &std::cout) + return GetStdHandle(STD_OUTPUT_HANDLE); + else if (&stream == &std::cerr || &stream == &std::clog) + return GetStdHandle(STD_ERROR_HANDLE); + return nullptr; + } + + //! same hack as used in get_standard_stream function, but for Windows with `std::wostream` + inline HANDLE get_terminal_handle(std::wostream& stream) + { + if (&stream == &std::wcout) + return GetStdHandle(STD_OUTPUT_HANDLE); + else if (&stream == &std::wcerr || &stream == &std::wclog) + return GetStdHandle(STD_ERROR_HANDLE); + return nullptr; + } + + //! Change Windows Terminal colors attribute. If some + //! parameter is `-1` then attribute won't changed. + template + void win_change_attributes(std::basic_ostream& stream, int foreground, int background) + { + // yeah, i know.. it's ugly, it's windows. + static WORD defaultAttributes = 0; + + // Windows doesn't have ANSI escape sequences and so we use special + // API to change Terminal output color. That means we can't + // manipulate colors by means of "std::stringstream" and hence + // should do nothing in this case. + if (!_internal::is_atty(stream)) + return; + + // get terminal handle + HANDLE hTerminal = INVALID_HANDLE_VALUE; + hTerminal = get_terminal_handle(stream); + + // save default terminal attributes if it unsaved + if (!defaultAttributes) + { + CONSOLE_SCREEN_BUFFER_INFO info; + if (!GetConsoleScreenBufferInfo(hTerminal, &info)) + return; + defaultAttributes = info.wAttributes; + } + + // restore all default settings + if (foreground == -1 && background == -1) + { + SetConsoleTextAttribute(hTerminal, defaultAttributes); + return; + } + + // get current settings + CONSOLE_SCREEN_BUFFER_INFO info; + if (!GetConsoleScreenBufferInfo(hTerminal, &info)) + return; + + if (foreground != -1) + { + info.wAttributes &= ~(info.wAttributes & 0x0F); + info.wAttributes |= static_cast(foreground); + } + + if (background != -1) + { + info.wAttributes &= ~(info.wAttributes & 0xF0); + info.wAttributes |= static_cast(background); + } + + SetConsoleTextAttribute(hTerminal, info.wAttributes); + } + #endif // TERMCOLOR_TARGET_WINDOWS + + } // namespace _internal + +} // namespace termcolor + + +#undef TERMCOLOR_TARGET_POSIX +#undef TERMCOLOR_TARGET_WINDOWS + +#if defined(TERMCOLOR_AUTODETECTED_IMPLEMENTATION) +# undef TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES +# undef TERMCOLOR_USE_WINDOWS_API +#endif + +#endif // TERMCOLOR_HPP_ diff --git a/vendor/termcolor/test/subtest.cpp b/vendor/termcolor/test/subtest.cpp new file mode 100644 index 00000000..0dc721d6 --- /dev/null +++ b/vendor/termcolor/test/subtest.cpp @@ -0,0 +1,8 @@ +#include +#include "termcolor/termcolor.hpp" + + +void subtest_from_another_tranlation_unit() +{ + std::cout << termcolor::blue << "subtest" << termcolor::reset << std::endl; +} diff --git a/vendor/termcolor/test/subtest.hpp b/vendor/termcolor/test/subtest.hpp new file mode 100644 index 00000000..a85f55bf --- /dev/null +++ b/vendor/termcolor/test/subtest.hpp @@ -0,0 +1,6 @@ +#ifndef SUBTEST_HPP_ +#define SUBTEST_HPP_ + +void subtest_from_another_tranlation_unit(); + +#endif // SUBTEST_HPP_ diff --git a/vendor/termcolor/test/test.cpp b/vendor/termcolor/test/test.cpp new file mode 100644 index 00000000..47e50b2b --- /dev/null +++ b/vendor/termcolor/test/test.cpp @@ -0,0 +1,155 @@ +//! +//! termcolor's test +//! ~~~~~~~~~~~~~~~~ +//! +//! A simple file which used all the termcolor featured. +//! It isn't a usual automated test, it's an unsual visual test! :D +//! +//! :copyright: (c) 2013 by Ihor Kalnytskyi +//! :license: BSD, see LICENSE for details +//! + +#if defined(_WIN32) || defined(_WIN64) +# define NO_ANSI_ESCAPE_SEQUENCES +#endif + +// Cygwin's C++ libraries seem to be stricter than other unix platforms. +// Strict standard conformance must be disabled by passing -U__STRICT_ANSI__ +// (or equivalent option) to the compiler, or by #undef __STRICT_ANSI__ +// before including this header file, , or before any other header +// that includes in the inclusion chain whithin the compilation +// unit that includes "termcolor.hpp". Or by enabling compiler extensions, +// such as issuing -std=gnu11++ GNU compiler option. +// +// This is required in order to `fileno()` is seen whithin "termcolor.hpp" +// scope. Note that other unix-like platforms could enforce strict standard +// conformance in the future and will require a similar workaround. +#if defined(__CYGWIN__) +# undef __STRICT_ANSI__ +# include +# include +# define __STRICT_ANSI__ +#else +# include +# include +#endif +#include "termcolor/termcolor.hpp" +#include "subtest.hpp" + +using namespace termcolor; + + +int main(int /*argc*/, char** /*argv*/) +{ + // test truecolors + std::cout << color<181, 137, 0> << "#b58900" << reset << std::endl; + std::cout << on_color<211, 54, 130> << "#d33682" << reset << std::endl; + std::cout << std::endl; + + // test 256 colors + std::cout << color<123> << "No. 123" << reset << std::endl; + std::cout << on_color<234> << "No. 234" << reset << std::endl; + std::cout << std::endl; + + // test foreground colors + std::cout << grey << "grey message" << reset << std::endl; + std::cout << red << "red message" << reset << std::endl; + std::cout << green << "green message" << reset << std::endl; + std::cout << yellow << "yellow message" << reset << std::endl; + std::cout << blue << "blue message" << reset << std::endl; + std::cout << magenta << "magenta message" << reset << std::endl; + std::cout << cyan << "cyan message" << reset << std::endl; + std::cout << white << "white message" << reset << std::endl; + std::cout << "default message" << std::endl; + std::cout << std::endl; + + // test bright foreground colors + std::cout << bright_grey << "bright grey message" << reset << std::endl; + std::cout << bright_red << "bright red message" << reset << std::endl; + std::cout << bright_green << "bright green message" << reset << std::endl; + std::cout << bright_yellow << "bright yellow message" << reset << std::endl; + std::cout << bright_blue << "bright blue message" << reset << std::endl; + std::cout << bright_magenta << "bright magenta message" << reset << std::endl; + std::cout << bright_cyan << "bright cyan message" << reset << std::endl; + std::cout << bright_white << "bright white message" << reset << std::endl; + std::cout << "default message" << std::endl; + std::cout << std::endl; + + + // test background colors + std::cout << on_grey << "message on grey" << reset << std::endl; + std::cout << on_red << "message on red" << reset << std::endl; + std::cout << on_green << "message on green" << reset << std::endl; + std::cout << on_yellow << "message on yellow" << reset << std::endl; + std::cout << on_blue << "message on blue" << reset << std::endl; + std::cout << on_magenta << "message on magenta" << reset << std::endl; + std::cout << on_cyan << "message on cyan" << reset << std::endl; + std::cout << on_white << "message on white" << reset << std::endl; + std::cout << "default message" << std::endl; + std::cout << std::endl; + + // test bright background colors + std::cout << on_bright_grey << "message on bright grey" << reset << std::endl; + std::cout << on_bright_red << "message on bright red" << reset << std::endl; + std::cout << on_bright_green << "message on bright green" << reset << std::endl; + std::cout << on_bright_yellow << "message on bright yellow" << reset << std::endl; + std::cout << on_bright_blue << "message on bright blue" << reset << std::endl; + std::cout << on_bright_magenta << "message on bright magenta" << reset << std::endl; + std::cout << on_bright_cyan << "message on bright cyan" << reset << std::endl; + std::cout << on_bright_white << "message on bright white" << reset << std::endl; + std::cout << "default message" << std::endl; + std::cout << std::endl; + + // test foreground and backgrounds colors + std::cout << red << on_white << "red on white" << reset << std::endl; + std::cout << blue << on_yellow << "blue on yellow" << reset << std::endl; + std::cout << std::endl; + + // test bright foreground or bright background colors + std::cout << bright_red << on_white << "bright red on white" << reset << std::endl; + std::cout << blue << on_bright_yellow << "blue on bright yellow" << reset << std::endl; + std::cout << std::endl; + + // test bright foreground and bright background colors + std::cout << bright_red << on_bright_white << "bright red on bright white" << reset << std::endl; + std::cout << bright_blue << on_bright_yellow << "bright blue on bright yellow" << reset << std::endl; + std::cout << std::endl; + + // test unsual attributes + std::cout << bold << red << "bold red message" << reset << std::endl; + std::cout << dark << blue << "dark blue message" << reset << std::endl; + std::cout << italic << "italic message" << reset << std::endl; + std::cout << underline << "underlined message" << reset << std::endl; + std::cout << blink << "blinked message" << reset << std::endl; + std::cout << reverse << "reversed message" << reset << std::endl; + std::cout << concealed << "concealed message" << reset << std::endl; + std::cout << crossed << "crossed message" << reset << std::endl; + std::cout << "default message" << std::endl; + std::cout << std::endl; + + // test clog/cerr streams + std::clog << "formatted " << yellow << "std::clog" << reset << " message" << std::endl; + std::cerr << "formatted " << red << "std::cerr" << reset << " message" << std::endl; + std::cout << std::endl; + + // test another translation unit + subtest_from_another_tranlation_unit(); + + // test ansi escape characters are skipped for streams + std::stringstream s1; + s1 << red << "term" << blue << on_yellow << "color"; + + if (s1.str() != "termcolor") + return 1; + +#ifndef NO_ANSI_ESCAPE_SEQUENCES + // test ansi escape characters are preserved for streams if asked + std::stringstream s2; + s2 << colorize << red << "term" << nocolorize << blue << "color"; + + if (s2.str() != "\033[31m" "termcolor") + return 2; +#endif // NO_ANSI_ESCAPE_SEQUENCES + + return 0; +}