21 std::size_t
lines() const noexcept {
return _lines; }
27 if (cmd._lines == 0U) {
32 HANDLE handle = invalid_handle();
33 if (&os == &std::cout) {
34 handle = ::GetStdHandle(STD_OUTPUT_HANDLE);
35 }
else if (&os == &std::cerr || &os == &std::clog) {
36 handle = ::GetStdHandle(STD_ERROR_HANDLE);
39 if (handle != invalid_handle()) {
40 if (try_enable_vt(handle)) {
41 write_ansi(os, cmd._lines);
45 if (clear_with_console_api(handle, cmd._lines)) {
51 write_ansi(os, cmd._lines);
56 static HANDLE invalid_handle() noexcept {
57 return INVALID_HANDLE_VALUE;
60 static bool try_enable_vt(HANDLE handle) {
62 if (!::GetConsoleMode(handle, &mode)) {
66 if ((mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING) != 0) {
70 return ::SetConsoleMode(handle, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING) != 0;
73 static bool clear_with_console_api(HANDLE handle, std::size_t
lines) {
74 CONSOLE_SCREEN_BUFFER_INFO info{};
75 if (!::GetConsoleScreenBufferInfo(handle, &info)) {
79 const SHORT width = info.dwSize.X;
84 SHORT cursor_y = info.dwCursorPosition.Y;
85 SHORT first_row =
static_cast<SHORT
>(std::max<int>(0,
static_cast<int>(cursor_y) -
static_cast<int>(
lines)));
87 for (SHORT row =
static_cast<SHORT
>(cursor_y - 1); row >= first_row; --row) {
89 COORD row_start{0, row};
90 if (!::FillConsoleOutputCharacterA(handle,
' ',
static_cast<DWORD
>(width), row_start, &written)) {
93 if (!::FillConsoleOutputAttribute(handle, info.wAttributes,
static_cast<DWORD
>(width), row_start, &written)) {
101 COORD target{0, first_row};
102 if (!::SetConsoleCursorPosition(handle, target)) {
110 static void write_ansi(std::ostream &os, std::size_t
lines) {
111 for (std::size_t i = 0; i <
lines; ++i) {
112 os <<
"\x1b[1A\x1b[2K";
113 if (i + 1U <
lines) {
117 os <<
'\r' << std::flush;