p-ranav / indicators Goto Github PK
View Code? Open in Web Editor NEWActivity Indicators for Modern C++
License: MIT License
Activity Indicators for Modern C++
License: MIT License
Use the following define before #include <windows.h>
to avoid build errors on Windows using Visual Studio:
#define NOMINMAX
More info here.
P.S.
I'm using single_include version.
The current implementation only prints when indexing into the progress bar and doesn't expose the print_progress method.
This leads to problems when the last access to the progress bar sets e.g. an option to make the postfix text to "Finalize" it's not going to be printed for the last-to-finish bar.
I think the most formally correct way to implement this would be with either a proxy object (instead of returning a real reference from the accessor, or with a set_option
/ set_progress
method that also takes an index.
What do you think?
os:windows
when build the package, we use
```
find_package(indicators 1.9.0 REQUIRED)
```
but the indicators_INCLUDE_PATH is empty.
can your solve my problem?
and size_t terminal_width() can be defined as static or will cause the redefine problem
This is a really nice library. When deploying though it was a little bit more work than expected, given the library size. One possibility would be to have a single-header version of the library.
For example, CLI11 ( https://github.com/CLIUtils/CLI11) of JSON for modern C++ (https://github.com/nlohmann/json) follow this approach.
The single-header version can be generated with an amalgamation script. But, by looking at your code, it seems that it may be easier to use a single file, since many of the file have only a few lines of code.
If there is interest, but not enough development time, I would be happy to try to produce the one-file version by manually merging the existing code.
Hey, first of all, awesome work! 😃
I ran into some issues when building and running the demo and I would like to share my workarounds.
$ mingw32-make.exe g++ -pthread -std=c++11 -I../include -o demo demo.cpp In file included from ../include/indicators/details/stream_helper.hpp:6, from ../include/indicators/progress_bar.hpp:4, from demo.cpp:4: ../include/indicators/termcolor.hpp: In function 'std::ostream& termcolor::red(std::ostream&)': ../include/indicators/termcolor.hpp:287:17: error: 'FOREGROUND_RED' was not declared in this scope 287 | FOREGROUND_RED | ^~~~~~~~~~~~~~ ../include/indicators/termcolor.hpp:287:17: note: the macro 'FOREGROUND_RED' had not yet been defined In file included from c:\winlibs-x86_64-posix-seh-gcc-10.2.0-llvm-11.0.0-mingw-w64-8.0.0-r3\mingw64\x86_64-w64-mingw32\include\windows.h:74, from ../include/indicators/terminal_size.hpp:7, from ../include/indicators/progress_bar.hpp:12, from demo.cpp:4: c:\winlibs-x86_64-posix-seh-gcc-10.2.0-llvm-11.0.0-mingw-w64-8.0.0-r3\mingw64\x86_64-w64-mingw32\include\wincon.h:121: note: it was later defined here 121 | #define FOREGROUND_RED 0x4
In indicators/termcolor.hpp
, some Windows-specific headers are not included. I changed lines 36-44 (moved an endif
) to this:
#elif defined(TERMCOLOR_OS_WINDOWS)
#if defined(_MSC_VER)
#if !defined(NOMINMAX)
#define NOMINMAX
#endif
#endif
# include <io.h>
# include <windows.h>
#endif
The second issue encountered was the from_bytes
conversion in function std::wstring utf8_decode(const std::string &str)
from indicators/display_width.hpp
. I replaced it with the function from this answer. Though I'm not sure if this second workaround is portable.
$ ./demo.exe [■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ] Buying more snacks Reading package list... Done [==================================================] Done { 97% } ⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠧ Restoring system state { ERROR } 98% Failed to restore system [■-------------------------------------------------] Reverting system restore ⡀ 101% Checking credentials ✔ Authenticated! Compiling mission - ✔ Searching for the Moon - ✔ Contacting Kerbal headquarters - ✔ Designing spaceship - ✔ Launching rocket - 🌎terminate called after throwing an instance of 'std::range_error' what(): wstring_convert::from_bytes
// credits: https://stackoverflow.com/a/7154226 static inline std::wstring utf8_decode(const std::string& utf8) { std::vector unicode; size_t i = 0; while (i < utf8.size()) { unsigned long uni; size_t todo; bool error = false; unsigned char ch = utf8[i++]; if (ch <= 0x7F) { uni = ch; todo = 0; } else if (ch <= 0xBF) { throw std::logic_error("not a UTF-8 string"); } else if (ch <= 0xDF) { uni = ch&0x1F; todo = 1; } else if (ch <= 0xEF) { uni = ch&0x0F; todo = 2; } else if (ch <= 0xF7) { uni = ch&0x07; todo = 3; } else { throw std::logic_error("not a UTF-8 string"); } for (size_t j = 0; j < todo; ++j) { if (i == utf8.size()) throw std::logic_error("not a UTF-8 string"); unsigned char ch = utf8[i++]; if (ch < 0x80 || ch > 0xBF) throw std::logic_error("not a UTF-8 string"); uni <<= 6; uni += ch & 0x3F; } if (uni >= 0xD800 && uni <= 0xDFFF) throw std::logic_error("not a UTF-8 string"); if (uni > 0x10FFFF) throw std::logic_error("not a UTF-8 string"); unicode.push_back(uni); } std::wstring utf16; for (size_t i = 0; i < unicode.size(); ++i) { unsigned long uni = unicode[i]; if (uni <= 0xFFFF) { utf16 += (wchar_t)uni; } else { uni -= 0x10000; utf16 += (wchar_t)((uni >> 10) + 0xD800); utf16 += (wchar_t)((uni & 0x3FF) + 0xDC00); } } return utf16; }
An #include <vector>
would also be necessary for the above workaround.
My current environment is the following:
indicators
latest commit (af7c004 as of 11 november 2020)$ g++ -v
Using built-in specs.
COLLECT_GCC=C:\winlibs-x86_64-posix-seh-gcc-10.2.0-llvm-11.0.0-mingw-w64-8.0.0-r3\mingw64\bin\g++.exe
COLLECT_LTO_WRAPPER=c:/winlibs-x86_64-posix-seh-gcc-10.2.0-llvm-11.0.0-mingw-w64-8.0.0-r3/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/10.2.0/lto-wrapper.exe
Target: x86_64-w64-mingw32
Configured with: ../configure --prefix=/R/winlibs64_stage/inst_gcc-10.2.0/share/gcc --build=x86_64-w64-mingw32 --host=x86_64-w64-mingw32 --with-pkgversion='MinGW-W64 x86_64-posix-seh, built by Brecht Sanders' --with-tune=generic --enable-checking=release --enable-threads=posix --disable-sjlj-exceptions --disable-libunwind-exceptions --enable-serial-configure --disable-bootstrap --enable-host-shared --enable-plugin --enable-default-ssp --disable-rpath --disable-libstdcxx-pch --enable-libstdcxx-time=yes --disable-libstdcxx-debug --disable-version-specific-runtime-libs --with-stabs --disable-symvers --enable-languages=c,c++,fortran,lto,objc,obj-c++,d --disable-gold --disable-nls --disable-stage1-checking --disable-win32-registry --disable-multilib --enable-ld --enable-libquadmath --enable-libada --enable-libssp --enable-libstdcxx --enable-lto --enable-fully-dynamic-string --enable-libgomp --enable-graphite
--enable-mingw-wildcard --with-mpc=/d/Prog/winlibs64_stage/custombuilt --with-mpfr=/d/Prog/winlibs64_stage/custombuilt --with-gmp=/d/Prog/winlibs64_stage/custombuilt --with-isl=/d/Prog/winlibs64_stage/custombuilt --enable-install-libiberty --enable-__cxa_atexit
--without-included-gettext --with-diagnostics-color=auto --with-libiconv --with-system-zlib --with-build-sysroot=/R/winlibs64_stage/gcc-10.2.0/build_mingw/mingw-w64
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 10.2.0 (MinGW-W64 x86_64-posix-seh, built by Brecht Sanders)
With this library, the progress bar is printed on a new line after each update. I've tried both cmd and PowerShell. Is Windows/its consoles supported?
Awesome lib.
I had trouble with usage of min/max on windows.
I will open a PR.
Hello!
When building release 1.9 with -Werror, an error occurs: "error: non-ISO-standard escape sequence, '\ e' [-Werror]"
Not really looked into this - as I have a work around. But if you have multiple includes of cursor_control.hpp in separate source files you get the error:
pkcs11_progress.cpp:(.text+0x0): multiple definition of
indicators::show_console_cursor(bool)'
pkcs11_ec_ecdsaAttacks.o:pkcs11_ec_ecdsaAttacks.cpp:(.text+0x376): first defined here
`
In the example MultiProgress, all the elapsed time of the 3 progresses are running together even when progress 1 and 3 have completed. Is it possible to add something like _end_time_point
to prevent this?
We already have a property is_started, but currently time is accessed in the progress bar even if it's not initialized (started).
This happens when a progress bar is printed from a dynamic multi (or probably also regular multi) bar, but no set_progress has been called.
Instead it should either print 00:00, or --:--
for elapsed time if is_started
is still false.
It is the dangerous naming convention, since implementations reserve all names starting with a double underscore and with single underscores following capital letters.
Even though it is not the case here, member names are started with an underscore and capital letter, it might be easy to fall into a trap.
It would be good to change the naming convention for underscores to follow the member name rather than precede the member name.
In terminal applications such as apt (debian/ubuntu) the progress bar is kept at the bottom while some text is displayed regarding the progress of the installation.
Would it be possible to add such functionality?
Maybe it is not the scope of this library
I'm wondering if it's possible to achieve the same progress bar style that's being using in Ubuntu during the installation of the packages, i.e., this. Basically, the progress bar stick to the bottom of the terminal, and doesn't break the output.
D (03:00:03.997) HEAP: Iteration: 232000 (diff 304 bytes)
V (03:00:04.006) Spinner: Created: 1407943886
V (03:00:04.011) Spinner: Destroyed: 1407943886
D (03:00:04.016) HEAP: Iteration: 231700 (diff 300 bytes)
V (03:00:04.025) Spinner: Created: -1271674128
V (03:00:04.030) Spinner: Destroyed: -1271674128
D (03:00:04.035) HEAP: Iteration: 231396 (diff 304 bytes)
V (03:00:04.044) Spinner: Created: 72749701
V (03:00:04.049) Spinner: Destroyed: 72749701
D (03:00:04.053) HEAP: Iteration: 231096 (diff 300 bytes)
V (03:00:04.063) Spinner: Created: -1957109953
V (03:00:04.067) Spinner: Destroyed: -1957109953
D (03:00:04.073) HEAP: Iteration: 230792 (diff 304 bytes)
V (03:00:04.082) Spinner: Created: 569508829
V (03:00:04.086) Spinner: Destroyed: 569508829
D (03:00:04.091) HEAP: Iteration: 230492 (diff 300 bytes)
every instance 304 or 300 bytes leaked
I want to use the Indeterminate Progress Bar in my program - but where I update the message to indicate the stage an algorithm is in. In the example the text "Checking for Updates" is shown. Is it possible to change this message dynamically whilst the bar is active?
Thanks for this cool library!
It looks like the project was renamed indica -> indicators in 304226c but is still referred to as indica in CMakeLists.txt. Additionally the declared project version does not match the tags & releases which can cause some confusion.
Hi, just heard about this libray from CppCast, and it looks sweet. I wondered, have you heard of the block drawing characters at https://en.wikipedia.org/wiki/Block_Elements? There are characters for 1/8th width blocks, 2/8th width blocks, 3/8th width blocks, etc. which can be used to make really smooth progress bars.
I used them for a progress bar I made for a python application:
The first few characters are full-width blocks, while the last character is whichever block character appropriate.
on windows, when I run the code, it will throw this error : "error: 'mutex' in namespace 'std' does not name a type". I google for it , somebody say "#include" cannt work on windows. I wanna know if there some solutions to solve this problem. thanks a lot.
I'm seeing an overflow issue with the Time Remaining display for progress bars with long run times and large progress values. The Time Remaining starts at a reasonable run time (lets say 7 hours), decreases normally for a bit, then jumps down to zero and begins counting up. At some point, it resets back to zero and begins counting up again. This final cycle repeats for the duration of the process.
It takes awhile for my process to start up, so it's been hard to capture an example of the beginning state, but here's what it looks like when it cyclically resets back to zero:
This seems like an integer overflow scenario in progress_bar.hpp:257
:
auto eta = std::chrono::nanoseconds(
progress_ > 0 ? static_cast<long long>(elapsed_.count() *
max_progress / progress_)
: 0);
It doesn't take long (in nanoseconds) for elapsed_.count() * 1325697865
to overflow long long
and my specific scenario can be quickly fixed by enforcing a specific order of operations: elapsed_.count() * (max_progress / progress_)
. I'm happy to submit this as a patch, but this only shifts the issue to an even larger value of max_progress
. Should there also be some mention of this issue in the documentation?
For fast execution and stability of API, progess should be represented with integral numbers.
Why do you need to define TERMCOLOR_HPP_ twice in the header file in single_include, they are located on line 15 and line 667, which puzzles me
The readme gif ends with a Kerbal mun landing. However we all know kerbals only landcrash on the mun
Please fix this so that the correct system state is indicated by indicator. 🌕🚀💥
I use indicators in a Computationally intensive task, I find using the indicators will make the task slower. if I do not use the indicators, it will take 1min. If I use the indicators, it will take 22min.
I want the tick()
not print the bar. Can I set an interval time? Such as print the bar every 5 seconds. I don't kown how to config it.
Because everything in MultiProgress Bar is templated it makes it not usable in cases, where amount of progress bars is not known at compile-time and this is a common case.
for example:
cp
program, that prints the progress. Amount of files is not known at compile timeIt would be nice to have a utility like pv
bundled with the library. Example:
gzip -c you.file | indicators [opts] > you.file.gz
Or some kind of option (for example, combine samples
into one utility with options and screw on to this at the same time https://github.com/p-ranav/argparse).
print_progress on the progress bars is a private function but if one desires to implement their own multi progress bar it's not easy without forking the project (as one can't externally declare a friend).
Is it really necessary for the function to be private?
I think there are legitimate use-cases not covered by the multi-progress implementations.
using namespace indicators;
// Hide cursor
show_console_cursor(false);
ProgressBar bar{
option::BarWidth{50},
option::Start{"["},
option::Fill{"■"},
option::Lead{"■"},
option::Remainder{"-"},
option::End{" ]"},
option::PostfixText{"Starting simulator"},
option::ForegroundColor{Color::cyan},
option::FontStyles{std::vector<FontStyle>{FontStyle::bold}}
};
here is the code for the first 10%
if ( !VLOG_IS_ON( 1 ) && Environment::isMasterRank() )
{
bar.set_option( option::PostfixText{ "Configuring "s} );
bar.set_progress( 10 );
}
the same for the rest
cols = csbi.srWindow.Right - csbi.srWindow.Left + 1; rows = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; return {static_cast<size_t>(rows), static_cast<size_t>(columns)};
columns should be cols
Awesome project!
But code can be polished a little.
Ex:
No need to use lock here
Just trying to build the source and examples - but using make - get the following error:
johughes@ubuntu:~/Downloads/indicators-master/build$ make
[ 3%] Building CXX object demo/CMakeFiles/demo.dir/demo.cpp.o
/home/johughes/Downloads/indicators-master/demo/demo.cpp:1:10: fatal error: indicators.hpp: No such file or directory
#include "indicators.hpp"
^~~~~~~~~~~~~~~~
compilation terminated.
demo/CMakeFiles/demo.dir/build.make:62: recipe for target 'demo/CMakeFiles/demo.dir/demo.cpp.o' failed
make[2]: *** [demo/CMakeFiles/demo.dir/demo.cpp.o] Error 1
CMakeFiles/Makefile2:85: recipe for target 'demo/CMakeFiles/demo.dir/all' failed
make[1]: *** [demo/CMakeFiles/demo.dir/all] Error 2
Makefile:151: recipe for target 'all' failed
make: *** [all] Error 2
the previous cmake did not report any errors.
In progress bar helper functions, use unicode::display_width
instead of os.str().size()
because prefix_text, postfix_text etc., can have multi-byte unicode characters too.
Could be great to detect the terminal width automatically.
This has answers for Win and POSIX:
https://stackoverflow.com/questions/23369503/get-size-of-terminal-window-rows-columns
This will have many benefits:
I had a hard time with this library after using the progress bar in a second file. The problem is on the following line:
After adding the inline specifier, everything works fine.
The dynamic progress bar uses ANSI escape codes for moving up and erasing lines.
This doesn't work on Windows (and I could not make it work using SetConsoleMode( ENABLE_VIRTUAL_TERMINAL_PROCESSING | ENABLE_VIRTUAL_TERMINAL_INPUT )
either).
I found the following library for go which seems great: https://github.com/k0kubun/go-ansi
The following code works fine on Windows:
namespace cursor
{
void move_up(int lines)
{
move(0, -lines);
}
void move_down(int lines)
{
move(0, -lines);
}
void move_left(int cols)
{
move(-cols, 0);
}
void move_up(int cols)
{
move(cols, 0);
}
void move(int x, int y) {
auto hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
if (!hStdout) return;
CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
GetConsoleScreenBufferInfo(hStdout, &csbiInfo);
COORD cursor;
cursor.X = csbiInfo.dwCursorPosition.X + x;
cursor.Y = csbiInfo.dwCursorPosition.Y + y;
SetConsoleCursorPosition(hStdout, cursor);
}
}
It would be nice to have more abstractions (also around finding the terminal windows size). Do you want to integrate these facilities into this library or should we create another one?
it just say could not open the file
From my understanding calling tick()
method will trigger the print function which will re-print the progress status regardless. Is this correct?
Can I open a PR to update only if something has changed?
indicators/include/indicators/progress_bar.hpp
Lines 112 to 119 in 2291c8c
Example:
C:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\shared\rpcndr.h(192): error C2872: 'byte': ambiguous symbol
C:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\shared\rpcndr.h(191): note: could be 'unsigned char byte'
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29333\include\cstddef(29): note: or 'std::byte'
C:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\shared\rpcndr.h(962): error C2872: 'byte': ambiguous symbol
C:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\shared\rpcndr.h(191): note: could be 'unsigned char byte'
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29333\include\cstddef(29): note: or 'std::byte'
C:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\shared\rpcndr.h(970): error C2872: 'byte': ambiguous symbol
C:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\shared\rpcndr.h(191): note: could be 'unsigned char byte'
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29333\include\cstddef(29): note: or 'std::byte'
C:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\shared\wtypesbase.h(437): error C2872: 'byte': ambiguous symbol
C:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\shared\rpcndr.h(191): note: could be 'unsigned char byte'
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29333\include\cstddef(29): note: or 'std::byte'
C:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\shared\wtypesbase.h(462): error C2872: 'byte': ambiguous symbol
C:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\shared\rpcndr.h(191): note: could be 'unsigned char byte'
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29333\include\cstddef(29): note: or 'std::byte'
C:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\shared\wtypesbase.h(479): error C2872: 'byte': ambiguous symbol
C:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\shared\rpcndr.h(191): note: could be 'unsigned char byte'
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29333\include\cstddef(29): note: or 'std::byte'
And so on...
Currently, I resolved it using this solution: https://stackoverflow.com/questions/45957830/gdipluspath-throws-ambiguous-byte-for-cstddef-and-rpcndr-h
Specifically, the #define byte win_byte_override
and #undef byte
.
But my impression is that this should be solved in the library itself.
While compiling the code from scratch, the compiler complains the following:
In file included from /Libraries/indicators/include/indicators/dynamic_progress.hpp:31,
from /Libraries/indicators/samples/dynamic_progress.cpp:1:
/Libraries/indicators/include/indicators/setting.hpp:199:27: error: ‘vector’ is not a member of ‘std’
199 | details::Setting<std::vector<std::string>, details::ProgressBarOption::spinner_states>;
The easy fix is to add #include <vector>
to setting.hpp
. This worked for me.
Hello!
I use prefix and postfix for my interface
I use about 30 characters for postfix, but it prints 70 or more like this:
-- Info Checksum is correct·········································
My limit is 84 characters.
Why does string length increase with empty characters?
I have the case that for some downloads the total bytes are not advertised by the server. So instead of a regular progress bar I would like to have something going from left to right, e.g.
two frames:
[....<==>.....]
[........<==>.]
etc.
It seems like the version 1.9 got re-tagged after it was published first.
This is a huge problem and causes trust isues.
It breaks package manager like Conan who check downloads against checksums (ref. conan-io/conan-center-index#4135)
and it raises the question of stability and trustworthy. "Is this a bug? Has the project been hacked?"
So please don't do this again. Once a version is tagged it should never be redefined.
mingw-w64-gcc 9.2
windows 10
error info:
indicators/terminal_size.hpp:22:10: fatal error: sys/ioctl.h: No such file or directory
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.