mirror of
https://codeberg.org/ProgramSnail/lang.git
synced 2025-12-05 22:48:43 +00:00
new deps (termcolor, magic enum), log fixes
This commit is contained in:
parent
49edbfb60c
commit
831cfa36f3
14 changed files with 1452 additions and 24 deletions
2
.ignore
2
.ignore
|
|
@ -1 +1 @@
|
||||||
deps/
|
deps/tree-sitter-lang
|
||||||
|
|
|
||||||
2
deps/termcolor/.gitignore
vendored
Normal file
2
deps/termcolor/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
.xmake
|
||||||
|
compile_commands.json
|
||||||
31
deps/termcolor/LICENSE
vendored
Normal file
31
deps/termcolor/LICENSE
vendored
Normal file
|
|
@ -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.
|
||||||
939
deps/termcolor/termcolor.hpp
vendored
Normal file
939
deps/termcolor/termcolor.hpp
vendored
Normal file
|
|
@ -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 <iostream>
|
||||||
|
|
||||||
|
// 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 <unistd.h>
|
||||||
|
#elif defined(TERMCOLOR_TARGET_WINDOWS)
|
||||||
|
# include <io.h>
|
||||||
|
# include <windows.h>
|
||||||
|
#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 <typename CharT>
|
||||||
|
bool is_colorized(std::basic_ostream<CharT>& stream);
|
||||||
|
template <typename CharT>
|
||||||
|
bool is_atty(const std::basic_ostream<CharT>& stream);
|
||||||
|
|
||||||
|
#if defined(TERMCOLOR_TARGET_WINDOWS)
|
||||||
|
template <typename CharT>
|
||||||
|
void win_change_attributes(std::basic_ostream<CharT>& stream, int foreground, int background = -1);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& colorize(std::basic_ostream<CharT>& stream)
|
||||||
|
{
|
||||||
|
stream.iword(_internal::colorize_index()) = 1L;
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& nocolorize(std::basic_ostream<CharT>& stream)
|
||||||
|
{
|
||||||
|
stream.iword(_internal::colorize_index()) = 0L;
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& reset(std::basic_ostream<CharT>& 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 <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& bold(std::basic_ostream<CharT>& 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 <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& dark(std::basic_ostream<CharT>& 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 <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& italic(std::basic_ostream<CharT>& 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 <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& underline(std::basic_ostream<CharT>& 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 <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& blink(std::basic_ostream<CharT>& 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 <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& reverse(std::basic_ostream<CharT>& 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 <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& concealed(std::basic_ostream<CharT>& 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 <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& crossed(std::basic_ostream<CharT>& 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 <uint8_t code, typename CharT>
|
||||||
|
std::basic_ostream<CharT>& color(std::basic_ostream<CharT>& 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 <uint8_t code, typename CharT>
|
||||||
|
std::basic_ostream<CharT>& on_color(std::basic_ostream<CharT>& 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 <uint8_t r, uint8_t g, uint8_t b, typename CharT>
|
||||||
|
std::basic_ostream<CharT>& color(std::basic_ostream<CharT>& 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 <uint8_t r, uint8_t g, uint8_t b, typename CharT>
|
||||||
|
std::basic_ostream<CharT>& on_color(std::basic_ostream<CharT>& 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 <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& grey(std::basic_ostream<CharT>& 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 <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& red(std::basic_ostream<CharT>& 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 <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& green(std::basic_ostream<CharT>& 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 <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& yellow(std::basic_ostream<CharT>& 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 <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& blue(std::basic_ostream<CharT>& 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 <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& magenta(std::basic_ostream<CharT>& 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 <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& cyan(std::basic_ostream<CharT>& 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 <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& white(std::basic_ostream<CharT>& 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 <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& bright_grey(std::basic_ostream<CharT>& 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 <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& bright_red(std::basic_ostream<CharT>& 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 <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& bright_green(std::basic_ostream<CharT>& 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 <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& bright_yellow(std::basic_ostream<CharT>& 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 <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& bright_blue(std::basic_ostream<CharT>& 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 <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& bright_magenta(std::basic_ostream<CharT>& 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 <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& bright_cyan(std::basic_ostream<CharT>& 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 <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& bright_white(std::basic_ostream<CharT>& 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 <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& on_grey(std::basic_ostream<CharT>& 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 <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& on_red(std::basic_ostream<CharT>& 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 <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& on_green(std::basic_ostream<CharT>& 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 <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& on_yellow(std::basic_ostream<CharT>& 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 <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& on_blue(std::basic_ostream<CharT>& 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 <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& on_magenta(std::basic_ostream<CharT>& 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 <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& on_cyan(std::basic_ostream<CharT>& 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 <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& on_white(std::basic_ostream<CharT>& 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 <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& on_bright_grey(std::basic_ostream<CharT>& 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 <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& on_bright_red(std::basic_ostream<CharT>& 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 <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& on_bright_green(std::basic_ostream<CharT>& 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 <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& on_bright_yellow(std::basic_ostream<CharT>& 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 <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& on_bright_blue(std::basic_ostream<CharT>& 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 <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& on_bright_magenta(std::basic_ostream<CharT>& 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 <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& on_bright_cyan(std::basic_ostream<CharT>& 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 <typename CharT>
|
||||||
|
std::basic_ostream<CharT>& on_bright_white(std::basic_ostream<CharT>& 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 <typename CharT>
|
||||||
|
bool is_colorized(std::basic_ostream<CharT>& stream)
|
||||||
|
{
|
||||||
|
return is_atty(stream) || static_cast<bool>(stream.iword(colorize_index()));
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Test whether a given `std::ostream` object refers to
|
||||||
|
//! a terminal.
|
||||||
|
template <typename CharT>
|
||||||
|
bool is_atty(const std::basic_ostream<CharT>& 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 <typename CharT>
|
||||||
|
void win_change_attributes(std::basic_ostream<CharT>& 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<WORD>(foreground);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (background != -1)
|
||||||
|
{
|
||||||
|
info.wAttributes &= ~(info.wAttributes & 0xF0);
|
||||||
|
info.wAttributes |= static_cast<WORD>(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_
|
||||||
7
deps/termcolor/xmake.lua
vendored
Normal file
7
deps/termcolor/xmake.lua
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
set_languages("c++20")
|
||||||
|
|
||||||
|
target("termcolor")
|
||||||
|
set_kind("headeronly")
|
||||||
|
add_headerfiles("termcolor.hpp")
|
||||||
|
set_warnings("all", "error")
|
||||||
|
set_rundir("$(projectdir)")
|
||||||
|
|
@ -11,8 +11,8 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
SourcesManager sources_manager;
|
SourcesManager sources_manager(Log({}, {}));
|
||||||
|
|
||||||
sources_manager.add_file(filename);
|
sources_manager.AddFile(filename);
|
||||||
sources_manager.print(std::cout);
|
sources_manager.Print(std::cout);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@
|
||||||
|
|
||||||
#include "basic_printers.hpp"
|
#include "basic_printers.hpp"
|
||||||
#include "error_handling.hpp"
|
#include "error_handling.hpp"
|
||||||
#include "error_log.hpp"
|
|
||||||
#include "expression_nodes.hpp"
|
#include "expression_nodes.hpp"
|
||||||
|
#include "log.hpp"
|
||||||
#include "name_tree.hpp"
|
#include "name_tree.hpp"
|
||||||
#include "statement_builders.hpp"
|
#include "statement_builders.hpp"
|
||||||
#include "statement_nodes.hpp"
|
#include "statement_nodes.hpp"
|
||||||
|
|
@ -17,7 +17,11 @@
|
||||||
|
|
||||||
class SourcesManager {
|
class SourcesManager {
|
||||||
public:
|
public:
|
||||||
void add_file(const std::string &filename) {
|
SourcesManager(Log &&log) : log_(std::move(log)) {}
|
||||||
|
|
||||||
|
void AddFile(const std::string &filename) {
|
||||||
|
Log::Context logc(log_, utils::Log::Area::kParse);
|
||||||
|
|
||||||
std::ifstream in;
|
std::ifstream in;
|
||||||
in.open(filename);
|
in.open(filename);
|
||||||
|
|
||||||
|
|
@ -32,8 +36,8 @@ public:
|
||||||
parser::ParseTree parse_tree(source);
|
parser::ParseTree parse_tree(source);
|
||||||
|
|
||||||
if (!parse_tree.is_properly_parsed()) {
|
if (!parse_tree.is_properly_parsed()) {
|
||||||
error_handling::handle_parsing_error(
|
logc.Fatal<Log::kProc>(
|
||||||
"There are some parsing errors in file", parse_tree.get_root());
|
{{"There are some parsing errors in file"}} /*,parse_tree.get_root()*/);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto new_statements = builders::build_source_file(
|
auto new_statements = builders::build_source_file(
|
||||||
|
|
@ -47,36 +51,36 @@ public:
|
||||||
new_statements.clear();
|
new_statements.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void print(std::ostream &out) {
|
void Print(std::ostream &out) {
|
||||||
printers::Printer printer(out, 2, 80, true);
|
printers::Printer printer(out, 2, 80, true);
|
||||||
printers::print(statements_, printer);
|
printers::print(statements_, printer);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
nodes::ExpressionStorage *expressions() { return &expression_storage_; }
|
nodes::ExpressionStorage &expressions() { return expression_storage_; }
|
||||||
|
|
||||||
const nodes::ExpressionStorage *expressions() const {
|
const nodes::ExpressionStorage &expressions() const {
|
||||||
return &expression_storage_;
|
return expression_storage_;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
nodes::TypeStorage *types() { return &type_storage_; }
|
nodes::TypeStorage &types() { return type_storage_; }
|
||||||
|
|
||||||
const nodes::TypeStorage *types() const { return &type_storage_; }
|
const nodes::TypeStorage &types() const { return type_storage_; }
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
names::NameTree *names() { return &name_tree_; }
|
names::NameTree &names() { return name_tree_; }
|
||||||
|
|
||||||
const names::NameTree *names() const { return &name_tree_; }
|
const names::NameTree &names() const { return name_tree_; }
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
error_handling::ErrorLog *errors() { return &error_log_; }
|
utils::Log &log() { return log_; }
|
||||||
|
|
||||||
const error_handling::ErrorLog *errors() const { return &error_log_; }
|
const utils::Log &log() const { return log_; }
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
@ -89,9 +93,9 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
nodes::ExpressionStorage expression_storage_;
|
Log log_;
|
||||||
nodes::TypeStorage type_storage_;
|
nodes::ExpressionStorage expression_storage_ = {};
|
||||||
names::NameTree name_tree_;
|
nodes::TypeStorage type_storage_ = {};
|
||||||
error_handling::ErrorLog error_log_;
|
names::NameTree name_tree_ = {};
|
||||||
std::vector<nodes::Statement> statements_;
|
std::vector<nodes::Statement> statements_ = {};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
#include "basic_nodes.hpp"
|
#include "basic_nodes.hpp"
|
||||||
#include "basic_type_check.hpp"
|
#include "basic_type_check.hpp"
|
||||||
#include "builtin_types.hpp"
|
#include "builtin_types.hpp"
|
||||||
#include "error_log.hpp"
|
|
||||||
#include "sources_manager.hpp"
|
#include "sources_manager.hpp"
|
||||||
#include "type_nodes.hpp"
|
#include "type_nodes.hpp"
|
||||||
#include "utils.hpp"
|
#include "utils.hpp"
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
#include "basic_nodes.hpp"
|
#include "basic_nodes.hpp"
|
||||||
#include "basic_printers.hpp"
|
#include "basic_printers.hpp"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace error_handling {
|
namespace error_handling {
|
||||||
|
|
|
||||||
79
lang/utils/include/executor.hpp
Normal file
79
lang/utils/include/executor.hpp
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "log.hpp"
|
||||||
|
|
||||||
|
namespace utils {
|
||||||
|
|
||||||
|
template <typename... States> class Task;
|
||||||
|
|
||||||
|
template <typename State> class ExecutorState {
|
||||||
|
public:
|
||||||
|
struct Tag {};
|
||||||
|
|
||||||
|
ExecutorState(State &&state) : state_(std::move(state)) {}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
State &state(Tag) { return state; }
|
||||||
|
const State &state(Tag) const { return state; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
State state_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename... States> class Executor : public ExecutorState<States>... {
|
||||||
|
friend class Task<States...>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Executor(Log &&log, States &&...states)
|
||||||
|
: ExecutorState<States>(std::move(states))..., log_(std::move(log)) {}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
template <typename T, typename... Args> T New(Args... args) {
|
||||||
|
return T(*this, args...);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
Log &log() { return log_; }
|
||||||
|
const Log &log() const { return log_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Log log_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename... States> class Task {
|
||||||
|
public:
|
||||||
|
Task(Executor<States...> &executor) : executor(executor) {}
|
||||||
|
|
||||||
|
virtual ~Task() {}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
virtual void operator()() = 0;
|
||||||
|
|
||||||
|
template <typename T, typename... Args> T New(Args... args) {
|
||||||
|
return executor.template New<T>(std::move(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
template <typename T> T &state() {
|
||||||
|
return executor.state(ExecutorState<T>::Tag);
|
||||||
|
}
|
||||||
|
template <typename T> const T &state() const {
|
||||||
|
return executor.state(ExecutorState<T>::Tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
Log &log() { return executor.log_; }
|
||||||
|
const Log &log() const { return executor.log_; }
|
||||||
|
|
||||||
|
public:
|
||||||
|
Executor<States...> &executor;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace utils
|
||||||
304
lang/utils/include/log.hpp
Normal file
304
lang/utils/include/log.hpp
Normal file
|
|
@ -0,0 +1,304 @@
|
||||||
|
#include <format>
|
||||||
|
#include <functional>
|
||||||
|
#include <iostream>
|
||||||
|
#include <optional>
|
||||||
|
#include <source_location>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
// Expect
|
||||||
|
|
||||||
|
#define EXPECT_EQ(context, left, right) \
|
||||||
|
(context).Expect((left) == (right), "#left == #right");
|
||||||
|
|
||||||
|
#define EXPECT_NE(context, left, right) \
|
||||||
|
(context).Expect((left) != (right), "#left != #right");
|
||||||
|
|
||||||
|
#define EXPECT_LE(context, left, right) \
|
||||||
|
(context).Expect((left) <= (right), "#left <= #right");
|
||||||
|
|
||||||
|
#define EXPECT_GE(context, left, right) \
|
||||||
|
(context).Expect((left) >= (right), "#left >= #right");
|
||||||
|
|
||||||
|
#define EXPECT_LT(context, left, right) \
|
||||||
|
(context).Expect((left) < (right), "#left < #right");
|
||||||
|
|
||||||
|
#define EXPECT_GT(context, left, right) \
|
||||||
|
(context).Expect((left) > (right), "#left > #right");
|
||||||
|
|
||||||
|
// Require
|
||||||
|
|
||||||
|
#define REQUIRE_EQ(context, left, right) \
|
||||||
|
(context).Require((left) == (right), "#left == #right");
|
||||||
|
|
||||||
|
#define REQUIRE_NE(context, left, right) \
|
||||||
|
(context).Require((left) != (right), "#left != #right");
|
||||||
|
|
||||||
|
#define REQUIRE_LE(context, left, right) \
|
||||||
|
(context).Require((left) <= (right), "#left <= #right");
|
||||||
|
|
||||||
|
#define REQUIRE_GE(context, left, right) \
|
||||||
|
(context).Require((left) >= (right), "#left >= #right");
|
||||||
|
|
||||||
|
#define REQUIRE_LT(context, left, right) \
|
||||||
|
(context).Require((left) < (right), "#left < #right");
|
||||||
|
|
||||||
|
#define REQUIRE_GT(context, left, right) \
|
||||||
|
(context).Require((left) > (right), "#left > #right");
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
namespace utils {
|
||||||
|
|
||||||
|
std::string to_string(const std::source_location &source_location);
|
||||||
|
|
||||||
|
struct Pos {
|
||||||
|
public:
|
||||||
|
struct Point {
|
||||||
|
size_t line;
|
||||||
|
size_t position;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
Point start;
|
||||||
|
Point end;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Log {
|
||||||
|
friend class Context;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum Kind {
|
||||||
|
kSys,
|
||||||
|
kProc,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class Level : uint32_t { // NOTE: change to_string(Log::Level level) on
|
||||||
|
// change
|
||||||
|
kDebug = 1,
|
||||||
|
kInfo = 3,
|
||||||
|
kImportant = 5,
|
||||||
|
kWarning = 7,
|
||||||
|
kError = 9,
|
||||||
|
kFatal = 11,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class Area {
|
||||||
|
kDefault,
|
||||||
|
kParse,
|
||||||
|
kIntepret,
|
||||||
|
// ...
|
||||||
|
};
|
||||||
|
struct Fragment {
|
||||||
|
// Fragment(std::string fragment) : fragment(fragment), color(kNone) {}
|
||||||
|
|
||||||
|
enum Color {
|
||||||
|
kNone,
|
||||||
|
kDebug,
|
||||||
|
kInfo,
|
||||||
|
kImportant,
|
||||||
|
kWarning,
|
||||||
|
kError,
|
||||||
|
kFatal,
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string fragment;
|
||||||
|
Color color = kNone;
|
||||||
|
|
||||||
|
explicit operator std::string() {
|
||||||
|
return fragment; // TODO: +color
|
||||||
|
}
|
||||||
|
};
|
||||||
|
using Fragments = std::vector<Fragment>;
|
||||||
|
|
||||||
|
struct Message {
|
||||||
|
Fragments message;
|
||||||
|
Level level;
|
||||||
|
Area area = Area::kDefault;
|
||||||
|
std::optional<Pos> pos = {};
|
||||||
|
std::source_location source_location = std::source_location::current();
|
||||||
|
};
|
||||||
|
|
||||||
|
class Context {
|
||||||
|
public:
|
||||||
|
Context(
|
||||||
|
Log &log, Area area, Level default_level = Level::kInfo,
|
||||||
|
std::source_location source_location = std::source_location::current())
|
||||||
|
: log_(log), area_(area), default_level_(default_level),
|
||||||
|
function_(to_string(source_location)) {
|
||||||
|
log_.PushLog<kSys>({
|
||||||
|
.message = {{"Enter ", Fragment::kInfo}, {function_}},
|
||||||
|
.level = default_level_,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
~Context() {
|
||||||
|
log_.PushLog<kSys>({
|
||||||
|
.message = {{"Leave ", Fragment::kInfo}, {function_}},
|
||||||
|
.level = default_level_,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Context(const Context &log) = delete;
|
||||||
|
Context(Context &&log) = delete;
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
template <Kind K>
|
||||||
|
void LogWithLevel(Fragments message, Level level,
|
||||||
|
std::optional<Pos> pos = {},
|
||||||
|
std::source_location source_location =
|
||||||
|
std::source_location::current()) {
|
||||||
|
log_.PushLog<K>({
|
||||||
|
.message = std::move(message),
|
||||||
|
.level = level,
|
||||||
|
.area = area_,
|
||||||
|
.pos = pos,
|
||||||
|
.source_location = source_location,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
template <Kind K>
|
||||||
|
void Default(Fragments message, std::optional<Pos> pos = {},
|
||||||
|
std::source_location source_location =
|
||||||
|
std::source_location::current()) {
|
||||||
|
LogWithLevel<K>(std::move(message), default_level_, pos, source_location);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <Kind K>
|
||||||
|
void Debug(Fragments message, std::optional<Pos> pos = {},
|
||||||
|
std::source_location source_location =
|
||||||
|
std::source_location::current()) {
|
||||||
|
LogWithLevel<K>(std::move(message), Level::kDebug, pos, source_location);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <Kind K>
|
||||||
|
void Info(Fragments message, std::optional<Pos> pos = {},
|
||||||
|
std::source_location source_location =
|
||||||
|
std::source_location::current()) {
|
||||||
|
LogWithLevel<K>(std::move(message), Level::kInfo, pos, source_location);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <Kind K>
|
||||||
|
void Important(Fragments message, std::optional<Pos> pos = {},
|
||||||
|
std::source_location source_location =
|
||||||
|
std::source_location::current()) {
|
||||||
|
LogWithLevel<K>(std::move(message), Level::kImportant, pos,
|
||||||
|
source_location);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <Kind K>
|
||||||
|
void Warning(Fragments message, std::optional<Pos> pos = {},
|
||||||
|
std::source_location source_location =
|
||||||
|
std::source_location::current()) {
|
||||||
|
LogWithLevel<K>(std::move(message), Level::kWarning, pos,
|
||||||
|
source_location);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <Kind K>
|
||||||
|
void Error(Fragments message, std::optional<Pos> pos = {},
|
||||||
|
std::source_location source_location =
|
||||||
|
std::source_location::current()) {
|
||||||
|
LogWithLevel<K>(std::move(message), Level::kError, pos, source_location);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <Kind K>
|
||||||
|
void Fatal(Fragments message, std::optional<Pos> pos = {},
|
||||||
|
std::source_location source_location =
|
||||||
|
std::source_location::current()) {
|
||||||
|
auto entity = Message{
|
||||||
|
.message = std::move(message),
|
||||||
|
.level = Level::kFatal,
|
||||||
|
.area = area_,
|
||||||
|
.pos = pos,
|
||||||
|
.source_location = source_location,
|
||||||
|
};
|
||||||
|
|
||||||
|
log_.PushLog<K>(entity);
|
||||||
|
throw entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
template <Kind K>
|
||||||
|
bool Expect(bool condition, Fragments message, std::optional<Pos> pos = {},
|
||||||
|
std::source_location source_location =
|
||||||
|
std::source_location::current()) {
|
||||||
|
message.insert(message.begin(),
|
||||||
|
{.fragment = "Expected: ", .color = Fragment::kError});
|
||||||
|
if (condition) {
|
||||||
|
Error<K>(std::move(message), pos, source_location);
|
||||||
|
}
|
||||||
|
return condition;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <Kind K>
|
||||||
|
bool Require(bool condition, Fragments message, std::optional<Pos> pos = {},
|
||||||
|
std::source_location source_location =
|
||||||
|
std::source_location::current()) {
|
||||||
|
message.insert(message.begin(),
|
||||||
|
{.fragment = "Required: ", .color = Fragment::kError});
|
||||||
|
if (condition) {
|
||||||
|
Error<K>(std::move(message), pos, source_location);
|
||||||
|
}
|
||||||
|
return condition;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Log &log_;
|
||||||
|
Area area_;
|
||||||
|
Level default_level_;
|
||||||
|
std::string function_;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
Log(std::function<void(const Message &)> sys_hook,
|
||||||
|
std::function<void(const Message &)> proc_hook)
|
||||||
|
: sys{}, proc{}, sys_hook_(sys_hook), proc_hook_(proc_hook) {}
|
||||||
|
|
||||||
|
// TODO: proc logs
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <Kind K> void PushLog(Message message) {
|
||||||
|
static_assert(K == kSys or K == kProc);
|
||||||
|
switch (K) {
|
||||||
|
case kSys:
|
||||||
|
sys_hook_(message);
|
||||||
|
sys.push_back(std::move(message));
|
||||||
|
break;
|
||||||
|
case kProc:
|
||||||
|
proc_hook_(message);
|
||||||
|
proc.push_back(std::move(message));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<Message> sys; // logs for runing code
|
||||||
|
std::vector<Message>
|
||||||
|
proc; // logs for code parsing / type check / interpretation / ...
|
||||||
|
std::function<void(const Message &)> sys_hook_;
|
||||||
|
std::function<void(const Message &)> proc_hook_;
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
std::string to_string(const std::source_location &source_location);
|
||||||
|
|
||||||
|
std::string to_string(Pos::Point point);
|
||||||
|
|
||||||
|
std::string to_string(Pos pos);
|
||||||
|
|
||||||
|
std::string to_string(Log::Fragments fragments);
|
||||||
|
|
||||||
|
std::string to_string(Log::Level level);
|
||||||
|
|
||||||
|
std::string to_string(Log::Message message);
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
Log BuildPrintLog(std::ostream &out, Log::Level min_level = Log::Level::kInfo);
|
||||||
|
|
||||||
|
} // namespace utils
|
||||||
|
|
||||||
|
using utils::Log;
|
||||||
1
lang/utils/src/executor.cpp
Normal file
1
lang/utils/src/executor.cpp
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
#include "executor.hpp"
|
||||||
54
lang/utils/src/log.cpp
Normal file
54
lang/utils/src/log.cpp
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
#include "log.hpp"
|
||||||
|
|
||||||
|
#include "magic_enum.hpp"
|
||||||
|
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
|
namespace utils {
|
||||||
|
|
||||||
|
std::string to_string(const std::source_location &source_location) {
|
||||||
|
return std::format("{}:{} {}", source_location.file_name(),
|
||||||
|
source_location.line(), source_location.function_name());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string to_string(Pos::Point point) {
|
||||||
|
return std::format("{},{}", point.line, point.position);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string to_string(Pos pos) {
|
||||||
|
return std::format("{} - {}", to_string(pos.start), to_string(pos.end));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string to_string(Log::Fragments fragments) {
|
||||||
|
return std::accumulate( //
|
||||||
|
std::move_iterator(fragments.begin()),
|
||||||
|
std::move_iterator(fragments.end()), std::string{},
|
||||||
|
[](auto &&acc, Log::Fragment &&fragment) {
|
||||||
|
acc += static_cast<std::string>(fragment);
|
||||||
|
return acc;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string to_string(Log::Level level) {
|
||||||
|
return std::string{magic_enum::enum_name(level).substr(1)}; // k... -> ...
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string to_string(Log::Message message) {
|
||||||
|
return std::format(
|
||||||
|
"{}: {}{} ({})", to_string(message.level), to_string(message.message),
|
||||||
|
message.pos ? (" at " + to_string(*message.pos)) : std::string{},
|
||||||
|
to_string(message.source_location));
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
inline Log BuildPrintLog(std::ostream &out, Log::Level min_level) {
|
||||||
|
auto const print = [&out, min_level](const Log::Message &message) {
|
||||||
|
if (message.level >= min_level) {
|
||||||
|
out << to_string(message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return Log(print, print);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace utils
|
||||||
|
|
@ -1,8 +1,15 @@
|
||||||
set_languages("c++20")
|
set_languages("c++20")
|
||||||
|
|
||||||
|
add_requires("magic_enum")
|
||||||
|
|
||||||
|
-- TODO:
|
||||||
|
-- includes("../../deps/termcolor")
|
||||||
|
|
||||||
target("lang.utils")
|
target("lang.utils")
|
||||||
set_kind("static")
|
set_kind("static")
|
||||||
add_includedirs("include", {public = true})
|
add_includedirs("include", {public = true})
|
||||||
add_files("src/**.cpp")
|
add_files("src/**.cpp")
|
||||||
|
add_packages("magic_enum")
|
||||||
|
-- add_deps("termcolor")
|
||||||
set_warnings("allextra", "error")
|
set_warnings("allextra", "error")
|
||||||
set_rundir("$(projectdir)")
|
set_rundir("$(projectdir)")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue