From 6770c13c08c9021bb5fc1375c6771dde99bd90be Mon Sep 17 00:00:00 2001 From: Marcus Holland-Moritz Date: Tue, 27 Jun 2023 11:14:09 +0200 Subject: [PATCH] Fancy console output for Windows --- include/dwarfs/console_writer.h | 2 ++ include/dwarfs/terminal.h | 2 ++ src/dwarfs/console_writer.cpp | 15 +++++++-- src/dwarfs/terminal.cpp | 59 ++++++++++++++++++++++++++++++--- src/mkdwarfs_main.cpp | 12 ++++++- 5 files changed, 83 insertions(+), 7 deletions(-) diff --git a/include/dwarfs/console_writer.h b/include/dwarfs/console_writer.h index 8355685e..30c458fb 100644 --- a/include/dwarfs/console_writer.h +++ b/include/dwarfs/console_writer.h @@ -43,6 +43,8 @@ class console_writer : public logger { level_type threshold, display_mode mode = NORMAL, bool verbose = false); + ~console_writer(); + void write(level_type level, const std::string& output, char const* file, int line) override; diff --git a/include/dwarfs/terminal.h b/include/dwarfs/terminal.h index bed077fc..a8be2326 100644 --- a/include/dwarfs/terminal.h +++ b/include/dwarfs/terminal.h @@ -48,6 +48,8 @@ enum class termcolor { bool stream_is_fancy_terminal(std::ostream& os); +bool set_cursor_state(bool enabled); + char const* terminal_color(termcolor color); std::string diff --git a/src/dwarfs/console_writer.cpp b/src/dwarfs/console_writer.cpp index 3e6e69d1..c0c71325 100644 --- a/src/dwarfs/console_writer.cpp +++ b/src/dwarfs/console_writer.cpp @@ -75,18 +75,29 @@ console_writer::console_writer(std::ostream& os, progress_mode pg_mode, } else { set_policy(); } + set_cursor_state(false); } +console_writer::~console_writer() { set_cursor_state(true); } + void console_writer::rewind() { if (!statebuf_.empty()) { + int lines = 0; + switch (mode_) { case NORMAL: - os_ << "\x1b[A\r\x1b[A\x1b[A\x1b[A\x1b[A\x1b[A\x1b[A\x1b[A"; + lines = 8; break; case REWRITE: - os_ << "\x1b[A\r\x1b[A\x1b[A\x1b[A"; + lines = 4; break; } + + os_ << '\r'; + + for (int i = 0; i < lines; ++i) { + os_ << "\x1b[A"; + } } } diff --git a/src/dwarfs/terminal.cpp b/src/dwarfs/terminal.cpp index 2537eaf3..ed6f713e 100644 --- a/src/dwarfs/terminal.cpp +++ b/src/dwarfs/terminal.cpp @@ -26,17 +26,68 @@ #include #include -#ifndef _WIN32 -#include -#endif +#include +#include #include "dwarfs/terminal.h" namespace dwarfs { +#if defined(_WIN32) +void WindowsEmulateVT100Terminal(DWORD std_handle) { + static bool done = false; + + if (done) { + return; + } + + done = true; + + // TODO? + // ::SetConsoleOutputCP(CP_UTF8); + // ::SetConsoleCP(CP_UTF8); + + // Enable VT processing on stdout and stdin + auto hdl = ::GetStdHandle(STD_OUTPUT_HANDLE); + + DWORD out_mode = 0; + ::GetConsoleMode(hdl, &out_mode); + + // https://docs.microsoft.com/en-us/windows/console/setconsolemode + static constexpr DWORD enable_virtual_terminal_processing = 0x0004; + static constexpr DWORD disable_newline_auto_return = 0x0008; + out_mode |= enable_virtual_terminal_processing; + out_mode |= disable_newline_auto_return; + + ::SetConsoleMode(hdl, out_mode); +} +#endif + +bool set_cursor_state(bool enabled [[maybe_unused]]) { + bool was_enabled = true; +#ifdef _WIN32 + auto hdl = ::GetStdHandle(STD_OUTPUT_HANDLE); + + ::CONSOLE_CURSOR_INFO cursorInfo; + + ::GetConsoleCursorInfo(hdl, &cursorInfo); + was_enabled = cursorInfo.bVisible; + cursorInfo.bVisible = enabled; + ::SetConsoleCursorInfo(hdl, &cursorInfo); +#endif + return was_enabled; +} + bool stream_is_fancy_terminal(std::ostream& os [[maybe_unused]]) { #ifdef _WIN32 - // TODO + if (&os == &std::cout) { + WindowsEmulateVT100Terminal(STD_OUTPUT_HANDLE); + return true; + } + if (&os == &std::cerr) { + WindowsEmulateVT100Terminal(STD_ERROR_HANDLE); + return true; + } return false; #else if (&os == &std::cout && !::isatty(::fileno(stdout))) { diff --git a/src/mkdwarfs_main.cpp b/src/mkdwarfs_main.cpp index 048e6ef8..7f106b4c 100644 --- a/src/mkdwarfs_main.cpp +++ b/src/mkdwarfs_main.cpp @@ -114,9 +114,19 @@ const std::map progress_modes{ {"none", console_writer::NONE}, {"simple", console_writer::SIMPLE}, {"ascii", console_writer::ASCII}, +#ifndef _WIN32 {"unicode", console_writer::UNICODE}, +#endif }; +const std::string default_progress_mode = +#ifdef _WIN32 + "ascii" +#else + "unicode" +#endif + ; + const std::map debug_filter_modes{ {"included", debug_filter_mode::INCLUDED}, {"included-files", debug_filter_mode::INCLUDED_FILES}, @@ -539,7 +549,7 @@ int mkdwarfs_main(int argc, sys_char** argv) { po::value(&log_level_str)->default_value("info"), "log level (error, warn, info, debug, trace)") ("progress", - po::value(&progress_mode)->default_value("unicode"), + po::value(&progress_mode)->default_value(default_progress_mode), progress_desc.c_str()) ("no-progress", po::value(&no_progress)->zero_tokens(),