Fancy console output for Windows

This commit is contained in:
Marcus Holland-Moritz 2023-06-27 11:14:09 +02:00
parent 3364972027
commit 6770c13c08
5 changed files with 83 additions and 7 deletions

View File

@ -43,6 +43,8 @@ class console_writer : public logger {
level_type threshold, display_mode mode = NORMAL, level_type threshold, display_mode mode = NORMAL,
bool verbose = false); bool verbose = false);
~console_writer();
void write(level_type level, const std::string& output, char const* file, void write(level_type level, const std::string& output, char const* file,
int line) override; int line) override;

View File

@ -48,6 +48,8 @@ enum class termcolor {
bool stream_is_fancy_terminal(std::ostream& os); bool stream_is_fancy_terminal(std::ostream& os);
bool set_cursor_state(bool enabled);
char const* terminal_color(termcolor color); char const* terminal_color(termcolor color);
std::string std::string

View File

@ -75,18 +75,29 @@ console_writer::console_writer(std::ostream& os, progress_mode pg_mode,
} else { } else {
set_policy<prod_logger_policy>(); set_policy<prod_logger_policy>();
} }
set_cursor_state(false);
} }
console_writer::~console_writer() { set_cursor_state(true); }
void console_writer::rewind() { void console_writer::rewind() {
if (!statebuf_.empty()) { if (!statebuf_.empty()) {
int lines = 0;
switch (mode_) { switch (mode_) {
case NORMAL: case NORMAL:
os_ << "\x1b[A\r\x1b[A\x1b[A\x1b[A\x1b[A\x1b[A\x1b[A\x1b[A"; lines = 8;
break; break;
case REWRITE: case REWRITE:
os_ << "\x1b[A\r\x1b[A\x1b[A\x1b[A"; lines = 4;
break; break;
} }
os_ << '\r';
for (int i = 0; i < lines; ++i) {
os_ << "\x1b[A";
}
} }
} }

View File

@ -26,17 +26,68 @@
#include <cstring> #include <cstring>
#include <iostream> #include <iostream>
#ifndef _WIN32 #include <folly/portability/Unistd.h>
#include <unistd.h> #include <folly/portability/Windows.h>
#endif
#include "dwarfs/terminal.h" #include "dwarfs/terminal.h"
namespace dwarfs { 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]]) { bool stream_is_fancy_terminal(std::ostream& os [[maybe_unused]]) {
#ifdef _WIN32 #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; return false;
#else #else
if (&os == &std::cout && !::isatty(::fileno(stdout))) { if (&os == &std::cout && !::isatty(::fileno(stdout))) {

View File

@ -114,9 +114,19 @@ const std::map<std::string, console_writer::progress_mode> progress_modes{
{"none", console_writer::NONE}, {"none", console_writer::NONE},
{"simple", console_writer::SIMPLE}, {"simple", console_writer::SIMPLE},
{"ascii", console_writer::ASCII}, {"ascii", console_writer::ASCII},
#ifndef _WIN32
{"unicode", console_writer::UNICODE}, {"unicode", console_writer::UNICODE},
#endif
}; };
const std::string default_progress_mode =
#ifdef _WIN32
"ascii"
#else
"unicode"
#endif
;
const std::map<std::string, debug_filter_mode> debug_filter_modes{ const std::map<std::string, debug_filter_mode> debug_filter_modes{
{"included", debug_filter_mode::INCLUDED}, {"included", debug_filter_mode::INCLUDED},
{"included-files", debug_filter_mode::INCLUDED_FILES}, {"included-files", debug_filter_mode::INCLUDED_FILES},
@ -539,7 +549,7 @@ int mkdwarfs_main(int argc, sys_char** argv) {
po::value<std::string>(&log_level_str)->default_value("info"), po::value<std::string>(&log_level_str)->default_value("info"),
"log level (error, warn, info, debug, trace)") "log level (error, warn, info, debug, trace)")
("progress", ("progress",
po::value<std::string>(&progress_mode)->default_value("unicode"), po::value<std::string>(&progress_mode)->default_value(default_progress_mode),
progress_desc.c_str()) progress_desc.c_str())
("no-progress", ("no-progress",
po::value<bool>(&no_progress)->zero_tokens(), po::value<bool>(&no_progress)->zero_tokens(),