54 Commits
v1.7 ... v1.8

Author SHA1 Message Date
Pranav
695fac00b4 Update README.md 2020-05-13 15:42:26 -05:00
Pranav Srinivas Kumar
17e1f47fd4 Added amalgamate to help generate single header for indicators 2020-05-13 15:39:20 -05:00
Pranav Srinivas Kumar
a1ad525065 Updated single header file version of indicators
* Added IndeterminateProgressBar
* Added `Color::unspecified` enum field
* Added `option::MaxProgress` and `option::Stream`
2020-05-09 21:41:57 -05:00
Pranav Srinivas Kumar
ad6cddbd0e Updated iterable sample GIF 2020-05-09 21:01:23 -05:00
Pranav Srinivas Kumar
b389f5e559 Updated iterable sample GIF 2020-05-09 20:58:41 -05:00
Pranav Srinivas Kumar
04cdd25844 Added sample to show max_progress working with iterables. Updated README 2020-05-09 20:54:32 -05:00
Pranav
e463046745 Update README.md 2020-05-09 20:39:40 -05:00
Pranav
3a798551ba Update README.md 2020-05-09 20:37:20 -05:00
Pranav
26c4c0286e Merge pull request #52 from p-ranav/feature/43
Closes #22
2020-05-09 20:36:09 -05:00
Pranav
5972b18450 Update README.md 2020-05-09 20:35:07 -05:00
Pranav Srinivas Kumar
6f057a51a1 Closes #22 2020-05-09 20:33:15 -05:00
Pranav Srinivas Kumar
b215cb850e Added functions to retrieve terminal width 2020-05-08 18:09:08 -05:00
Pranav
e950065e34 Merge pull request #51 from p-ranav/feature/43
Feature/43
2020-05-08 17:28:47 -05:00
Pranav
643e5ce6a1 Update README.md 2020-05-08 17:25:50 -05:00
Pranav Srinivas Kumar
11ec12c0cb Added indeterminate progress bar demo GIF 2020-05-08 17:23:21 -05:00
Pranav Srinivas Kumar
d2179d75ce Updated sample for indeterminate_progress_bar and added demo GIF 2020-05-08 17:18:00 -05:00
Pranav Srinivas Kumar
6d73795218 Implemented indeterminate progress bar w/ sample 2020-05-08 17:13:28 -05:00
Pranav Srinivas Kumar
6857345da5 Initial commit 2020-05-08 16:30:47 -05:00
Pranav Srinivas Kumar
3800785216 Updated dynamic progress bar GIF 2020-05-08 16:19:13 -05:00
Pranav Srinivas Kumar
a949efd512 Removed unnecessary mark_as_completed in set_progress sample 2020-05-08 15:23:01 -05:00
Pranav Srinivas Kumar
296bde6088 Minor bug fixes and updates:
* Removed progress bar sample that progresses in reverse direction - This needs a class of its own
* Fixed a casting error in progress_bar class when dealing with max_progress variable
* Minor update to the cursor movement functions in linux
* Updated single include to include these changes
2020-05-08 15:14:52 -05:00
Pranav
66af25ab62 Merge pull request #50 from godbyk/feature/adjustable-tick-size
Add a MaxProgress option (default: 100).
2020-05-02 18:45:30 -05:00
Kevin M. Godby
371bcb2c3b Add a MaxProgress option (default: 100).
The MaxProgress option allows you to set the maximum number of ticks
that are within a progress bar. Each call to tick() increments the tick
count. The progress bar percentage is the number of ticks divided by the
MaxProgress option.

The default MaxProgress is 100, so each tick would be 1%.  If
MaxProgress is set to 500, for example, then each tick would be 0.2%.
2020-04-30 21:37:06 -05:00
Pranav
df4a97b068 Merge pull request #49 from godbyk/bugfix/cmake-homepage-url
Support versions of CMake going back to version 3.8.
2020-04-30 17:59:10 -07:00
Kevin M. Godby
55494a572b Support version of CMake going back to version 3.8.
The DESCRIPTION parameter of the project() command was introduced in
CMake version 3.9.

The HOMEPAGE_URL parameter was introduced in CMake version 3.11.
2020-04-30 19:24:17 -05:00
Pranav
3d1d01ba0d Merge pull request #48 from motis-project/win-cursor-mv
Abstraction for Cursor Movements (Issue #46)
2020-04-26 10:28:57 -07:00
Felix Gündling
c2beb2ac22 adjust readme, demo, and examples: replace show/hide cursor calls 2020-04-26 18:52:23 +02:00
Felix Gündling
d99cad1ede setting console mode to processed output not neccesary if we use SetConsoleCursorPosition 2020-04-25 08:57:32 +02:00
Felix Gündling
ad5cf841be cursor movement and cursor hiding support for windows 2020-04-25 08:49:30 +02:00
Pranav Srinivas Kumar
4aef1470f1 Showing [00:00<00:00] if start time is not saved yet #45 2020-04-15 10:18:28 -05:00
Pranav Srinivas Kumar
dd08556b27 Fixed typo 2020-04-06 11:51:19 -07:00
Pranav
57a942f392 Merge pull request #40 from p-ranav/feature/font_styles
Feature/font styles
2020-04-06 11:49:27 -07:00
Pranav Srinivas Kumar
78a98fec4d Minor updates 2020-04-06 11:48:16 -07:00
Pranav Srinivas Kumar
06414bb6db Resolved merge conflicts 2020-04-06 11:46:53 -07:00
Pranav Srinivas Kumar
cd6dc2aebf Fixed merge conflict 2020-04-06 11:43:20 -07:00
Pranav Srinivas Kumar
446b0d3147 Recovered CMakeLists 2020-04-06 11:41:18 -07:00
Pranav Srinivas Kumar
a3e50e0862 Updated single include 2020-04-06 11:35:10 -07:00
Pranav
936b8e66d8 Update README.md 2020-04-06 13:30:57 -05:00
Pranav Srinivas Kumar
16d3484788 Fixed build 2020-04-06 11:25:54 -07:00
Pranav Srinivas Kumar
833e1cd6db Initial commit 2020-04-06 11:10:41 -07:00
Pranav Srinivas Kumar
07b9eede8a Minor updates to support FontStyles 2020-04-06 11:05:44 -07:00
Pranav
562cb80a36 Merge pull request #38 from wolfv/add_color_unspecified
remove bold output and default color to unspecified
2020-04-06 11:05:31 -07:00
Wolf Vollprecht
7e43298470 remove bold output and default color to unspecified 2020-04-06 19:05:11 +02:00
Pranav
fd21e7d81f Closes #36 2020-04-03 16:02:31 -05:00
Pranav
37b3fc395e Merge pull request #35 from LesleyLai/master
fix MSVC unused parameter warning
2020-03-04 04:58:21 -06:00
Lesley
99f4f3f05b fix MSVC unused parameter warning 2020-03-03 22:02:11 -07:00
Pranav
5a9419b191 Update README.md 2020-02-24 16:37:13 +05:30
Pranav
4ada9e3f77 Update README.md 2020-02-24 16:36:39 +05:30
Pranav
8ad116cc5f Update README.md 2020-02-24 16:34:06 +05:30
Pranav
4b1ce0d2f7 Update README.md 2020-02-23 20:32:41 +05:30
Pranav
3fb4eb9dd1 Update README.md 2020-02-22 11:20:13 +05:30
Pranav
0e041e8fea Merge pull request #33 from p-ranav/bugfix/25
Change progress_ to size_t
2020-02-22 11:16:41 +05:30
Pranav Srinivas Kumar
201ce9c4fb Bumped to v1.8 2020-02-22 11:13:04 +05:30
Pranav Srinivas Kumar
d4a38eb034 Closes 25 - Changed to 2020-02-22 11:02:16 +05:30
41 changed files with 2830 additions and 664 deletions

View File

@@ -4,9 +4,16 @@ if(DEFINED PROJECT_NAME)
set(INDICATORS_SUBPROJECT ON)
endif()
project(indicators VERSION 1.7.0 LANGUAGES CXX
HOMEPAGE_URL "https://github.com/p-ranav/indicators"
DESCRIPTION "Activity Indicators for Modern C++")
if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.12")
project(indicators VERSION 1.8.0 LANGUAGES CXX
HOMEPAGE_URL "https://github.com/p-ranav/indicators"
DESCRIPTION "Activity Indicators for Modern C++")
elseif(CMAKE_VERSION VERSION_GREATER_EQUAL "3.9")
project(indicators VERSION 1.8.0 LANGUAGES CXX
DESCRIPTION "Activity Indicators for Modern C++")
else()
project(indicators VERSION 1.8.0 LANGUAGES CXX)
endif()
if(EXISTS "${CMAKE_BINARY_DIR}/conanbuildinfo.cmake")
include("${CMAKE_BINARY_DIR}/conanbuildinfo.cmake")

243
README.md
View File

@@ -12,39 +12,37 @@
<a href="https://github.com/p-ranav/indicators/blob/master/LICENSE">
<img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="license"/>
</a>
<img src="https://img.shields.io/badge/version-1.7-blue.svg?cacheSeconds=2592000" alt="version"/>
<img src="https://img.shields.io/badge/version-1.8-blue.svg?cacheSeconds=2592000" alt="version"/>
</p>
<p align="center">
<img src="img/demo.gif"/>
</p>
# Highlights
## Highlights
* Thread-safe progress bars and spinners
* Header-only library. Grab a copy of `include/indicators`
* Header-only library. Grab a copy of `include/indicators`.
* Single-header version in `single_include/indicators`.
* Source for the above GIF can be found [here](demo/demo.cpp)
* MIT License
```bash
git clone https://github.com/p-ranav/indicators
cd indicators
mkdir build && cd build
cmake -DINDICATORS_SAMPLES=ON -DINDICATORS_DEMO=ON ..
make
```
## Table of Contents
# Table of Contents
* Supported Indicators
* [Basic Progress Bar](#basic-progress-bar)
* [Indeterminate Progress Bar](#indeterminate-progress-bar)
* [Block Progress Bar](#block-progress-bar)
* [Multi Progress](#multiprogress)
* [Dynamic Progress](#dynamicprogress)
* [Progress Spinner](#progress-spinner)
* [Working with Iterables](#working-with-iterables)
* [Building Samples](#building-samples)
* [Generating Single Header](#generating-single-header)
* [Contributing](#contributing)
* [License](#license)
* [Progress Bar](#progress-bar)
* [Block Progress Bar](#block-progress-bar)
* [Multi Progress](#multiprogress)
* [Dynamic Progress](#dynamicprogress)
* [Progress Spinner](#progress-spinner)
* [Contributing](#contributing)
* [License](#license)
# Progress bar
## Basic Progress bar
To introduce a progress bar in your application, include `indicators/progress_bar.hpp` and create a `ProgressBar` object. Here's the general structure of a progress bar:
@@ -53,11 +51,11 @@ To introduce a progress bar in your application, include `indicators/progress_ba
^^^^^^^^^^^^^ Bar Width ^^^^^^^^^^^^^^^
```
The amount of progress in ProgressBar is maintained as a float in range `[0, 100]`. When progress reaches 100, the progression is complete.
The amount of progress in ProgressBar is maintained as a `size_t` 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:
## Update progress using `bar.tick()`
### Update progress using `bar.tick()`
You can update the progress bar using `bar.tick()` which increments progress by exactly `1%`.
@@ -80,7 +78,8 @@ int main() {
option::Remainder{" "},
option::End{"]"},
option::PostfixText{"Extracting Archive"},
option::ForegroundColor{Color::green}
option::ForegroundColor{Color::green},
option::FontStyles{std::vector<FontStyle>{FontStyle::bold}}
};
// Update bar state
@@ -97,7 +96,7 @@ int main() {
The above code will print a progress bar that goes from 0 to 100% at the rate of 1% every 100 ms.
## Updating progress using `bar.set_progress(value)`
### 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:
@@ -108,14 +107,16 @@ If you'd rather control progress of the bar in discrete steps, consider using `b
```cpp
#include <chrono>
#include <indicators/cursor_control.hpp>
#include <indicators/progress_bar.hpp>
#include <thread>
int main() {
using namespace indicators;
// Hide cursor
std::cout << "\e[?25l";
using namespace indicators;
show_console_cursor(false);
ProgressBar bar{
option::BarWidth{50},
option::Start{"["},
@@ -124,7 +125,8 @@ int main() {
option::Remainder{"-"},
option::End{" ]"},
option::PostfixText{"Loading dependency 1/4"},
option::ForegroundColor{Color::cyan}
option::ForegroundColor{Color::cyan},
option::FontStyles{std::vector<FontStyle>{FontStyle::bold}}
};
// Update bar state
@@ -151,16 +153,14 @@ int main() {
bar.set_progress(100); // all done
bar.mark_as_completed();
// Show cursor
std::cout << "\e[?25h";
show_console_cursor(true);
return 0;
}
```
## Showing Time Elapsed/Remaining
### 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 `[{elapsed}<{remaining}]`:
@@ -170,11 +170,16 @@ All progress bars and spinners in `indicators` support showing time elapsed and
```cpp
#include <chrono>
#include <indicators/cursor_control.hpp>
#include <indicators/progress_bar.hpp>
#include <thread>
int main() {
using namespace indicators;
// Hide cursor
show_console_cursor(false);
indicators::ProgressBar bar{
option::BarWidth{50},
option::Start{" ["},
@@ -185,7 +190,8 @@ int main() {
option::PrefixText{"Training Gaze Network 👀"},
option::ForegroundColor{Color::yellow},
option::ShowElapsedTime{true},
option::ShowRemainingTime{true}
option::ShowRemainingTime{true},
option::FontStyles{std::vector<FontStyle>{FontStyle::bold}}
};
// Update bar state
@@ -197,13 +203,68 @@ int main() {
}
// Show cursor
std::cout << "\e[?25h";
show_console_cursor(true);
return 0;
}
```
# Block Progress Bar
## Indeterminate Progress Bar
You might have a use-case for a progress bar where the maximum amount of progress is unknown, e.g., you're downloading from a remote server that isn't advertising the total bytes.
Use an `indicators::IndeterminateProgressBar` for such cases. An `IndeterminateProgressBar` is similar to a regular progress bar except the total amount to progress towards is unknown. Ticking on this progress bar will happily run forever.
When you know progress is complete, simply call `bar.mark_as_completed()`.
<p align="center">
<img src="img/indeterminate_progress_bar.gif"/>
</p>
```cpp
#include <chrono>
#include <indicators/indeterminate_progress_bar.hpp>
#include <indicators/cursor_control.hpp>
#include <indicators/termcolor.hpp>
#include <thread>
int main() {
indicators::IndeterminateProgressBar bar{
indicators::option::BarWidth{40},
indicators::option::Start{"["},
indicators::option::Fill{"·"},
indicators::option::Lead{"<==>"},
indicators::option::End{"]"},
indicators::option::PostfixText{"Checking for Updates"},
indicators::option::ForegroundColor{indicators::Color::yellow},
indicators::option::FontStyles{
std::vector<indicators::FontStyle>{indicators::FontStyle::bold}}
};
indicators::show_console_cursor(false);
auto job = [&bar]() {
std::this_thread::sleep_for(std::chrono::milliseconds(10000));
bar.mark_as_completed();
std::cout << termcolor::bold << termcolor::green
<< "System is up to date!\n" << termcolor::reset;
};
std::thread job_completion_thread(job);
// Update bar state
while (!bar.is_completed()) {
bar.tick();
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
job_completion_thread.join();
indicators::show_console_cursor(true);
return 0;
}
```
## Block Progress Bar
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.
@@ -218,15 +279,17 @@ Are you in need of a smooth block progress bar using [unicode block elements](ht
int main() {
// Hide cursor
std::cout << "\e[?25l";
using namespace indicators;
// Hide cursor
show_console_cursor(false);
BlockProgressBar bar{
option::BarWidth{80},
option::Start{"["},
option::End{"]"},
option::ForegroundColor{Color::white}
option::ForegroundColor{Color::white} ,
option::FontStyles{std::vector<FontStyle>{FontStyle::bold}}
};
// Update bar state
@@ -240,18 +303,20 @@ int main() {
}
// Show cursor
std::cout << "\e[?25h";
show_console_cursor(true);
return 0;
}
```
# MultiProgress
## MultiProgress
`indicators` supports management of multiple progress bars with the `MultiProgress` class template.
`template <typename Indicator, size_t count> class MultiProgress` is a class template that holds references to multiple progress bars and provides a safe interface to update the state of each bar. `MultiProgress` works with both `ProgressBar` and `BlockProgressBar` classes.
Use this class if you know the number of progress bars to manage at compile time.
Below is an example `MultiProgress` object that manages three `ProgressBar` objects.
<p align="center">
@@ -275,7 +340,8 @@ int main() {
option::ForegroundColor{Color::yellow},
option::ShowElapsedTime{true},
option::ShowRemainingTime{true},
option::PrefixText{"Progress Bar #1 "}
option::PrefixText{"Progress Bar #1 "},
option::FontStyles{std::vector<FontStyle>{FontStyle::bold}}
};
// Configure second progress bar
@@ -290,7 +356,8 @@ int main() {
option::ForegroundColor{Color::cyan},
option::ShowElapsedTime{true},
option::ShowRemainingTime{true},
option::PrefixText{"Progress Bar #2 "}
option::PrefixText{"Progress Bar #2 "},
option::FontStyles{std::vector<FontStyle>{FontStyle::bold}}
};
// Configure third progress bar
@@ -304,7 +371,8 @@ int main() {
option::ForegroundColor{Color::red},
option::ShowElapsedTime{true},
option::ShowRemainingTime{true},
option::PrefixText{"Progress Bar #3 "}
option::PrefixText{"Progress Bar #3 "},
option::FontStyles{std::vector<FontStyle>{FontStyle::bold}}
};
// Construct MultiProgress object
@@ -351,9 +419,13 @@ int main() {
}
```
# DynamicProgress
## DynamicProgress
`DynamicProgress` is a container class, similar to `MultiProgress`, for managing multiple progress bars. As the name suggests, with `DynamicProgress`, you can dynamically add new progress bars. Simply call `bars.push_back`.
`DynamicProgress` is a container class, similar to `MultiProgress`, for managing multiple progress bars. As the name suggests, with `DynamicProgress`, you can dynamically add new progress bars.
To add new progress bars, call `bars.push_back(new_bar)`. This call will return the index of the appended bar. You can then refer to this bar with the indexing operator, e.g., `bars[4].set_progress(55)`.
Use this class if you don't know the number of progress bars at compile time.
Below is an example `DynamicProgress` object that manages six `ProgressBar` objects. Three of these bars are added dynamically.
@@ -504,7 +576,7 @@ In the above code, notice the option `bars.set_option(option::HideBarWhenComplet
<img src="img/dynamic_progress_bar_hide_completed.gif"/>
</p>
# Progress Spinner
## Progress Spinner
To introduce a progress spinner in your application, include `indicators/progress_spinner.hpp` and create a `ProgressSpinner` object. Here's the general structure of a progress spinner:
@@ -526,7 +598,8 @@ int main() {
indicators::ProgressSpinner spinner{
option::PostfixText{"Checking credentials"},
option::ForegroundColor{Color::yellow},
option::SpinnerStates{std::vector<std::string>{"", "", "", "", "", "", "", ""}}
option::SpinnerStates{std::vector<std::string>{"", "", "", "", "", "", "", ""}},
option::FontStyles{std::vector<FontStyle>{FontStyle::bold}}
};
// Update spinner state
@@ -552,6 +625,84 @@ int main() {
}
```
## Working with Iterables
If you'd like to use progress bars to indicate progress while iterating over iterables, e.g., a list of numbers, this
can be achieved by using the `option::MaxProgress`:
<p align="center">
<img src="img/block_progress_bar_iterable.gif"/>
</p>
```cpp
#include <chrono>
#include <indicators/block_progress_bar.hpp>
#include <indicators/cursor_control.hpp>
#include <thread>
int main() {
// Hide cursor
indicators::show_console_cursor(false);
// Random list of numbers
std::vector<size_t> numbers;
for (size_t i = 0; i < 1259438; ++i) {
numbers.push_back(i);
}
using namespace indicators;
BlockProgressBar bar{
option::BarWidth{80},
option::ForegroundColor{Color::white},
option::FontStyles{
std::vector<FontStyle>{FontStyle::bold}},
option::MaxProgress{numbers.size()}
};
std::cout << "Iterating over a list of numbers (size = "
<< numbers.size() << ")\n";
std::vector<size_t> result;
for (size_t i = 0; i < numbers.size(); ++i) {
// Perform some computation
result.push_back(numbers[i] * numbers[i]);
// Show iteration as postfix text
bar.set_option(option::PostfixText{
std::to_string(i) + "/" + std::to_string(numbers.size())
});
// update progress bar
bar.tick();
}
bar.mark_as_completed();
// Show cursor
indicators::show_console_cursor(true);
return 0;
}
```
## Building Samples
```bash
git clone https://github.com/p-ranav/indicators
cd indicators
mkdir build && cd build
cmake -DINDICATORS_SAMPLES=ON -DINDICATORS_DEMO=ON ..
make
```
## Generating Single Header
```bash
python3 utils/amalgamate/amalgamate.py -c single_include.json -s .
```
## Contributing
Contributions are welcome, have a look at the [CONTRIBUTING.md](CONTRIBUTING.md) document for more information.

View File

@@ -1,12 +1,12 @@
#include <indicators/progress_bar.hpp>
#include <indicators/progress_spinner.hpp>
#include "indicators.hpp"
#include <vector>
int main() {
using namespace indicators;
// Hide cursor
std::cout << "\e[?25l";
using namespace indicators;
show_console_cursor(false);
{
//
// PROGRESS BAR 1
@@ -17,7 +17,9 @@ int main() {
option::Lead{""},
option::Remainder{" "},
option::End{" ]"},
option::ForegroundColor{indicators::Color::yellow}};
option::ForegroundColor{indicators::Color::yellow},
option::FontStyles{
std::vector<indicators::FontStyle>{indicators::FontStyle::bold}}};
std::atomic<size_t> index{0};
std::vector<std::string> status_text = {"Rocket.exe is not responding",
@@ -58,6 +60,7 @@ int main() {
p.set_option(option::End{""});
p.set_option(option::ForegroundColor{indicators::Color::white});
p.set_option(option::ShowPercentage{false});
p.set_option(option::FontStyles{std::vector<indicators::FontStyle>{indicators::FontStyle::bold}});
auto job = [&p]() {
while (true) {
p.set_option(
@@ -88,6 +91,7 @@ int main() {
p.set_option(option::End{"]"});
p.set_option(option::PostfixText{"Getting started"});
p.set_option(option::ForegroundColor{indicators::Color::green});
p.set_option(option::FontStyles{std::vector<indicators::FontStyle>{indicators::FontStyle::bold}});
auto job = [&p]() {
while (true) {
auto ticks = p.current();
@@ -124,6 +128,7 @@ int main() {
p4.set_option(option::ForegroundColor{indicators::Color::cyan});
p4.set_option(option::PostfixText{"Restoring system state"});
p4.set_option(option::ShowPercentage{false});
p4.set_option(option::FontStyles{std::vector<indicators::FontStyle>{indicators::FontStyle::bold}});
std::atomic<size_t> index4{0};
auto job4 = [&p4, &index4, &lead_spinner]() {
while (true) {
@@ -151,36 +156,6 @@ int main() {
thread4.join();
std::this_thread::sleep_for(std::chrono::milliseconds(100));
{
//
// GOING BACKWARDS
//
indicators::ProgressBar p{option::BarWidth{50},
option::Start{"["},
option::Fill{""},
option::Lead{""},
option::Remainder{"-"},
option::End{"]"},
option::ForegroundColor{indicators::Color::white},
option::PostfixText{"Reverting system restore"}};
p.set_progress(100); // TODO backwards as an option?
std::atomic<size_t> progress{100};
auto job = [&p, &progress]() {
while (true) {
progress -= 1;
p.set_progress(progress);
if (progress == 0) {
p.set_option(option::PostfixText{"Revert complete!"});
p.mark_as_completed();
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(60));
}
};
std::thread thread(job);
thread.join();
}
}
{
@@ -190,7 +165,8 @@ int main() {
indicators::ProgressSpinner p{
option::PrefixText{""}, option::PostfixText{"Checking credentials"},
option::ForegroundColor{indicators::Color::yellow},
option::SpinnerStates{std::vector<std::string>{"", "", "", "", "", "", "", ""}}};
option::SpinnerStates{std::vector<std::string>{"", "", "", "", "", "", "", ""}},
option::FontStyles{std::vector<indicators::FontStyle>{indicators::FontStyle::bold}}};
auto job = [&p]() {
while (true) {
@@ -219,7 +195,8 @@ int main() {
indicators::ProgressSpinner p{
option::PrefixText{" - "}, option::PostfixText{"Searching for the Moon"},
option::ForegroundColor{indicators::Color::white}, option::ShowPercentage{false},
option::SpinnerStates{std::vector<std::string>{"", "", "", ""}}};
option::SpinnerStates{std::vector<std::string>{"", "", "", ""}},
option::FontStyles{std::vector<indicators::FontStyle>{indicators::FontStyle::bold}}};
auto job = [&p]() {
while (true) {
auto current = p.current();
@@ -263,7 +240,9 @@ int main() {
option::Remainder{" "},
option::End{"🌑"},
option::PostfixText{"Achieved low-Earth orbit"},
option::ForegroundColor{indicators::Color::white}};
option::ForegroundColor{indicators::Color::white},
option::FontStyles{
std::vector<indicators::FontStyle>{indicators::FontStyle::bold}}};
std::vector<std::string> ship_trail{"", "", "", "", "", "", "", ""};
std::atomic<int> ship_trail_index{0};
auto job2 = [&p2, &ship_trail_index, &ship_trail]() {
@@ -301,7 +280,7 @@ int main() {
}
// Show cursor
std::cout << "\e[?25h";
show_console_cursor(true);
return 0;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 MiB

After

Width:  |  Height:  |  Size: 221 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 MiB

After

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

View File

@@ -1,29 +1,3 @@
/*
Activity Indicators for Modern C++
https://github.com/p-ranav/indicators
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
SPDX-License-Identifier: MIT
Copyright (c) 2019 Pranav Srinivas Kumar <pranav.srinivas.kumar@gmail.com>.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
#include <indicators/color.hpp>
@@ -46,7 +20,8 @@ class BlockProgressBar {
using Settings = std::tuple<option::ForegroundColor, option::BarWidth, option::Start, option::End,
option::PrefixText, option::PostfixText, option::ShowPercentage,
option::ShowElapsedTime, option::ShowRemainingTime, option::Completed,
option::SavedStartTime, option::MaxPostfixTextLen>;
option::SavedStartTime, option::MaxPostfixTextLen, option::FontStyles,
option::MaxProgress, option::Stream>;
public:
template <typename... Args,
@@ -55,7 +30,7 @@ public:
void *>::type = nullptr>
explicit BlockProgressBar(Args &&... args)
: settings_(details::get<details::ProgressBarOption::foreground_color>(
option::ForegroundColor{Color::white}, std::forward<Args>(args)...),
option::ForegroundColor{Color::unspecified}, std::forward<Args>(args)...),
details::get<details::ProgressBarOption::bar_width>(option::BarWidth{100},
std::forward<Args>(args)...),
details::get<details::ProgressBarOption::start>(option::Start{"["},
@@ -77,7 +52,14 @@ public:
details::get<details::ProgressBarOption::saved_start_time>(
option::SavedStartTime{false}, std::forward<Args>(args)...),
details::get<details::ProgressBarOption::max_postfix_text_len>(
option::MaxPostfixTextLen{0}, std::forward<Args>(args)...)) {}
option::MaxPostfixTextLen{0}, std::forward<Args>(args)...),
details::get<details::ProgressBarOption::font_styles>(
option::FontStyles{std::vector<FontStyle>{}}, std::forward<Args>(args)...),
details::get<details::ProgressBarOption::max_progress>(option::MaxProgress{100},
std::forward<Args>(args)...),
details::get<details::ProgressBarOption::stream>(
option::Stream{std::cout}, std::forward<Args>(args)...)
) {}
template <typename T, details::ProgressBarOption id>
void set_option(details::Setting<T, id> &&setting) {
@@ -136,7 +118,7 @@ public:
size_t current() {
std::lock_guard<std::mutex> lock{mutex_};
return std::min(static_cast<size_t>(progress_), size_t(100));
return std::min(static_cast<size_t>(progress_), size_t(get_value<details::ProgressBarOption::max_progress>()));
}
bool is_completed() const { return get_value<details::ProgressBarOption::completed>(); }
@@ -177,63 +159,84 @@ private:
}
}
public:
void print_progress(bool from_multi_progress = false) {
std::lock_guard<std::mutex> lock{mutex_};
auto& os = get_value<details::ProgressBarOption::stream>();
const auto max_progress = get_value<details::ProgressBarOption::max_progress>();
if (multi_progress_mode_ && !from_multi_progress) {
if (progress_ > 100.0) {
if (progress_ > max_progress) {
get_value<details::ProgressBarOption::completed>() = true;
}
return;
}
std::lock_guard<std::mutex> lock{mutex_};
auto now = std::chrono::high_resolution_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(now - start_time_point_);
std::cout << termcolor::bold;
details::set_stream_color(std::cout, get_value<details::ProgressBarOption::foreground_color>());
std::cout << get_value<details::ProgressBarOption::prefix_text>();
std::cout << get_value<details::ProgressBarOption::start>();
if (get_value<details::ProgressBarOption::foreground_color>() != Color::unspecified)
details::set_stream_color(os, get_value<details::ProgressBarOption::foreground_color>());
details::BlockProgressScaleWriter writer{std::cout,
for (auto &style : get_value<details::ProgressBarOption::font_styles>())
details::set_font_style(os, style);
os << get_value<details::ProgressBarOption::prefix_text>();
os << get_value<details::ProgressBarOption::start>();
details::BlockProgressScaleWriter writer{os,
get_value<details::ProgressBarOption::bar_width>()};
writer.write(progress_);
writer.write(progress_ / max_progress * 100);
std::cout << get_value<details::ProgressBarOption::end>();
os << get_value<details::ProgressBarOption::end>();
if (get_value<details::ProgressBarOption::show_percentage>()) {
std::cout << " " << std::min(static_cast<size_t>(progress_), size_t(100)) << "%";
os << " " << std::min(static_cast<size_t>(progress_ / max_progress * 100.0), size_t(100)) << "%";
}
auto &saved_start_time = get_value<details::ProgressBarOption::saved_start_time>();
if (get_value<details::ProgressBarOption::show_elapsed_time>()) {
std::cout << " [";
details::write_duration(std::cout, elapsed);
os << " [";
if (saved_start_time)
details::write_duration(os, elapsed);
else
os << "00:00s";
}
if (get_value<details::ProgressBarOption::show_remaining_time>()) {
if (get_value<details::ProgressBarOption::show_elapsed_time>())
std::cout << "<";
os << "<";
else
std::cout << " [";
auto eta = std::chrono::nanoseconds(
progress_ > 0 ? static_cast<long long>(elapsed.count() * 100 / progress_) : 0);
auto remaining = eta > elapsed ? (eta - elapsed) : (elapsed - eta);
details::write_duration(std::cout, remaining);
std::cout << "]";
os << " [";
if (saved_start_time) {
auto eta = std::chrono::nanoseconds(
progress_ > 0 ? static_cast<long long>(elapsed.count() * max_progress / progress_) : 0);
auto remaining = eta > elapsed ? (eta - elapsed) : (elapsed - eta);
details::write_duration(os, remaining);
} else {
os << "00:00s";
}
os << "]";
} else {
if (get_value<details::ProgressBarOption::show_elapsed_time>())
std::cout << "]";
os << "]";
}
if (get_value<details::ProgressBarOption::max_postfix_text_len>() == 0)
get_value<details::ProgressBarOption::max_postfix_text_len>() = 10;
std::cout << " " << get_value<details::ProgressBarOption::postfix_text>()
os << " " << get_value<details::ProgressBarOption::postfix_text>()
<< std::string(get_value<details::ProgressBarOption::max_postfix_text_len>(), ' ')
<< "\r";
std::cout.flush();
if (progress_ > 100.0) {
os.flush();
if (progress_ > max_progress) {
get_value<details::ProgressBarOption::completed>() = true;
}
if (get_value<details::ProgressBarOption::completed>() &&
!from_multi_progress) // Don't std::endl if calling from MultiProgress
std::cout << termcolor::reset << std::endl;
os << termcolor::reset << std::endl;
}
};

View File

@@ -1,32 +1,6 @@
/*
Activity Indicators for Modern C++
https://github.com/p-ranav/indica
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
SPDX-License-Identifier: MIT
Copyright (c) 2019 Pranav Srinivas Kumar <pranav.srinivas.kumar@gmail.com>.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
#include <indicators/termcolor.hpp>
namespace indicators {
enum class Color { grey, red, green, yellow, blue, magenta, cyan, white };
enum class Color { grey, red, green, yellow, blue, magenta, cyan, white, unspecified };
}

View File

@@ -0,0 +1,35 @@
#pragma once
#if defined(_MSC_VER)
#if !defined(NOMINMAX)
#define NOMINMAX
#endif
#include <io.h>
#include <windows.h>
#else
#include <cstdio>
#endif
namespace indicators {
#if defined(_MSC_VER)
void show_console_cursor(bool const show) {
HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO cursorInfo;
GetConsoleCursorInfo(out, &cursorInfo);
cursorInfo.bVisible = show; // set the cursor visibility
SetConsoleCursorInfo(out, &cursorInfo);
}
#else
void show_console_cursor(bool const show) {
std::fputs(show ? "\e[?25h" : "\e[?25l", stdout);
}
#endif
} // namespace indicators

View File

@@ -0,0 +1,46 @@
#pragma once
#if defined(_MSC_VER)
#if !defined(NOMINMAX)
#define NOMINMAX
#endif
#include <io.h>
#include <windows.h>
#else
#include <iostream>
#endif
namespace indicators {
#ifdef _MSC_VER
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);
}
void move_up(int lines) { move(0, -lines); }
void move_down(int lines) { move(0, -lines); }
void move_right(int cols) { move(cols, 0); }
void move_left(int cols) { move(-cols, 0); }
#else
void move_up(int lines) { std::cout << "\033[" << lines << "A"; }
void move_down(int lines) { std::cout << "\033[" << lines << "B"; }
void move_right(int cols) { std::cout << "\033[" << cols << "C"; }
void move_left(int cols) { std::cout << "\033[" << cols << "D"; }
#endif
} // namespace indicators

View File

@@ -1,6 +1,6 @@
#pragma once
#include <indicators/color.hpp>
#include <indicators/setting.hpp>
#include <indicators/termcolor.hpp>
#include <algorithm>
@@ -47,6 +47,37 @@ inline void set_stream_color(std::ostream &os, Color color) {
}
}
inline void set_font_style(std::ostream &os, FontStyle style) {
switch (style) {
case FontStyle::bold:
os << termcolor::bold;
break;
case FontStyle::dark:
os << termcolor::dark;
break;
case FontStyle::italic:
os << termcolor::italic;
break;
case FontStyle::underline:
os << termcolor::underline;
break;
case FontStyle::blink:
os << termcolor::blink;
break;
case FontStyle::reverse:
os << termcolor::reverse;
break;
case FontStyle::concealed:
os << termcolor::concealed;
break;
case FontStyle::crossed:
os << termcolor::crossed;
break;
default:
break;
}
}
inline std::ostream &write_duration(std::ostream &os, std::chrono::nanoseconds ns) {
using namespace std;
using namespace std::chrono;
@@ -103,7 +134,7 @@ public:
: os(os), bar_width(bar_width), fill(fill), lead(lead), remainder(remainder) {}
std::ostream &write(float progress) {
auto pos = static_cast<size_t>(progress * static_cast<float>(bar_width) / 100.0);
auto pos = static_cast<size_t>(progress * bar_width / 100.0);
for (size_t i = 0; i < bar_width; ++i) {
if (i < pos)
os << fill;
@@ -123,5 +154,30 @@ private:
std::string remainder;
};
class IndeterminateProgressScaleWriter {
public:
IndeterminateProgressScaleWriter(std::ostream &os, size_t bar_width, const std::string &fill,
const std::string &lead)
: os(os), bar_width(bar_width), fill(fill), lead(lead) {}
std::ostream &write(size_t progress) {
for (size_t i = 0; i < bar_width; ++i) {
if (i < progress)
os << fill;
else if (i == progress)
os << lead;
else
os << fill;
}
return os;
}
private:
std::ostream &os;
size_t bar_width = 0;
std::string fill;
std::string lead;
};
} // namespace details
} // namespace indicators

View File

@@ -1,29 +1,3 @@
/*
Activity Indicators for Modern C++
https://github.com/p-ranav/indicators
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
SPDX-License-Identifier: MIT
Copyright (c) 2019 Pranav Srinivas Kumar <pranav.srinivas.kumar@gmail.com>.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
#include <atomic>
#include <functional>
@@ -98,6 +72,7 @@ private:
return details::get_value<id>(settings_).value;
}
public:
void print_progress() {
std::lock_guard<std::mutex> lock{mutex_};
auto &hide_bar_when_complete = get_value<details::ProgressBarOption::hide_bar_when_complete>();
@@ -123,7 +98,7 @@ private:
for (size_t i = 0; i < total_count_; ++i)
std::cout << "\x1b[A";
}
for (auto &bar: bars_) {
for (auto &bar : bars_) {
bar.get().print_progress(true);
std::cout << "\n";
}

View File

@@ -0,0 +1,7 @@
#pragma once
namespace indicators {
enum class FontStyle { bold, dark, italic, underline, blink, reverse, concealed, crossed };
}

View File

@@ -0,0 +1,203 @@
#pragma once
#include <indicators/details/stream_helper.hpp>
#include <algorithm>
#include <atomic>
#include <chrono>
#include <cmath>
#include <indicators/color.hpp>
#include <indicators/setting.hpp>
#include <iomanip>
#include <iostream>
#include <mutex>
#include <string>
#include <thread>
#include <tuple>
#include <type_traits>
namespace indicators {
class IndeterminateProgressBar {
using Settings =
std::tuple<option::BarWidth, option::PrefixText, option::PostfixText, option::Start,
option::End, option::Fill, option::Lead,
option::MaxPostfixTextLen, option::Completed,
option::ForegroundColor, option::FontStyles, option::Stream>;
enum class Direction {
forward,
backward
};
Direction direction_{Direction::forward};
public:
template <typename... Args,
typename std::enable_if<details::are_settings_from_tuple<
Settings, typename std::decay<Args>::type...>::value,
void *>::type = nullptr>
explicit IndeterminateProgressBar(Args &&... args)
: settings_(details::get<details::ProgressBarOption::bar_width>(option::BarWidth{100},
std::forward<Args>(args)...),
details::get<details::ProgressBarOption::prefix_text>(
option::PrefixText{}, std::forward<Args>(args)...),
details::get<details::ProgressBarOption::postfix_text>(
option::PostfixText{}, std::forward<Args>(args)...),
details::get<details::ProgressBarOption::start>(option::Start{"["},
std::forward<Args>(args)...),
details::get<details::ProgressBarOption::end>(option::End{"]"},
std::forward<Args>(args)...),
details::get<details::ProgressBarOption::fill>(option::Fill{"."},
std::forward<Args>(args)...),
details::get<details::ProgressBarOption::lead>(option::Lead{"<==>"},
std::forward<Args>(args)...),
details::get<details::ProgressBarOption::max_postfix_text_len>(
option::MaxPostfixTextLen{0}, std::forward<Args>(args)...),
details::get<details::ProgressBarOption::completed>(option::Completed{false},
std::forward<Args>(args)...),
details::get<details::ProgressBarOption::foreground_color>(
option::ForegroundColor{Color::unspecified}, std::forward<Args>(args)...),
details::get<details::ProgressBarOption::font_styles>(
option::FontStyles{std::vector<FontStyle>{}}, std::forward<Args>(args)...),
details::get<details::ProgressBarOption::stream>(
option::Stream{std::cout}, std::forward<Args>(args)...)) {
// starts with [<==>...........]
// progress_ = 0
// ends with [...........<==>]
// ^^^^^^^^^^^^^^^^^ bar_width
// ^^^^^^^^^^^^ (bar_width - len(lead))
// progress_ = bar_width - len(lead)
progress_ = 0;
max_progress_ = get_value<details::ProgressBarOption::bar_width>()
- get_value<details::ProgressBarOption::lead>().size()
+ get_value<details::ProgressBarOption::start>().size()
+ get_value<details::ProgressBarOption::end>().size();
}
template <typename T, details::ProgressBarOption id>
void set_option(details::Setting<T, id> &&setting) {
static_assert(!std::is_same<T, typename std::decay<decltype(details::get_value<id>(
std::declval<Settings>()))>::type>::value,
"Setting has wrong type!");
std::lock_guard<std::mutex> lock(mutex_);
get_value<id>() = std::move(setting).value;
}
template <typename T, details::ProgressBarOption id>
void set_option(const details::Setting<T, id> &setting) {
static_assert(!std::is_same<T, typename std::decay<decltype(details::get_value<id>(
std::declval<Settings>()))>::type>::value,
"Setting has wrong type!");
std::lock_guard<std::mutex> lock(mutex_);
get_value<id>() = setting.value;
}
void set_option(
const details::Setting<std::string, details::ProgressBarOption::postfix_text> &setting) {
std::lock_guard<std::mutex> lock(mutex_);
get_value<details::ProgressBarOption::postfix_text>() = setting.value;
if (setting.value.length() > get_value<details::ProgressBarOption::max_postfix_text_len>()) {
get_value<details::ProgressBarOption::max_postfix_text_len>() = setting.value.length();
}
}
void
set_option(details::Setting<std::string, details::ProgressBarOption::postfix_text> &&setting) {
std::lock_guard<std::mutex> lock(mutex_);
get_value<details::ProgressBarOption::postfix_text>() = std::move(setting).value;
auto &new_value = get_value<details::ProgressBarOption::postfix_text>();
if (new_value.length() > get_value<details::ProgressBarOption::max_postfix_text_len>()) {
get_value<details::ProgressBarOption::max_postfix_text_len>() = new_value.length();
}
}
void tick() {
{
std::lock_guard<std::mutex> lock{mutex_};
if (get_value<details::ProgressBarOption::completed>())
return;
progress_ += (direction_ == Direction::forward) ? 1 : -1;
if (direction_ == Direction::forward && progress_ == max_progress_) {
// time to go back
direction_ = Direction::backward;
} else if (direction_ == Direction::backward && progress_ == 0) {
direction_ = Direction::forward;
}
}
print_progress();
}
bool is_completed() {
return get_value<details::ProgressBarOption::completed>();
}
void mark_as_completed() {
get_value<details::ProgressBarOption::completed>() = true;
print_progress();
}
private:
template <details::ProgressBarOption id>
auto get_value() -> decltype((details::get_value<id>(std::declval<Settings &>()).value)) {
return details::get_value<id>(settings_).value;
}
template <details::ProgressBarOption id>
auto get_value() const
-> decltype((details::get_value<id>(std::declval<const Settings &>()).value)) {
return details::get_value<id>(settings_).value;
}
size_t progress_{0};
size_t max_progress_;
Settings settings_;
std::chrono::nanoseconds elapsed_;
std::mutex mutex_;
template <typename Indicator, size_t count> friend class MultiProgress;
template <typename Indicator> friend class DynamicProgress;
std::atomic<bool> multi_progress_mode_{false};
public:
void print_progress(bool from_multi_progress = false) {
std::lock_guard<std::mutex> lock{mutex_};
auto& os = get_value<details::ProgressBarOption::stream>();
if (multi_progress_mode_ && !from_multi_progress) {
return;
}
if (get_value<details::ProgressBarOption::foreground_color>() != Color::unspecified)
details::set_stream_color(os, get_value<details::ProgressBarOption::foreground_color>());
for (auto &style : get_value<details::ProgressBarOption::font_styles>())
details::set_font_style(os, style);
os << get_value<details::ProgressBarOption::prefix_text>();
os << get_value<details::ProgressBarOption::start>();
details::IndeterminateProgressScaleWriter writer{os,
get_value<details::ProgressBarOption::bar_width>(),
get_value<details::ProgressBarOption::fill>(),
get_value<details::ProgressBarOption::lead>()};
writer.write(progress_);
os << get_value<details::ProgressBarOption::end>();
if (get_value<details::ProgressBarOption::max_postfix_text_len>() == 0)
get_value<details::ProgressBarOption::max_postfix_text_len>() = 10;
os << " " << get_value<details::ProgressBarOption::postfix_text>()
<< std::string(get_value<details::ProgressBarOption::max_postfix_text_len>(), ' ')
<< "\r";
os.flush();
if (get_value<details::ProgressBarOption::completed>() &&
!from_multi_progress) // Don't std::endl if calling from MultiProgress
os << termcolor::reset << std::endl;
}
};
} // namespace indicators

View File

@@ -1,37 +1,13 @@
/*
Activity Indicators for Modern C++
https://github.com/p-ranav/indicators
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
SPDX-License-Identifier: MIT
Copyright (c) 2019 Pranav Srinivas Kumar <pranav.srinivas.kumar@gmail.com>.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
#include <atomic>
#include <functional>
#include <indicators/color.hpp>
#include <iostream>
#include <mutex>
#include <vector>
#include <indicators/cursor_movement.hpp>
#include <indicators/color.hpp>
namespace indicators {
template <typename Indicator, size_t count> class MultiProgress {
@@ -45,6 +21,13 @@ public:
}
}
template <size_t index>
typename std::enable_if<(index >= 0 && index < count), void>::type set_progress(size_t value) {
if (!bars_[index].get().is_completed())
bars_[index].get().set_progress(value);
print_progress();
}
template <size_t index>
typename std::enable_if<(index >= 0 && index < count), void>::type set_progress(float value) {
if (!bars_[index].get().is_completed())
@@ -76,11 +59,11 @@ private:
return result;
}
public:
void print_progress() {
std::lock_guard<std::mutex> lock{mutex_};
if (started_)
for (size_t i = 0; i < count; ++i)
std::cout << "\x1b[A";
move_up(count);
for (auto &bar : bars_) {
bar.get().print_progress(true);
std::cout << "\n";

View File

@@ -1,29 +1,3 @@
/*
Activity Indicators for Modern C++
https://github.com/p-ranav/indicators
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
SPDX-License-Identifier: MIT
Copyright (c) 2019 Pranav Srinivas Kumar <pranav.srinivas.kumar@gmail.com>.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
#include <indicators/details/stream_helper.hpp>
@@ -50,7 +24,7 @@ class ProgressBar {
option::End, option::Fill, option::Lead, option::Remainder,
option::MaxPostfixTextLen, option::Completed, option::ShowPercentage,
option::ShowElapsedTime, option::ShowRemainingTime, option::SavedStartTime,
option::ForegroundColor>;
option::ForegroundColor, option::FontStyles, option::MaxProgress, option::Stream>;
public:
template <typename... Args,
@@ -87,7 +61,13 @@ public:
details::get<details::ProgressBarOption::saved_start_time>(
option::SavedStartTime{false}, std::forward<Args>(args)...),
details::get<details::ProgressBarOption::foreground_color>(
option::ForegroundColor{Color::white}, std::forward<Args>(args)...)) {}
option::ForegroundColor{Color::unspecified}, std::forward<Args>(args)...),
details::get<details::ProgressBarOption::font_styles>(
option::FontStyles{std::vector<FontStyle>{}}, std::forward<Args>(args)...),
details::get<details::ProgressBarOption::max_progress>(
option::MaxProgress{100}, std::forward<Args>(args)...),
details::get<details::ProgressBarOption::stream>(
option::Stream{std::cout}, std::forward<Args>(args)...)) {}
template <typename T, details::ProgressBarOption id>
void set_option(details::Setting<T, id> &&setting) {
@@ -126,9 +106,9 @@ public:
}
}
void set_progress(float new_progress) {
void set_progress(size_t new_progress) {
{
std::lock_guard<std::mutex> lck(mutex_);
std::lock_guard<std::mutex> lock(mutex_);
progress_ = new_progress;
}
@@ -147,7 +127,7 @@ public:
size_t current() {
std::lock_guard<std::mutex> lock{mutex_};
return std::min(static_cast<size_t>(progress_), size_t(100));
return std::min(progress_, size_t(get_value<details::ProgressBarOption::max_progress>()));
}
bool is_completed() const { return get_value<details::ProgressBarOption::completed>(); }
@@ -169,7 +149,7 @@ private:
return details::get_value<id>(settings_).value;
}
float progress_{0};
size_t progress_{0};
Settings settings_;
std::chrono::nanoseconds elapsed_;
std::chrono::time_point<std::chrono::high_resolution_clock> start_time_point_;
@@ -189,10 +169,15 @@ private:
}
}
public:
void print_progress(bool from_multi_progress = false) {
std::lock_guard<std::mutex> lock{mutex_};
auto& os = get_value<details::ProgressBarOption::stream>();
const auto max_progress = get_value<details::ProgressBarOption::max_progress>();
if (multi_progress_mode_ && !from_multi_progress) {
if (progress_ > 100.0) {
if (progress_ >= max_progress) {
get_value<details::ProgressBarOption::completed>() = true;
}
return;
@@ -201,57 +186,72 @@ private:
if (!get_value<details::ProgressBarOption::completed>())
elapsed_ = std::chrono::duration_cast<std::chrono::nanoseconds>(now - start_time_point_);
std::cout << termcolor::bold;
details::set_stream_color(std::cout, get_value<details::ProgressBarOption::foreground_color>());
std::cout << get_value<details::ProgressBarOption::prefix_text>();
if (get_value<details::ProgressBarOption::foreground_color>() != Color::unspecified)
details::set_stream_color(os, get_value<details::ProgressBarOption::foreground_color>());
std::cout << get_value<details::ProgressBarOption::start>();
for (auto &style : get_value<details::ProgressBarOption::font_styles>())
details::set_font_style(os, style);
details::ProgressScaleWriter writer{std::cout,
os << get_value<details::ProgressBarOption::prefix_text>();
os << get_value<details::ProgressBarOption::start>();
details::ProgressScaleWriter writer{os,
get_value<details::ProgressBarOption::bar_width>(),
get_value<details::ProgressBarOption::fill>(),
get_value<details::ProgressBarOption::lead>(),
get_value<details::ProgressBarOption::remainder>()};
writer.write(progress_);
writer.write(double(progress_) / double(max_progress) * 100.0f);
std::cout << get_value<details::ProgressBarOption::end>();
os << get_value<details::ProgressBarOption::end>();
if (get_value<details::ProgressBarOption::show_percentage>()) {
std::cout << " " << std::min(static_cast<size_t>(progress_), size_t(100)) << "%";
os << " " << std::min(static_cast<size_t>(static_cast<float>(progress_) / max_progress * 100), size_t(100)) << "%";
}
auto &saved_start_time = get_value<details::ProgressBarOption::saved_start_time>();
if (get_value<details::ProgressBarOption::show_elapsed_time>()) {
std::cout << " [";
details::write_duration(std::cout, elapsed_);
os << " [";
if (saved_start_time)
details::write_duration(os, elapsed_);
else
os << "00:00s";
}
if (get_value<details::ProgressBarOption::show_remaining_time>()) {
if (get_value<details::ProgressBarOption::show_elapsed_time>())
std::cout << "<";
os << "<";
else
std::cout << " [";
auto eta = std::chrono::nanoseconds(
progress_ > 0 ? static_cast<long long>(elapsed_.count() * 100 / progress_) : 0);
auto remaining = eta > elapsed_ ? (eta - elapsed_) : (elapsed_ - eta);
details::write_duration(std::cout, remaining);
std::cout << "]";
os << " [";
if (saved_start_time) {
auto eta = std::chrono::nanoseconds(
progress_ > 0 ? static_cast<long long>(elapsed_.count() * max_progress / progress_) : 0);
auto remaining = eta > elapsed_ ? (eta - elapsed_) : (elapsed_ - eta);
details::write_duration(os, remaining);
} else {
os << "00:00s";
}
os << "]";
} else {
if (get_value<details::ProgressBarOption::show_elapsed_time>())
std::cout << "]";
os << "]";
}
if (get_value<details::ProgressBarOption::max_postfix_text_len>() == 0)
get_value<details::ProgressBarOption::max_postfix_text_len>() = 10;
std::cout << " " << get_value<details::ProgressBarOption::postfix_text>()
os << " " << get_value<details::ProgressBarOption::postfix_text>()
<< std::string(get_value<details::ProgressBarOption::max_postfix_text_len>(), ' ')
<< "\r";
std::cout.flush();
if (progress_ > 100.0) {
os.flush();
if (progress_ >= max_progress) {
get_value<details::ProgressBarOption::completed>() = true;
}
if (get_value<details::ProgressBarOption::completed>() &&
!from_multi_progress) // Don't std::endl if calling from MultiProgress
std::cout << termcolor::reset << std::endl;
os << termcolor::reset << std::endl;
}
};

View File

@@ -1,29 +1,3 @@
/*
Activity Indicators for Modern C++
https://github.com/p-ranav/indicators
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
SPDX-License-Identifier: MIT
Copyright (c) 2019 Pranav Srinivas Kumar <pranav.srinivas.kumar@gmail.com>.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
#include <indicators/details/stream_helper.hpp>
@@ -49,7 +23,8 @@ class ProgressSpinner {
std::tuple<option::ForegroundColor, option::PrefixText, option::PostfixText,
option::ShowPercentage, option::ShowElapsedTime, option::ShowRemainingTime,
option::ShowSpinner, option::SavedStartTime, option::Completed,
option::MaxPostfixTextLen, option::SpinnerStates>;
option::MaxPostfixTextLen, option::SpinnerStates, option::FontStyles,
option::MaxProgress, option::Stream>;
public:
template <typename... Args,
@@ -58,7 +33,7 @@ public:
void *>::type = nullptr>
explicit ProgressSpinner(Args &&... args)
: settings_(details::get<details::ProgressBarOption::foreground_color>(
option::ForegroundColor{Color::white}, std::forward<Args>(args)...),
option::ForegroundColor{Color::unspecified}, std::forward<Args>(args)...),
details::get<details::ProgressBarOption::prefix_text>(
option::PrefixText{}, std::forward<Args>(args)...),
details::get<details::ProgressBarOption::postfix_text>(
@@ -80,7 +55,13 @@ public:
details::get<details::ProgressBarOption::spinner_states>(
option::SpinnerStates{std::vector<std::string>{"", "", "", "", "", "",
"", "", "", ""}},
std::forward<Args>(args)...)) {}
std::forward<Args>(args)...),
details::get<details::ProgressBarOption::font_styles>(
option::FontStyles{std::vector<FontStyle>{}}, std::forward<Args>(args)...),
details::get<details::ProgressBarOption::max_progress>(
option::MaxProgress{100}, std::forward<Args>(args)...),
details::get<details::ProgressBarOption::stream>(
option::Stream{std::cout}, std::forward<Args>(args)...)) {}
template <typename T, details::ProgressBarOption id>
void set_option(details::Setting<T, id> &&setting) {
@@ -119,7 +100,7 @@ public:
}
}
void set_progress(float value) {
void set_progress(size_t value) {
{
std::lock_guard<std::mutex> lock{mutex_};
progress_ = value;
@@ -139,7 +120,7 @@ public:
size_t current() {
std::lock_guard<std::mutex> lock{mutex_};
return std::min(static_cast<size_t>(progress_), size_t(100));
return std::min(progress_, size_t(get_value<details::ProgressBarOption::max_progress>()));
}
bool is_completed() const { return get_value<details::ProgressBarOption::completed>(); }
@@ -151,7 +132,7 @@ public:
private:
Settings settings_;
float progress_{0.0};
size_t progress_{0};
size_t index_{0};
std::chrono::time_point<std::chrono::high_resolution_clock> start_time_point_;
std::mutex mutex_;
@@ -177,53 +158,62 @@ private:
}
}
public:
void print_progress() {
std::lock_guard<std::mutex> lock{mutex_};
auto& os = get_value<details::ProgressBarOption::stream>();
const auto max_progress = get_value<details::ProgressBarOption::max_progress>();
auto now = std::chrono::high_resolution_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(now - start_time_point_);
std::cout << termcolor::bold;
details::set_stream_color(std::cout, get_value<details::ProgressBarOption::foreground_color>());
std::cout << get_value<details::ProgressBarOption::prefix_text>();
if (get_value<details::ProgressBarOption::foreground_color>() != Color::unspecified)
details::set_stream_color(os, get_value<details::ProgressBarOption::foreground_color>());
for (auto &style : get_value<details::ProgressBarOption::font_styles>())
details::set_font_style(os, style);
os << get_value<details::ProgressBarOption::prefix_text>();
if (get_value<details::ProgressBarOption::spinner_show>())
std::cout << get_value<details::ProgressBarOption::spinner_states>()
os << get_value<details::ProgressBarOption::spinner_states>()
[index_ % get_value<details::ProgressBarOption::spinner_states>().size()];
if (get_value<details::ProgressBarOption::show_percentage>()) {
std::cout << " " << std::min(static_cast<size_t>(progress_), size_t(100)) << "%";
os << " " << std::min(progress_, size_t(max_progress)) << "%";
}
if (get_value<details::ProgressBarOption::show_elapsed_time>()) {
std::cout << " [";
details::write_duration(std::cout, elapsed);
os << " [";
details::write_duration(os, elapsed);
}
if (get_value<details::ProgressBarOption::show_remaining_time>()) {
if (get_value<details::ProgressBarOption::show_elapsed_time>())
std::cout << "<";
os << "<";
else
std::cout << " [";
os << " [";
auto eta = std::chrono::nanoseconds(
progress_ > 0 ? static_cast<long long>(elapsed.count() * 100 / progress_) : 0);
progress_ > 0 ? static_cast<long long>(elapsed.count() * max_progress / progress_) : 0);
auto remaining = eta > elapsed ? (eta - elapsed) : (elapsed - eta);
details::write_duration(std::cout, remaining);
std::cout << "]";
details::write_duration(os, remaining);
os << "]";
} else {
if (get_value<details::ProgressBarOption::show_elapsed_time>())
std::cout << "]";
os << "]";
}
if (get_value<details::ProgressBarOption::max_postfix_text_len>() == 0)
get_value<details::ProgressBarOption::max_postfix_text_len>() = 10;
std::cout << " " << get_value<details::ProgressBarOption::postfix_text>()
os << " " << get_value<details::ProgressBarOption::postfix_text>()
<< std::string(get_value<details::ProgressBarOption::max_postfix_text_len>(), ' ')
<< "\r";
std::cout.flush();
os.flush();
index_ += 1;
if (progress_ > 100.0) {
if (progress_ > max_progress) {
get_value<details::ProgressBarOption::completed>() = true;
}
if (get_value<details::ProgressBarOption::completed>())
std::cout << termcolor::reset << std::endl;
os << termcolor::reset << std::endl;
}
};

View File

@@ -28,9 +28,11 @@ SOFTWARE.
#include <cstddef>
#include <indicators/color.hpp>
#include <indicators/font_style.hpp>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
namespace indicators {
@@ -86,7 +88,10 @@ enum class ProgressBarOption {
foreground_color,
spinner_show,
spinner_states,
hide_bar_when_complete
font_styles,
hide_bar_when_complete,
max_progress,
stream
};
template <typename T, ProgressBarOption Id> struct Setting {
@@ -130,14 +135,14 @@ template <ProgressBarOption Id, typename Default> Default &&get_impl(Default &&d
}
template <ProgressBarOption Id, typename Default, typename T, typename... Args>
auto get_impl(Default &&def, T &&first, Args &&... tail) ->
auto get_impl(Default &&/*def*/, T &&first, Args &&... /*tail*/) ->
typename std::enable_if<(std::decay<T>::type::id == Id),
decltype(std::forward<T>(first))>::type {
return std::forward<T>(first);
}
template <ProgressBarOption Id, typename Default, typename T, typename... Args>
auto get_impl(Default &&def, T &&first, Args &&... tail) ->
auto get_impl(Default &&def, T &&/*first*/, Args &&... tail) ->
typename std::enable_if<(std::decay<T>::type::id != Id),
decltype(get_impl<Id>(std::forward<Default>(def),
std::forward<Args>(tail)...))>::type {
@@ -199,5 +204,9 @@ using SpinnerStates =
details::Setting<std::vector<std::string>, details::ProgressBarOption::spinner_states>;
using HideBarWhenComplete =
details::BooleanSetting<details::ProgressBarOption::hide_bar_when_complete>;
using FontStyles =
details::Setting<std::vector<FontStyle>, details::ProgressBarOption::font_styles>;
using MaxProgress = details::IntegerSetting<details::ProgressBarOption::max_progress>;
using Stream = details::Setting<std::ostream&, details::ProgressBarOption::stream>;
} // namespace option
} // namespace indicators
} // namespace indicators

View File

@@ -0,0 +1,37 @@
#pragma once
#include <utility>
namespace indicators {
#if defined(_MSC_VER)
#include <windows.h>
std::pair<size_t, size_t> terminal_size() {
CONSOLE_SCREEN_BUFFER_INFO csbi;
int columns, rows;
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
columns = 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>(cols)};
}
size_t terminal_width() {
return terminal_size().second;
}
#else
#include <sys/ioctl.h> //ioctl() and TIOCGWINSZ
#include <unistd.h> // for STDOUT_FILENO
std::pair<size_t, size_t> terminal_size() {
struct winsize size;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &size);
return {static_cast<size_t>(size.ws_row), static_cast<size_t>(size.ws_col)};
}
size_t terminal_width() {
return terminal_size().second;
}
#endif
}

View File

@@ -2,6 +2,9 @@
add_executable(block_progress_bar block_progress_bar.cpp)
target_link_libraries(block_progress_bar PRIVATE indicators::indicators)
add_executable(block_progress_bar_iterable block_progress_bar_iterable.cpp)
target_link_libraries(block_progress_bar_iterable PRIVATE indicators::indicators)
add_executable(multi_threaded_bar multi_threaded_bar.cpp)
target_link_libraries(multi_threaded_bar PRIVATE indicators::indicators)
@@ -11,6 +14,9 @@ target_link_libraries(progress_bar_set_progress PRIVATE indicators::indicators)
add_executable(progress_bar_tick progress_bar_tick.cpp)
target_link_libraries(progress_bar_tick PRIVATE indicators::indicators)
add_executable(progress_bar_sstream progress_bar_sstream.cpp)
target_link_libraries(progress_bar_sstream PRIVATE indicators::indicators)
add_executable(progress_spinner progress_spinner.cpp)
target_link_libraries(progress_spinner PRIVATE indicators::indicators)
@@ -25,3 +31,10 @@ target_link_libraries(multi_block_progress_bar PRIVATE indicators::indicators)
add_executable(dynamic_progress dynamic_progress.cpp)
target_link_libraries(dynamic_progress PRIVATE indicators::indicators)
add_executable(max_progress max_progress.cpp)
target_link_libraries(max_progress PRIVATE indicators::indicators)
add_executable(indeterminate_progress_bar indeterminate_progress_bar.cpp)
target_link_libraries(indeterminate_progress_bar PRIVATE indicators::indicators)

View File

@@ -1,13 +1,18 @@
#include <chrono>
#include <indicators/block_progress_bar.hpp>
#include <indicators/cursor_control.hpp>
#include <thread>
int main() {
// Hide cursor
std::cout << "\e[?25l";
indicators::show_console_cursor(false);
indicators::BlockProgressBar bar{indicators::option::BarWidth{80}};
indicators::BlockProgressBar bar{
indicators::option::BarWidth{80},
indicators::option::FontStyles{
std::vector<indicators::FontStyle>{indicators::FontStyle::bold}}
};
// Update bar state
auto progress = 0.0f;
@@ -20,7 +25,7 @@ int main() {
}
// Show cursor
std::cout << "\e[?25h";
indicators::show_console_cursor(true);
return 0;
}

View File

@@ -0,0 +1,50 @@
#include <chrono>
#include <indicators/block_progress_bar.hpp>
#include <indicators/cursor_control.hpp>
#include <thread>
int main() {
// Hide cursor
indicators::show_console_cursor(false);
// Random list of numbers
std::vector<size_t> numbers;
for (size_t i = 0; i < 1259438; ++i) {
numbers.push_back(i);
}
using namespace indicators;
BlockProgressBar bar{
option::BarWidth{80},
option::ForegroundColor{Color::white},
option::FontStyles{
std::vector<FontStyle>{FontStyle::bold}},
option::MaxProgress{numbers.size()}
};
std::cout << "Iterating over a list of numbers (size = "
<< numbers.size() << ")\n";
std::vector<size_t> result;
for (size_t i = 0; i < numbers.size(); ++i) {
// Perform some computation
result.push_back(numbers[i] * numbers[i]);
// Show iteration as postfix text
bar.set_option(option::PostfixText{
std::to_string(i) + "/" + std::to_string(numbers.size())
});
// update progress bar
bar.tick();
}
bar.mark_as_completed();
// Show cursor
indicators::show_console_cursor(true);
return 0;
}

View File

@@ -6,27 +6,39 @@ int main() {
ProgressBar bar1{option::BarWidth{50}, option::ForegroundColor{Color::red},
option::ShowElapsedTime{true}, option::ShowRemainingTime{true},
option::PrefixText{"5c90d4a2d1a8: Downloading "}};
option::PrefixText{"5c90d4a2d1a8: Downloading "},
indicators::option::FontStyles{
std::vector<indicators::FontStyle>{indicators::FontStyle::bold}}};
ProgressBar bar2{option::BarWidth{50}, option::ForegroundColor{Color::yellow},
option::ShowElapsedTime{true}, option::ShowRemainingTime{true},
option::PrefixText{"22337bfd13a9: Downloading "}};
option::PrefixText{"22337bfd13a9: Downloading "},
indicators::option::FontStyles{
std::vector<indicators::FontStyle>{indicators::FontStyle::bold}}};
ProgressBar bar3{option::BarWidth{50}, option::ForegroundColor{Color::green},
option::ShowElapsedTime{true}, option::ShowRemainingTime{true},
option::PrefixText{"10f26c680a34: Downloading "}};
option::PrefixText{"10f26c680a34: Downloading "},
indicators::option::FontStyles{
std::vector<indicators::FontStyle>{indicators::FontStyle::bold}}};
ProgressBar bar4{option::BarWidth{50}, option::ForegroundColor{Color::white},
option::ShowElapsedTime{true}, option::ShowRemainingTime{true},
option::PrefixText{"6364e0d7a283: Downloading "}};
option::PrefixText{"6364e0d7a283: Downloading "},
indicators::option::FontStyles{
std::vector<indicators::FontStyle>{indicators::FontStyle::bold}}};
ProgressBar bar5{option::BarWidth{50}, option::ForegroundColor{Color::blue},
option::ShowElapsedTime{true}, option::ShowRemainingTime{true},
option::PrefixText{"ff1356ba118b: Downloading "}};
option::PrefixText{"ff1356ba118b: Downloading "},
indicators::option::FontStyles{
std::vector<indicators::FontStyle>{indicators::FontStyle::bold}}};
ProgressBar bar6{option::BarWidth{50}, option::ForegroundColor{Color::cyan},
option::ShowElapsedTime{true}, option::ShowRemainingTime{true},
option::PrefixText{"5a17453338b4: Downloading "}};
option::PrefixText{"5a17453338b4: Downloading "},
indicators::option::FontStyles{
std::vector<indicators::FontStyle>{indicators::FontStyle::bold}}};
std::cout << termcolor::bold << termcolor::white << "Pulling image foo:bar/baz\n";

View File

@@ -0,0 +1,40 @@
#include <chrono>
#include <indicators/indeterminate_progress_bar.hpp>
#include <indicators/cursor_control.hpp>
#include <indicators/termcolor.hpp>
#include <thread>
int main() {
indicators::IndeterminateProgressBar bar{
indicators::option::BarWidth{40},
indicators::option::Start{"["},
indicators::option::Fill{"·"},
indicators::option::Lead{"<==>"},
indicators::option::End{"]"},
indicators::option::PostfixText{"Checking for Updates"},
indicators::option::ForegroundColor{indicators::Color::yellow},
indicators::option::FontStyles{
std::vector<indicators::FontStyle>{indicators::FontStyle::bold}}
};
indicators::show_console_cursor(false);
auto job = [&bar]() {
std::this_thread::sleep_for(std::chrono::milliseconds(10000));
bar.mark_as_completed();
std::cout << termcolor::bold << termcolor::green
<< "System is up to date!\n" << termcolor::reset;
};
std::thread job_completion_thread(job);
// Update bar state
while (!bar.is_completed()) {
bar.tick();
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
job_completion_thread.join();
indicators::show_console_cursor(true);
return 0;
}

30
samples/max_progress.cpp Normal file
View File

@@ -0,0 +1,30 @@
#include <chrono>
#include <indicators/block_progress_bar.hpp>
#include <indicators/cursor_control.hpp>
#include <thread>
int main() {
// Hide cursor
indicators::show_console_cursor(false);
indicators::BlockProgressBar bar{
indicators::option::BarWidth{80},
indicators::option::FontStyles{
std::vector<indicators::FontStyle>{indicators::FontStyle::bold}},
indicators::option::MaxProgress{400}
};
// Update bar state
while (true) {
bar.tick();
if (bar.is_completed())
break;
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
// Show cursor
indicators::show_console_cursor(true);
return 0;
}

View File

@@ -5,15 +5,21 @@ int main() {
using namespace indicators;
BlockProgressBar bar1{option::BarWidth{50}, option::ForegroundColor{Color::yellow},
option::ShowElapsedTime{true}, option::ShowRemainingTime{true},
option::PrefixText{"Progress Bar #1 "}};
option::PrefixText{"Progress Bar #1 "},
indicators::option::FontStyles{
std::vector<indicators::FontStyle>{indicators::FontStyle::bold}}};
BlockProgressBar bar2{option::BarWidth{50}, option::ForegroundColor{Color::cyan},
option::ShowElapsedTime{true}, option::ShowRemainingTime{true},
option::PrefixText{"Progress Bar #2 "}};
option::PrefixText{"Progress Bar #2 "},
indicators::option::FontStyles{
std::vector<indicators::FontStyle>{indicators::FontStyle::bold}}};
BlockProgressBar bar3{option::BarWidth{50}, option::ForegroundColor{Color::red},
option::ShowElapsedTime{true}, option::ShowRemainingTime{true},
option::PrefixText{"Progress Bar #3 "}};
option::PrefixText{"Progress Bar #3 "},
indicators::option::FontStyles{
std::vector<indicators::FontStyle>{indicators::FontStyle::bold}}};
indicators::MultiProgress<indicators::BlockProgressBar, 3> bars(bar1, bar2, bar3);

View File

@@ -12,7 +12,9 @@ int main() {
indicators::option::ForegroundColor{indicators::Color::yellow},
indicators::option::ShowElapsedTime{true},
indicators::option::ShowRemainingTime{true},
indicators::option::PrefixText{"Progress Bar #1 "}};
indicators::option::PrefixText{"Progress Bar #1 "},
indicators::option::FontStyles{
std::vector<indicators::FontStyle>{indicators::FontStyle::bold}}};
indicators::ProgressBar bar2{indicators::option::BarWidth{50},
indicators::option::Start{"["},
@@ -23,7 +25,9 @@ int main() {
indicators::option::ForegroundColor{indicators::Color::cyan},
indicators::option::ShowElapsedTime{true},
indicators::option::ShowRemainingTime{true},
indicators::option::PrefixText{"Progress Bar #2 "}};
indicators::option::PrefixText{"Progress Bar #2 "},
indicators::option::FontStyles{
std::vector<indicators::FontStyle>{indicators::FontStyle::bold}}};
indicators::ProgressBar bar3{indicators::option::BarWidth{50},
indicators::option::Start{"["},
@@ -34,7 +38,9 @@ int main() {
indicators::option::ForegroundColor{indicators::Color::red},
indicators::option::ShowElapsedTime{true},
indicators::option::ShowRemainingTime{true},
indicators::option::PrefixText{"Progress Bar #3 "}};
indicators::option::PrefixText{"Progress Bar #3 "},
indicators::option::FontStyles{
std::vector<indicators::FontStyle>{indicators::FontStyle::bold}}};
indicators::MultiProgress<indicators::ProgressBar, 3> bars(bar1, bar2, bar3);

View File

@@ -11,6 +11,8 @@ int main() {
indicators::option::Remainder{"-"},
indicators::option::End{" ]"},
indicators::option::ForegroundColor{indicators::Color::yellow},
indicators::option::FontStyles{
std::vector<indicators::FontStyle>{indicators::FontStyle::bold}}
};
// As configured, the bar will look like this:

View File

@@ -1,11 +1,12 @@
#include <chrono>
#include <indicators/cursor_control.hpp>
#include <indicators/progress_bar.hpp>
#include <thread>
int main() {
// Hide cursor
std::cout << "\e[?25l";
indicators::show_console_cursor(false);
indicators::ProgressBar bar{
indicators::option::BarWidth{50},
@@ -16,6 +17,8 @@ int main() {
indicators::option::End{" ]"},
indicators::option::PostfixText{"Loading dependency 1/4"},
indicators::option::ForegroundColor{indicators::Color::cyan},
indicators::option::FontStyles{
std::vector<indicators::FontStyle>{indicators::FontStyle::bold}}
};
// Update bar state
@@ -42,10 +45,8 @@ int main() {
bar.set_progress(100); // all done
bar.mark_as_completed();
// Show cursor
std::cout << "\e[?25h";
indicators::show_console_cursor(true);
return 0;
}

View File

@@ -0,0 +1,37 @@
#include <chrono>
#include <indicators/progress_bar.hpp>
#include <thread>
#include <sstream>
int main() {
using namespace indicators;
std::stringstream os;
ProgressBar bar{
option::BarWidth{50},
option::Start{"["},
option::Fill{"="},
option::Lead{">"},
option::Remainder{" "},
option::End{"]"},
option::PostfixText{"Getting started"},
option::ForegroundColor{indicators::Color::green},
option::FontStyles{
std::vector<indicators::FontStyle>{indicators::FontStyle::bold}},
option::Stream{os}
};
// Update bar state
while (true) {
bar.tick();
if (bar.is_completed())
break;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
std::cout << "Stream contents:\n";
std::cout << os.str() << "\n";
return 0;
}

View File

@@ -12,6 +12,8 @@ int main() {
indicators::option::End{" ]"},
indicators::option::PostfixText{"Getting started"},
indicators::option::ForegroundColor{indicators::Color::green},
indicators::option::FontStyles{
std::vector<indicators::FontStyle>{indicators::FontStyle::bold}}
};
// Update bar state

View File

@@ -1,15 +1,18 @@
#include <indicators/cursor_control.hpp>
#include <indicators/progress_spinner.hpp>
int main() {
// Hide cursor
std::cout << "\e[?25l";
indicators::show_console_cursor(false);
indicators::ProgressSpinner spinner{
indicators::option::PostfixText{"Checking credentials"},
indicators::option::ForegroundColor{indicators::Color::yellow},
indicators::option::SpinnerStates{
std::vector<std::string>{"", "", "", "", "", "", "", ""}},
indicators::option::FontStyles{
std::vector<indicators::FontStyle>{indicators::FontStyle::bold}}
};
// Update spinner state
@@ -32,7 +35,7 @@ int main() {
thread.join();
// Show cursor
std::cout << "\e[?25h";
indicators::show_console_cursor(true);
return 0;
}

View File

@@ -1,8 +1,12 @@
#include <chrono>
#include <indicators/cursor_control.hpp>
#include <indicators/progress_bar.hpp>
#include <thread>
int main() {
// Hide cursor
indicators::show_console_cursor(false);
indicators::ProgressBar bar{
indicators::option::BarWidth{50},
indicators::option::Start{" ["},
@@ -14,6 +18,8 @@ int main() {
indicators::option::ForegroundColor{indicators::Color::yellow},
indicators::option::ShowElapsedTime{true},
indicators::option::ShowRemainingTime{true},
indicators::option::FontStyles{
std::vector<indicators::FontStyle>{indicators::FontStyle::bold}}
};
// Update bar state
@@ -25,7 +31,7 @@ int main() {
}
// Show cursor
std::cout << "\e[?25h";
indicators::show_console_cursor(true);
return 0;
}

21
single_include.json Normal file
View File

@@ -0,0 +1,21 @@
{
"project": "Activity Indicators for Modern C++",
"target": "single_include/indicators/indicators.hpp",
"sources": [
"include/indicators/color.hpp",
"include/indicators/font_style.hpp",
"include/indicators/termcolor.hpp",
"include/indicators/terminal_size.hpp",
"include/indicators/setting.hpp",
"include/indicators/cursor_control.hpp",
"include/indicators/cursor_movement.hpp",
"include/indicators/details/stream_helper.hpp",
"include/indicators/progress_bar.hpp",
"include/indicators/block_progress_bar.hpp",
"include/indicators/indeterminate_progress_bar.hpp",
"include/indicators/multi_progress.hpp",
"include/indicators/dynamic_progress.hpp",
"include/indicators/progress_spinner.hpp"
],
"include_paths": ["include"]
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,10 @@
The following changes have been made to the code with respect to <https://github.com/edlund/amalgamate/commit/c91f07eea1133aa184f652b8f1398eaf03586208>:
- Resolved inspection results from PyCharm:
- replaced tabs with spaces
- added encoding annotation
- reindented file to remove trailing whitespaces
- unused import `sys`
- membership check
- made function from `_is_within`
- removed unused variable `actual_path`

View File

@@ -0,0 +1,27 @@
amalgamate.py - Amalgamate C source and header files
Copyright (c) 2012, Erik Edlund <erik.edlund@32767.se>
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of Erik Edlund, nor the names of its contributors may
be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -0,0 +1,66 @@
# amalgamate.py - Amalgamate C source and header files
Origin: https://bitbucket.org/erikedlund/amalgamate
Mirror: https://github.com/edlund/amalgamate
`amalgamate.py` aims to make it easy to use SQLite-style C source and header
amalgamation in projects.
For more information, please refer to: http://sqlite.org/amalgamation.html
## Here be dragons
`amalgamate.py` is quite dumb, it only knows the bare minimum about C code
required in order to be able to handle trivial include directives. It can
produce weird results for unexpected code.
Things to be aware of:
`amalgamate.py` will not handle complex include directives correctly:
#define HEADER_PATH "path/to/header.h"
#include HEADER_PATH
In the above example, `path/to/header.h` will not be included in the
amalgamation (HEADER_PATH is never expanded).
`amalgamate.py` makes the assumption that each source and header file which
is not empty will end in a new-line character, which is not immediately
preceded by a backslash character (see 5.1.1.2p1.2 of ISO C99).
`amalgamate.py` should be usable with C++ code, but raw string literals from
C++11 will definitely cause problems:
R"delimiter(Terrible raw \ data " #include <sneaky.hpp>)delimiter"
R"delimiter(Terrible raw \ data " escaping)delimiter"
In the examples above, `amalgamate.py` will stop parsing the raw string literal
when it encounters the first quotation mark, which will produce unexpected
results.
## Installing amalgamate.py
Python v.2.7.0 or higher is required.
`amalgamate.py` can be tested and installed using the following commands:
./test.sh && sudo -k cp ./amalgamate.py /usr/local/bin/
## Using amalgamate.py
amalgamate.py [-v] -c path/to/config.json -s path/to/source/dir \
[-p path/to/prologue.(c|h)]
* The `-c, --config` option should specify the path to a JSON config file which
lists the source files, include paths and where to write the resulting
amalgamation. Have a look at `test/source.c.json` and `test/include.h.json`
to see two examples.
* The `-s, --source` option should specify the path to the source directory.
This is useful for supporting separate source and build directories.
* The `-p, --prologue` option should specify the path to a file which will be
added to the beginning of the amalgamation. It is optional.

View File

@@ -0,0 +1,299 @@
#!/usr/bin/env python
# coding=utf-8
# amalgamate.py - Amalgamate C source and header files.
# Copyright (c) 2012, Erik Edlund <erik.edlund@32767.se>
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# * Neither the name of Erik Edlund, nor the names of its contributors may
# be used to endorse or promote products derived from this software without
# specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import argparse
import datetime
import json
import os
import re
class Amalgamation(object):
# Prepends self.source_path to file_path if needed.
def actual_path(self, file_path):
if not os.path.isabs(file_path):
file_path = os.path.join(self.source_path, file_path)
return file_path
# Search included file_path in self.include_paths and
# in source_dir if specified.
def find_included_file(self, file_path, source_dir):
search_dirs = self.include_paths[:]
if source_dir:
search_dirs.insert(0, source_dir)
for search_dir in search_dirs:
search_path = os.path.join(search_dir, file_path)
if os.path.isfile(self.actual_path(search_path)):
return search_path
return None
def __init__(self, args):
with open(args.config, 'r') as f:
config = json.loads(f.read())
for key in config:
setattr(self, key, config[key])
self.verbose = args.verbose == "yes"
self.prologue = args.prologue
self.source_path = args.source_path
self.included_files = []
# Generate the amalgamation and write it to the target file.
def generate(self):
amalgamation = ""
if self.prologue:
with open(self.prologue, 'r') as f:
amalgamation += datetime.datetime.now().strftime(f.read())
if self.verbose:
print("Config:")
print(" target = {0}".format(self.target))
print(" working_dir = {0}".format(os.getcwd()))
print(" include_paths = {0}".format(self.include_paths))
print("Creating amalgamation:")
for file_path in self.sources:
# Do not check the include paths while processing the source
# list, all given source paths must be correct.
# actual_path = self.actual_path(file_path)
print(" - processing \"{0}\"".format(file_path))
t = TranslationUnit(file_path, self, True)
amalgamation += t.content
with open(self.target, 'w') as f:
f.write(amalgamation)
print("...done!\n")
if self.verbose:
print("Files processed: {0}".format(self.sources))
print("Files included: {0}".format(self.included_files))
print("")
def _is_within(match, matches):
for m in matches:
if match.start() > m.start() and \
match.end() < m.end():
return True
return False
class TranslationUnit(object):
# // C++ comment.
cpp_comment_pattern = re.compile(r"//.*?\n")
# /* C comment. */
c_comment_pattern = re.compile(r"/\*.*?\*/", re.S)
# "complex \"stri\\\ng\" value".
string_pattern = re.compile("[^']" r'".*?(?<=[^\\])"', re.S)
# Handle simple include directives. Support for advanced
# directives where macros and defines needs to expanded is
# not a concern right now.
include_pattern = re.compile(
r'#\s*include\s+(<|")(?P<path>.*?)("|>)', re.S)
# #pragma once
pragma_once_pattern = re.compile(r'#\s*pragma\s+once', re.S)
# Search for pattern in self.content, add the match to
# contexts if found and update the index accordingly.
def _search_content(self, index, pattern, contexts):
match = pattern.search(self.content, index)
if match:
contexts.append(match)
return match.end()
return index + 2
# Return all the skippable contexts, i.e., comments and strings
def _find_skippable_contexts(self):
# Find contexts in the content in which a found include
# directive should not be processed.
skippable_contexts = []
# Walk through the content char by char, and try to grab
# skippable contexts using regular expressions when found.
i = 1
content_len = len(self.content)
while i < content_len:
j = i - 1
current = self.content[i]
previous = self.content[j]
if current == '"':
# String value.
i = self._search_content(j, self.string_pattern,
skippable_contexts)
elif current == '*' and previous == '/':
# C style comment.
i = self._search_content(j, self.c_comment_pattern,
skippable_contexts)
elif current == '/' and previous == '/':
# C++ style comment.
i = self._search_content(j, self.cpp_comment_pattern,
skippable_contexts)
else:
# Skip to the next char.
i += 1
return skippable_contexts
# Returns True if the match is within list of other matches
# Removes pragma once from content
def _process_pragma_once(self):
content_len = len(self.content)
if content_len < len("#include <x>"):
return 0
# Find contexts in the content in which a found include
# directive should not be processed.
skippable_contexts = self._find_skippable_contexts()
pragmas = []
pragma_once_match = self.pragma_once_pattern.search(self.content)
while pragma_once_match:
if not _is_within(pragma_once_match, skippable_contexts):
pragmas.append(pragma_once_match)
pragma_once_match = self.pragma_once_pattern.search(self.content,
pragma_once_match.end())
# Handle all collected pragma once directives.
prev_end = 0
tmp_content = ''
for pragma_match in pragmas:
tmp_content += self.content[prev_end:pragma_match.start()]
prev_end = pragma_match.end()
tmp_content += self.content[prev_end:]
self.content = tmp_content
# Include all trivial #include directives into self.content.
def _process_includes(self):
content_len = len(self.content)
if content_len < len("#include <x>"):
return 0
# Find contexts in the content in which a found include
# directive should not be processed.
skippable_contexts = self._find_skippable_contexts()
# Search for include directives in the content, collect those
# which should be included into the content.
includes = []
include_match = self.include_pattern.search(self.content)
while include_match:
if not _is_within(include_match, skippable_contexts):
include_path = include_match.group("path")
search_same_dir = include_match.group(1) == '"'
found_included_path = self.amalgamation.find_included_file(
include_path, self.file_dir if search_same_dir else None)
if found_included_path:
includes.append((include_match, found_included_path))
include_match = self.include_pattern.search(self.content,
include_match.end())
# Handle all collected include directives.
prev_end = 0
tmp_content = ''
for include in includes:
include_match, found_included_path = include
tmp_content += self.content[prev_end:include_match.start()]
tmp_content += "// {0}".format(include_match.group(0))
if found_included_path not in self.amalgamation.included_files:
t = TranslationUnit(found_included_path, self.amalgamation, False)
tmp_content += t.content
prev_end = include_match.end()
tmp_content += self.content[prev_end:]
self.content = tmp_content
return len(includes)
# Make all content processing
def _process(self):
if not self.is_root:
self._process_pragma_once()
self._process_includes()
def __init__(self, file_path, amalgamation, is_root):
self.file_path = file_path
self.file_dir = os.path.dirname(file_path)
self.amalgamation = amalgamation
self.is_root = is_root
self.amalgamation.included_files.append(self.file_path)
actual_path = self.amalgamation.actual_path(file_path)
if not os.path.isfile(actual_path):
raise IOError("File not found: \"{0}\"".format(file_path))
with open(actual_path, 'r') as f:
self.content = f.read()
self._process()
def main():
description = "Amalgamate C source and header files."
usage = " ".join([
"amalgamate.py",
"[-v]",
"-c path/to/config.json",
"-s path/to/source/dir",
"[-p path/to/prologue.(c|h)]"
])
argsparser = argparse.ArgumentParser(
description=description, usage=usage)
argsparser.add_argument("-v", "--verbose", dest="verbose",
choices=["yes", "no"], metavar="", help="be verbose")
argsparser.add_argument("-c", "--config", dest="config",
required=True, metavar="", help="path to a JSON config file")
argsparser.add_argument("-s", "--source", dest="source_path",
required=True, metavar="", help="source code path")
argsparser.add_argument("-p", "--prologue", dest="prologue",
required=False, metavar="", help="path to a C prologue file")
amalgamation = Amalgamation(argsparser.parse_args())
amalgamation.generate()
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,8 @@
{
"project": "cgame competitive programming for codingame",
"target": "AllTrees.cpp",
"sources": [
"test/gametheory/TreesTest.cpp"
],
"include_paths": ["include"]
}