diff --git a/CMakeLists.txt b/CMakeLists.txt index 23ba43c..a5771dc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,7 @@ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.12") project(indicators VERSION 2.3.0 LANGUAGES CXX HOMEPAGE_URL "https://github.com/p-ranav/indicators" DESCRIPTION "Activity Indicators for Modern C++") + cmake_minimum_required(VERSION 3.12) elseif(CMAKE_VERSION VERSION_GREATER_EQUAL "3.9") project(indicators VERSION 2.3.0 LANGUAGES CXX DESCRIPTION "Activity Indicators for Modern C++") diff --git a/include/indicators/cursor_control.hpp b/include/indicators/cursor_control.hpp index 641156f..a349717 100644 --- a/include/indicators/cursor_control.hpp +++ b/include/indicators/cursor_control.hpp @@ -1,4 +1,3 @@ - #ifndef INDICATORS_CURSOR_CONTROL #define INDICATORS_CURSOR_CONTROL @@ -12,12 +11,14 @@ #include #endif +#include "terminal_size.hpp" + namespace indicators { #if defined(_MSC_VER) -static inline void show_console_cursor(bool const show) { - HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE); +static inline void show_console_cursor(bool const show, TerminalHandle hndl = TerminalHandle::StdOut) { + HANDLE out = GetStdHandle(os_handle(hndl)); CONSOLE_CURSOR_INFO cursorInfo; @@ -26,8 +27,8 @@ static inline void show_console_cursor(bool const show) { SetConsoleCursorInfo(out, &cursorInfo); } -static inline void erase_line() { - auto hStdout = GetStdHandle(STD_OUTPUT_HANDLE); +static inline void erase_line(TerminalHandle hndl = TerminalHandle::StdOut) { + auto hStdout = GetStdHandle(os_handle(hndl)); if (!hStdout) return; @@ -51,16 +52,25 @@ static inline void erase_line() { #else -static inline void show_console_cursor(bool const show) { - std::fputs(show ? "\033[?25h" : "\033[?25l", stdout); +static inline FILE* os_stream(TerminalHandle hndl) +{ + switch (hndl) { + case TerminalHandle::StdOut: return stdout; + case TerminalHandle::StdErr: return stderr; + } + return stdout; } -static inline void erase_line() { - std::fputs("\r\033[K", stdout); +static inline void show_console_cursor(bool const show, TerminalHandle hndl = TerminalHandle::StdOut) { + std::fputs(show ? "\033[?25h" : "\033[?25l", os_stream(hndl)); +} + +static inline void erase_line(TerminalHandle hndl = TerminalHandle::StdOut) { + std::fputs("\r\033[K", os_stream(hndl)); } #endif } // namespace indicators -#endif \ No newline at end of file +#endif diff --git a/include/indicators/display_width.hpp b/include/indicators/display_width.hpp index b1283ff..2b5e084 100644 --- a/include/indicators/display_width.hpp +++ b/include/indicators/display_width.hpp @@ -74,8 +74,8 @@ namespace details { */ struct interval { - int first; - int last; + wchar_t first; + wchar_t last; }; /* auxiliary function for binary search in interval table */ @@ -356,4 +356,4 @@ static inline int display_width(const std::wstring &input) { } // namespace unicode -#endif \ No newline at end of file +#endif diff --git a/include/indicators/progress_bar.hpp b/include/indicators/progress_bar.hpp index ce22957..c0f745e 100644 --- a/include/indicators/progress_bar.hpp +++ b/include/indicators/progress_bar.hpp @@ -84,7 +84,7 @@ class ProgressBar { option::ProgressType{ProgressType::incremental}, std::forward(args)...), details::get( - option::Stream{std::cout}, std::forward(args)...)) { + option::Stream{TerminalHandle::StdOut}, std::forward(args)...)) { // if progress is incremental, start from min_progress // else start from max_progress @@ -278,12 +278,18 @@ class ProgressBar { const auto result_size = unicode::display_width(result); return {result, result_size}; } +private: + std::ostream& as_stream(TerminalHandle hndl) { + if (hndl == TerminalHandle::StdOut) { return std::cout; } + return std::cerr; + } public: void print_progress(bool from_multi_progress = false) { std::lock_guard lock{mutex_}; - auto &os = get_value(); + auto stream_type = get_value(); + auto &os = as_stream(stream_type); const auto type = get_value(); const auto min_progress = @@ -335,7 +341,7 @@ class ProgressBar { const auto start_length = get_value().size(); const auto bar_width = get_value(); const auto end_length = get_value().size(); - const auto terminal_width = terminal_size().second; + const auto terminal_width = terminal_size(stream_type).second; // prefix + bar_width + postfix should be <= terminal_width const int remaining = terminal_width - (prefix_length + start_length + bar_width + end_length + postfix_length); if (prefix_length == -1 || postfix_length == -1) { @@ -359,4 +365,4 @@ class ProgressBar { } // namespace indicators -#endif \ No newline at end of file +#endif diff --git a/include/indicators/setting.hpp b/include/indicators/setting.hpp index 7298258..932add8 100644 --- a/include/indicators/setting.hpp +++ b/include/indicators/setting.hpp @@ -32,6 +32,7 @@ SOFTWARE. #include #include #include +#include #include #include #include @@ -215,8 +216,9 @@ using FontStyles = using MinProgress = details::IntegerSetting; using MaxProgress = details::IntegerSetting; using ProgressType = details::Setting; -using Stream = details::Setting; + +using Stream = details::Setting; } // namespace option } // namespace indicators -#endif \ No newline at end of file +#endif diff --git a/include/indicators/terminal_size.hpp b/include/indicators/terminal_size.hpp index 0d03077..7b44d52 100644 --- a/include/indicators/terminal_size.hpp +++ b/include/indicators/terminal_size.hpp @@ -1,24 +1,37 @@ - #ifndef INDICATORS_TERMINAL_SIZE #define INDICATORS_TERMINAL_SIZE #include +namespace indicators { + enum class TerminalHandle { + StdOut, StdErr + }; +}; #if defined(_WIN32) #include namespace indicators { -static inline std::pair terminal_size() { +static inline DWORD os_handle(TerminalHandle hndl) +{ + switch (hndl) { + case TerminalHandle::StdOut: return STD_OUTPUT_HANDLE; + case TerminalHandle::StdErr: return STD_ERROR_HANDLE; + } + return STD_OUTPUT_HANDLE; +} + +static inline std::pair terminal_size(TerminalHandle hndl) { CONSOLE_SCREEN_BUFFER_INFO csbi; int cols, rows; - GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi); + GetConsoleScreenBufferInfo(GetStdHandle(os_handle(hndl)), &csbi); cols = csbi.srWindow.Right - csbi.srWindow.Left + 1; rows = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; return {static_cast(rows), static_cast(cols)}; } -static inline size_t terminal_width() { return terminal_size().second; } +static inline size_t terminal_width(TerminalHandle hndl) { return terminal_size(hndl).second; } } // namespace indicators @@ -29,16 +42,26 @@ static inline size_t terminal_width() { return terminal_size().second; } namespace indicators { -static inline std::pair terminal_size() { +static inline int os_handle(TerminalHandle hndl) +{ + switch (hndl) { + case TerminalHandle::StdOut: return STDOUT_FILENO; + case TerminalHandle::StdErr: return STDERR_FILENO; + } + return STDOUT_FILENO; +} + + +static inline std::pair terminal_size(TerminalHandle hndl) { struct winsize size{}; - ioctl(STDOUT_FILENO, TIOCGWINSZ, &size); + ioctl(os_handle(hndl), TIOCGWINSZ, &size); return {static_cast(size.ws_row), static_cast(size.ws_col)}; } -static inline size_t terminal_width() { return terminal_size().second; } +static inline size_t terminal_width(TerminalHandle hndl) { return terminal_size(hndl).second; } } // namespace indicators #endif -#endif \ No newline at end of file +#endif diff --git a/single_include/indicators/indicators.hpp b/single_include/indicators/indicators.hpp index 3832d66..b859ac7 100644 --- a/single_include/indicators/indicators.hpp +++ b/single_include/indicators/indicators.hpp @@ -1415,8 +1415,8 @@ namespace details { */ struct interval { - int first; - int last; + wchar_t first; + wchar_t last; }; /* auxiliary function for binary search in interval table */