diff --git a/CMakeLists.txt b/CMakeLists.txt index ea8fc60b..b57a7c4d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -169,6 +169,7 @@ list( src/dwarfs/progress.cpp src/dwarfs/scanner.cpp src/dwarfs/similarity.cpp + src/dwarfs/terminal.cpp src/dwarfs/util.cpp src/dwarfs/worker_group.cpp) diff --git a/include/dwarfs/console_writer.h b/include/dwarfs/console_writer.h index 21b03b99..ecca755a 100644 --- a/include/dwarfs/console_writer.h +++ b/include/dwarfs/console_writer.h @@ -57,5 +57,6 @@ class console_writer : public logger { const progress_mode pg_mode_; const size_t width_; const display_mode mode_; + const bool color_; }; } // namespace dwarfs diff --git a/include/dwarfs/logger.h b/include/dwarfs/logger.h index 17d202a3..789f6512 100644 --- a/include/dwarfs/logger.h +++ b/include/dwarfs/logger.h @@ -80,6 +80,7 @@ class stream_logger : public logger { std::ostream& os_; std::mutex mx_; std::atomic threshold_; + const bool color_; }; class level_logger { diff --git a/include/dwarfs/terminal.h b/include/dwarfs/terminal.h new file mode 100644 index 00000000..1bf7af3b --- /dev/null +++ b/include/dwarfs/terminal.h @@ -0,0 +1,51 @@ +/* vim:set ts=2 sw=2 sts=2 et: */ +/** + * \author Marcus Holland-Moritz (github@mhxnet.de) + * \copyright Copyright (c) Marcus Holland-Moritz + * + * This file is part of dwarfs. + * + * dwarfs is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * dwarfs is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with dwarfs. If not, see . + */ + +#pragma once + +#include + +namespace dwarfs { + +enum class termcolor { + NORMAL, + RED, + GREEN, + YELLOW, + BLUE, + CYAN, + WHITE, + MAGENTA, + BOLD_RED, + BOLD_GREEN, + BOLD_YELLOW, + BOLD_BLUE, + BOLD_MAGENTA, + BOLD_CYAN, + BOLD_WHITE, + NUM_COLORS +}; + +bool stream_is_fancy_terminal(std::ostream& os); + +char const* terminal_color(termcolor color); + +} // namespace dwarfs diff --git a/src/dwarfs/console_writer.cpp b/src/dwarfs/console_writer.cpp index 257b05ec..ed2388f8 100644 --- a/src/dwarfs/console_writer.cpp +++ b/src/dwarfs/console_writer.cpp @@ -31,6 +31,7 @@ #include "dwarfs/entry_interface.h" #include "dwarfs/inode.h" #include "dwarfs/progress.h" +#include "dwarfs/terminal.h" #include "dwarfs/util.h" namespace dwarfs { @@ -50,7 +51,8 @@ console_writer::console_writer(std::ostream& os, progress_mode pg_mode, , frac_(0.0) , pg_mode_(pg_mode) , width_(width) - , mode_(mode) { + , mode_(mode) + , color_(stream_is_fancy_terminal(os)) { os_.imbue(std::locale(os_.getloc(), new boost::posix_time::time_facet("%H:%M:%S.%f"))); if (threshold > level_type::INFO) { @@ -79,19 +81,21 @@ void console_writer::write(level_type level, const std::string& output) { const char* prefix = ""; const char* suffix = ""; - switch (level) { - case ERROR: - prefix = "\033[1;31m"; - suffix = "\033[0m"; - break; + if (color_) { + switch (level) { + case ERROR: + prefix = terminal_color(termcolor::BOLD_RED); + suffix = terminal_color(termcolor::NORMAL); + break; - case WARN: - prefix = "\033[1;33m"; - suffix = "\033[0m"; - break; + case WARN: + prefix = terminal_color(termcolor::BOLD_YELLOW); + suffix = terminal_color(termcolor::NORMAL); + break; - default: - break; + default: + break; + } } std::lock_guard lock(mx_); diff --git a/src/dwarfs/logger.cpp b/src/dwarfs/logger.cpp index da9b6754..e601ed9a 100644 --- a/src/dwarfs/logger.cpp +++ b/src/dwarfs/logger.cpp @@ -32,6 +32,7 @@ #include #include "dwarfs/logger.h" +#include "dwarfs/terminal.h" namespace dwarfs { @@ -91,7 +92,8 @@ logger::level_type logger::parse_level(std::string_view level) { } stream_logger::stream_logger(std::ostream& os, level_type threshold) - : os_(os) { + : os_(os) + , color_(stream_is_fancy_terminal(os)) { os_.imbue(std::locale(os_.getloc(), new boost::posix_time::time_facet("%H:%M:%S.%f"))); set_threshold(threshold); @@ -100,9 +102,28 @@ stream_logger::stream_logger(std::ostream& os, level_type threshold) void stream_logger::write(level_type level, const std::string& output) { if (level <= threshold_) { auto t = boost::posix_time::microsec_clock::local_time(); + const char* prefix = ""; + const char* suffix = ""; + + if (color_) { + switch (level) { + case ERROR: + prefix = terminal_color(termcolor::BOLD_RED); + suffix = terminal_color(termcolor::NORMAL); + break; + + case WARN: + prefix = terminal_color(termcolor::BOLD_YELLOW); + suffix = terminal_color(termcolor::NORMAL); + break; + + default: + break; + } + } std::lock_guard lock(mx_); - os_ << t << " " << output << "\n"; + os_ << prefix << t << " " << output << suffix << "\n"; if (threshold_ == TRACE) { backtrace(os_); diff --git a/src/dwarfs/terminal.cpp b/src/dwarfs/terminal.cpp new file mode 100644 index 00000000..58d0d5f3 --- /dev/null +++ b/src/dwarfs/terminal.cpp @@ -0,0 +1,71 @@ +/* vim:set ts=2 sw=2 sts=2 et: */ +/** + * \author Marcus Holland-Moritz (github@mhxnet.de) + * \copyright Copyright (c) Marcus Holland-Moritz + * + * This file is part of dwarfs. + * + * dwarfs is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * dwarfs is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with dwarfs. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "dwarfs/terminal.h" + +namespace dwarfs { + +bool stream_is_fancy_terminal(std::ostream& os) { + if (&os == &std::cout && !::isatty(::fileno(stdout))) { + return false; + } + if (&os == &std::cerr && !::isatty(::fileno(stderr))) { + return false; + } + auto term = ::getenv("TERM"); + std::cerr << "term: " << term << std::endl; + return term && term[0] && ::strcmp(term, "dumb"); +} + +char const* terminal_color(termcolor color) { + static constexpr std::array(termcolor::NUM_COLORS)> + colors = {{ + "\033[0m", + "\033[31m", + "\033[32m", + "\033[33m", + "\033[34m", + "\033[35m", + "\033[36m", + "\033[37m", + "\033[1;31m", + "\033[1;32m", + "\033[1;33m", + "\033[1;34m", + "\033[1;35m", + "\033[1;36m", + "\033[1;37m", + }}; + + return colors.at(static_cast(color)); +} + +} // namespace dwarfs diff --git a/src/mkdwarfs.cpp b/src/mkdwarfs.cpp index c6126b3e..a9542fc4 100644 --- a/src/mkdwarfs.cpp +++ b/src/mkdwarfs.cpp @@ -68,6 +68,7 @@ #include "dwarfs/progress.h" #include "dwarfs/scanner.h" #include "dwarfs/script.h" +#include "dwarfs/terminal.h" #include "dwarfs/util.h" #ifdef DWARFS_HAVE_PYTHON @@ -599,7 +600,7 @@ int mkdwarfs(int argc, char** argv) { if (no_progress) { progress_mode = "none"; } - if (progress_mode != "none" && !::isatty(::fileno(stderr))) { + if (progress_mode != "none" && !stream_is_fancy_terminal(std::cerr)) { progress_mode = "simple"; } if (!progress_modes.count(progress_mode)) {