Files
indicators/README.md

335 lines
8.7 KiB
Markdown
Raw Normal View History

2019-12-04 18:32:10 -06:00
<p align="center">
2019-12-04 21:12:12 -06:00
<img height="70" src="img/logo.png"/>
2019-12-04 18:33:06 -06:00
</p>
2019-12-04 19:34:03 -06:00
<p align="center">
2019-12-04 21:10:58 -06:00
<a href="https://github.com/p-ranav/indicators/blob/master/LICENSE">
2019-12-04 19:34:03 -06:00
<img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="license"/>
</a>
2019-12-16 11:00:38 -06:00
<img src="https://img.shields.io/badge/version-1.1-blue.svg?cacheSeconds=2592000" alt="version"/>
2019-12-04 19:34:03 -06:00
</p>
2019-12-04 18:33:06 -06:00
<p align="center">
<img src="img/demo.gif"/>
2019-12-04 18:32:10 -06:00
</p>
2019-12-04 20:01:47 -06:00
# Highlights
2019-12-16 09:48:23 -06:00
* Thread-safe progress bars and spinners
2019-12-04 21:10:58 -06:00
* Header-only library. Grab a copy of `include/indicators`
2019-12-04 20:13:44 -06:00
* Source for the above GIF can be found [here](demo/demo.cpp)
2019-12-04 21:00:44 -06:00
* MIT License
2019-12-04 20:01:47 -06:00
2019-12-04 19:32:32 -06:00
# Progress bar
2019-12-04 21:10:58 -06:00
To introduce a progress bar in your application, include `indicators/progress_bar.hpp` and create a `ProgressBar` object.
```cpp
2019-12-04 21:10:58 -06:00
#include <indicators/progress_bar.hpp>
int main() {
2019-12-04 21:10:58 -06:00
indicators::ProgressBar bar;
// Configure the bar
bar.set_bar_width(50);
bar.start_bar_with("[");
bar.fill_bar_progress_with("=");
bar.lead_bar_progress_with(">");
bar.fill_bar_remainder_with(" ");
bar.end_bar_with("]");
bar.set_postfix_text("Getting started");
2019-12-17 09:33:08 -06:00
bar.set_foreground_color(indicators::Color::GREEN);
2019-12-04 19:51:29 -06:00
// Update bar state
return 0;
}
```
2019-12-16 11:07:16 -06:00
Here's the general structure of a progress bar:
```
2019-12-17 09:37:11 -06:00
{prefix} {start} {fill} {lead} {remaining} {end} {percentage} [{elapsed}<{remaining}?] {postfix}
^^^^^^^^^^^^^ Bar Width ^^^^^^^^^^^^^^^
2019-12-16 11:07:16 -06:00
```
The amount of progress in ProgressBar is maintained as a float in range `[0, 100]`. When progress reaches 100, the progression is complete.
From application-level code, there are two ways in which you can update this progress:
2019-12-04 20:42:30 -06:00
## Update progress using `bar.tick()`
You can update the progress bar using `bar.tick()` which increments progress by exactly `1%`.
```cpp
2019-12-04 21:10:58 -06:00
#include <indicators/progress_bar.hpp>
#include <thread>
#include <chrono>
int main() {
2019-12-04 21:10:58 -06:00
indicators::ProgressBar bar;
// Configure the bar
bar.set_bar_width(50);
bar.start_bar_with("[");
bar.fill_bar_progress_with("=");
bar.lead_bar_progress_with(">");
bar.fill_bar_remainder_with(" ");
bar.end_bar_with("]");
bar.set_postfix_text("Getting started");
2019-12-04 21:10:58 -06:00
bar.set_foreground_color(indicators::Color::GREEN);
// Update bar state
while (true) {
bar.tick();
if (bar.is_completed())
break;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
return 0;
}
```
The above code will print a progress bar that goes from 0 to 100% at the rate of 1% every 100 ms.
2019-12-04 19:32:32 -06:00
## Updating progress using `bar.set_progress(value)`
If you'd rather control progress of the bar in discrete steps, consider using `bar.set_progress(value)`. Example:
```cpp
2019-12-04 21:10:58 -06:00
#include <indicators/progress_bar.hpp>
#include <thread>
#include <chrono>
int main() {
2019-12-04 21:10:58 -06:00
indicators::ProgressBar bar;
// Configure the bar
bar.set_bar_width(50);
bar.start_bar_with("[");
bar.fill_bar_progress_with("=");
bar.lead_bar_progress_with(">");
bar.fill_bar_remainder_with(" ");
bar.end_bar_with("]");
bar.set_postfix_text("Getting started");
2019-12-04 21:10:58 -06:00
bar.set_foreground_color(indicators::Color::GREEN);
// Update bar state
2019-12-05 15:55:55 -06:00
bar.set_progress(10); // 10% done
// do some work
std::this_thread::sleep_for(std::chrono::milliseconds(100));
bar.set_progress(30); // 30% done
// do some more work
std::this_thread::sleep_for(std::chrono::milliseconds(600));
bar.set_progress(65); // 65% done
// do final bit of work
std::this_thread::sleep_for(std::chrono::milliseconds(300));
bar.set_progress(100); // all done
return 0;
}
```
2019-12-04 19:32:32 -06:00
## Multi-threaded Example
2019-12-04 19:25:15 -06:00
```cpp
2019-12-04 21:10:58 -06:00
#include <indicators/progress_bar.hpp>
2019-12-04 19:25:15 -06:00
#include <vector>
int main() {
2019-12-04 21:10:58 -06:00
indicators::ProgressBar bar;
2019-12-04 19:25:15 -06:00
bar.set_bar_width(50);
bar.start_bar_with("[");
bar.fill_bar_progress_with("■");
bar.lead_bar_progress_with("■");
bar.fill_bar_remainder_with("-");
bar.end_bar_with("]");
2019-12-04 21:10:58 -06:00
bar.set_foreground_color(indicators::Color::YELLOW);
2019-12-04 19:25:15 -06:00
// As configured, the bar will look like this:
//
// [■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■-------------] 70%
//
//
std::atomic<size_t> index{0};
std::vector<std::string> status_text =
{
"Rocket.exe is not responding",
"Finding a replacement engineer",
"Buying more snacks",
"Assimilating the modding community",
"Crossing fingers",
"Porting KSP to a Nokia 3310"
};
// Let's say you want to append some status text to the right of the progress bar
// You can use bar.set_postfix_text(...) to append text to the right
//
// [■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■-------------] 70% Finding a replacement engineer
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//
//
auto job = [&bar, &index, &status_text]() {
while (true) {
if (bar.is_completed()) {
break;
}
bar.set_postfix_text(status_text[index % status_text.size()]);
bar.tick();
index += 1;
2019-12-04 19:30:38 -06:00
std::this_thread::sleep_for(std::chrono::milliseconds(200));
2019-12-04 19:25:15 -06:00
}
};
std::thread first_job(job);
std::thread second_job(job);
std::thread third_job(job);
std::thread last_job(job);
first_job.join();
second_job.join();
third_job.join();
last_job.join();
return 0;
}
```
2019-12-04 19:28:49 -06:00
2019-12-17 09:48:36 -06:00
## Showing Time Elapsed/Remaining
All progress bars and spinners in `indicators` support showing time elapsed and time remaining. Inspired by python's [tqdm](https://github.com/tqdm/tqdm) module, the format of this meter is as follows:
```bash
[{elapsed}<{remaining}]
```
Below is an example for configuring this meter:
```cpp
```
2019-12-16 10:53:53 -06:00
# Block Progress Bar
2019-12-16 09:26:49 -06:00
2019-12-16 09:29:19 -06:00
Are you in need of a smooth block progress bar using [unicode block elements](https://en.wikipedia.org/wiki/Block_Elements)? Use `BlockProgressBar` instead of `ProgressBar`. Thanks to [this blog post](https://mike42.me/blog/2018-06-make-better-cli-progress-bars-with-unicode-block-characters) for making `BlockProgressBar` an easy addition to the library.
2019-12-16 09:26:49 -06:00
<p align="center">
2019-12-16 10:22:14 -06:00
<img src="img/block_progress_bar.gif"/>
2019-12-16 09:26:49 -06:00
</p>
```cpp
2019-12-16 09:31:10 -06:00
#include <indicators/block_progress_bar.hpp>
#include <thread>
#include <chrono>
int main() {
// Hide cursor
std::cout << "\e[?25l";
2019-12-16 09:26:49 -06:00
indicators::BlockProgressBar bar;
// Configure the bar
bar.set_bar_width(80);
bar.start_bar_with("[");
bar.end_bar_with("]");
bar.set_foreground_color(indicators::Color::WHITE);
// Update bar state
auto progress = 0.0f;
while (true) {
bar.set_progress(progress);
progress += 0.25f;
if (bar.is_completed())
break;
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
2019-12-16 09:31:10 -06:00
// Show cursor
std::cout << "\e[?25h";
return 0;
}
2019-12-16 09:26:49 -06:00
```
2019-12-04 19:51:29 -06:00
# Progress Spinner
2019-12-04 21:10:58 -06:00
To introduce a progress spinner in your application, include `indicators/progress_spinner.hpp` and create a `ProgressSpinner` object.
2019-12-04 19:51:29 -06:00
```cpp
2019-12-04 21:10:58 -06:00
#include <indicators/progress_spinner.hpp>
2019-12-04 19:51:29 -06:00
int main() {
2019-12-04 21:10:58 -06:00
indicators::ProgressSpinner spinner;
2019-12-04 19:51:29 -06:00
// Configure the spinner
spinner.set_prefix_text(" ");
spinner.set_postfix_text("Checking credentials");
2019-12-04 21:10:58 -06:00
spinner.set_foreground_color(indicators::Color::YELLOW);
2019-12-04 19:51:29 -06:00
spinner.set_spinner_states({"⠈", "⠐", "⠠", "⢀", "⡀", "⠄", "⠂", "⠁"});
// Update spinner state
return 0;
}
```
2019-12-16 11:07:16 -06:00
Here's the general structure of a progress spinner:
```
2019-12-17 09:37:11 -06:00
{prefix} {spinner} {percentage} [{elapsed}<{remaining}] {postfix}
2019-12-16 11:07:16 -06:00
```
2019-12-04 19:52:33 -06:00
ProgressSpinner has a vector of strings: `spinner_states`. At each update, the spinner will pick the next string from this sequence to print to the console. The spinner state can be updated similarly to ProgressBars: Using either `tick()` or `set_progress(value)`.
2019-12-04 19:51:29 -06:00
```cpp
2019-12-04 21:10:58 -06:00
#include <indicators/progress_spinner.hpp>
2019-12-04 19:51:29 -06:00
int main() {
2019-12-04 21:10:58 -06:00
indicators::ProgressSpinner spinner;
2019-12-04 19:51:29 -06:00
// Configure the spinner
spinner.set_postfix_text("Checking credentials");
2019-12-04 21:10:58 -06:00
spinner.set_foreground_color(indicators::Color::YELLOW);
2019-12-04 19:51:29 -06:00
spinner.set_spinner_states({"⠈", "⠐", "⠠", "⢀", "⡀", "⠄", "⠂", "⠁"});
// Update spinner state
auto job = [&spinner]() {
while (true) {
if (spinner.is_completed()) {
2019-12-04 21:10:58 -06:00
spinner.set_foreground_color(indicators::Color::GREEN);
2019-12-04 19:51:29 -06:00
spinner.set_prefix_text("✔");
spinner.hide_spinner();
spinner.hide_percentage();
spinner.set_postfix_text("Authenticated!");
2019-12-17 09:33:08 -06:00
spinner.mark_as_completed();
2019-12-04 19:51:29 -06:00
break;
} else
spinner.tick();
std::this_thread::sleep_for(std::chrono::milliseconds(40));
}
};
std::thread thread(job);
thread.join();
return 0;
}
```
2019-12-04 19:58:25 -06:00
## Contributing
Contributions are welcome, have a look at the [CONTRIBUTING.md](CONTRIBUTING.md) document for more information.
## License
The project is available under the [MIT](https://opensource.org/licenses/MIT) license.