Activity Indicators for Modern C++

Overview

ci status codacy license version

Highlights

  • Thread-safe progress bars and spinners
  • 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
  • MIT License

Table of Contents

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:

{prefix} {start} {fill} {lead} {remaining} {end} {percentage} [{elapsed}<{remaining}] {postfix}
         ^^^^^^^^^^^^^ Bar Width ^^^^^^^^^^^^^^^   

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()

You can update the progress bar using bar.tick() which increments progress by exactly 1%.

#include <indicators/progress_bar.hpp>
#include <thread>
#include <chrono>

int main() {
  using namespace indicators;
  ProgressBar bar{
    option::BarWidth{50},
    option::Start{"["},
    option::Fill{"="},
    option::Lead{">"},
    option::Remainder{" "},
    option::End{"]"},
    option::PostfixText{"Extracting Archive"},
    option::ForegroundColor{Color::green},
    option::FontStyles{std::vector<FontStyle>{FontStyle::bold}}
  };
  
  // Update bar state
  while (true) {
    bar.tick();
    if (bar.is_completed())
      break;
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
  }

  return 0;
}

The above code will print a progress bar that goes from 0 to 100% at the rate of 1% every 100 ms.

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:

#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);

  ProgressBar bar{
    option::BarWidth{50},
    option::Start{"["},
    option::Fill{""},
    option::Lead{""},
    option::Remainder{"-"},
    option::End{" ]"},
    option::PostfixText{"Loading dependency 1/4"},
    option::ForegroundColor{Color::cyan},
    option::FontStyles{std::vector<FontStyle>{FontStyle::bold}}
  };

  // Update bar state
  bar.set_progress(10); // 10% done

  // do some work
  std::this_thread::sleep_for(std::chrono::milliseconds(800));

  bar.set_option(option::PostfixText{"Loading dependency 2/4"});  

  bar.set_progress(30); // 30% done

  // do some more work
  std::this_thread::sleep_for(std::chrono::milliseconds(700));

  bar.set_option(option::PostfixText{"Loading dependency 3/4"});  

  bar.set_progress(65); // 65% done

  // do final bit of work
  std::this_thread::sleep_for(std::chrono::milliseconds(900));

  bar.set_option(option::PostfixText{"Loaded dependencies!"});

  bar.set_progress(100); // all done

  // Show cursor
  show_console_cursor(true);

  return 0;
}

Showing Time Elapsed/Remaining

All progress bars and spinners in indicators support showing time elapsed and time remaining. Inspired by python's tqdm module, the format of this meter is [{elapsed}<{remaining}]:

#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{" ["},
    option::Fill{""},
    option::Lead{""},
    option::Remainder{"-"},
    option::End{"]"},
    option::PrefixText{"Training Gaze Network 👀"},
    option::ForegroundColor{Color::yellow},
    option::ShowElapsedTime{true},
    option::ShowRemainingTime{true},
    option::FontStyles{std::vector<FontStyle>{FontStyle::bold}}
  };

  // Update bar state
  while (true) {
    bar.tick();
    if (bar.is_completed())
      break;
    std::this_thread::sleep_for(std::chrono::milliseconds(1000));
  }

  // Show cursor
  show_console_cursor(true);

  return 0;
}

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().

#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? Use BlockProgressBar instead of ProgressBar. Thanks to this blog post for making BlockProgressBar an easy addition to the library.

#include <indicators/block_progress_bar.hpp>
#include <thread>
#include <chrono>

int main() {

  using namespace indicators;

  // Hide cursor
  show_console_cursor(false);

  BlockProgressBar bar{
    option::BarWidth{80},
    option::Start{"["},
    option::End{"]"},
    option::ForegroundColor{Color::white}  ,
    option::FontStyles{std::vector<FontStyle>{FontStyle::bold}}
  };
  
  // Update bar state
  auto progress = 0.0f;
  while (true) {
    bar.set_progress(progress);
    progress += 0.25f;
    if (bar.is_completed())
      break;
    std::this_thread::sleep_for(std::chrono::milliseconds(50));
  }

  // Show cursor
  show_console_cursor(true);

  return 0;
}

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.

#include <indicators/multi_progress.hpp>
#include <indicators/progress_bar.hpp>

int main() {
  using namespace indicators;
  // Configure first progress bar
  ProgressBar bar1{
    option::BarWidth{50},
    option::Start{"["},
    option::Fill{""},
    option::Lead{""},
    option::Remainder{" "},
    option::End{" ]"},
    option::ForegroundColor{Color::yellow},
    option::ShowElapsedTime{true},
    option::ShowRemainingTime{true},
    option::PrefixText{"Progress Bar #1 "},
    option::FontStyles{std::vector<FontStyle>{FontStyle::bold}}
  };

  // Configure second progress bar

  ProgressBar bar2{
    option::BarWidth{50},
    option::Start{"["},
    option::Fill{"="},
    option::Lead{">"},
    option::Remainder{" "},
    option::End{" ]"},
    option::ForegroundColor{Color::cyan},
    option::ShowElapsedTime{true},
    option::ShowRemainingTime{true},
    option::PrefixText{"Progress Bar #2 "},
    option::FontStyles{std::vector<FontStyle>{FontStyle::bold}}
  };
  
  // Configure third progress bar
  indicators::ProgressBar bar3{
    option::BarWidth{50},
    option::Start{"["},
    option::Fill{"#"},
    option::Lead{"#"},
    option::Remainder{" "},
    option::End{" ]"},
    option::ForegroundColor{Color::red},
    option::ShowElapsedTime{true},
    option::ShowRemainingTime{true},
    option::PrefixText{"Progress Bar #3 "},
    option::FontStyles{std::vector<FontStyle>{FontStyle::bold}}
  };

  // Construct MultiProgress object
  indicators::MultiProgress<indicators::ProgressBar, 3> bars(bar1, bar2, bar3);

  std::cout << "Multiple Progress Bars:\n";

  auto job1 = [&bars]() {
    while (true) {
      bars.tick<0>();
      if (bars.is_completed<0>())
        break;
      std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
  };

  auto job2 = [&bars]() {
    while (true) {
      bars.tick<1>();
      if (bars.is_completed<1>())
        break;
      std::this_thread::sleep_for(std::chrono::milliseconds(200));
    }
  };

  auto job3 = [&bars]() {
    while (true) {
      bars.tick<2>();
      if (bars.is_completed<2>())
        break;
      std::this_thread::sleep_for(std::chrono::milliseconds(60));
    }
  };

  std::thread first_job(job1);
  std::thread second_job(job2);
  std::thread third_job(job3);

  first_job.join();
  second_job.join();
  third_job.join();

  return 0;
}

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.

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.

#include <indicators/dynamic_progress.hpp>
#include <indicators/progress_bar.hpp>
using namespace indicators;

int main() {

  ProgressBar bar1{option::BarWidth{50}, option::ForegroundColor{Color::red},
                   option::ShowElapsedTime{true}, option::ShowRemainingTime{true},
                   option::PrefixText{"5c90d4a2d1a8: Downloading "}};

  ProgressBar bar2{option::BarWidth{50}, option::ForegroundColor{Color::yellow},
                   option::ShowElapsedTime{true}, option::ShowRemainingTime{true},
                   option::PrefixText{"22337bfd13a9: Downloading "}};

  ProgressBar bar3{option::BarWidth{50}, option::ForegroundColor{Color::green},
                   option::ShowElapsedTime{true}, option::ShowRemainingTime{true},
                   option::PrefixText{"10f26c680a34: Downloading "}};

  ProgressBar bar4{option::BarWidth{50}, option::ForegroundColor{Color::white},
                   option::ShowElapsedTime{true}, option::ShowRemainingTime{true},
                   option::PrefixText{"6364e0d7a283: Downloading "}};

  ProgressBar bar5{option::BarWidth{50}, option::ForegroundColor{Color::blue},
                   option::ShowElapsedTime{true}, option::ShowRemainingTime{true},
                   option::PrefixText{"ff1356ba118b: Downloading "}};

  ProgressBar bar6{option::BarWidth{50}, option::ForegroundColor{Color::cyan},
                   option::ShowElapsedTime{true}, option::ShowRemainingTime{true},
                   option::PrefixText{"5a17453338b4: Downloading "}};

  std::cout << termcolor::bold << termcolor::white << "Pulling image foo:bar/baz\n";

  // Construct with 3 progress bars. We'll add 3 more at a later point
  DynamicProgress<ProgressBar> bars(bar1, bar2, bar3);
  
  // Do not hide bars when completed
  bars.set_option(option::HideBarWhenComplete{false});

  std::thread fourth_job, fifth_job, sixth_job;

  auto job4 = [&bars](size_t i) {
    while (true) {
      bars[i].tick();
      if (bars[i].is_completed()) {
        bars[i].set_option(option::PrefixText{"6364e0d7a283: Pull complete "});
        bars[i].mark_as_completed();
        break;
      }
      std::this_thread::sleep_for(std::chrono::milliseconds(50));
    }
  };

  auto job5 = [&bars](size_t i) {
    while (true) {
      bars[i].tick();
      if (bars[i].is_completed()) {
        bars[i].set_option(option::PrefixText{"ff1356ba118b: Pull complete "});
        bars[i].mark_as_completed();
        break;
      }
      std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
  };

  auto job6 = [&bars](size_t i) {
    while (true) {
      bars[i].tick();
      if (bars[i].is_completed()) {
        bars[i].set_option(option::PrefixText{"5a17453338b4: Pull complete "});
        bars[i].mark_as_completed();
        break;
      }
      std::this_thread::sleep_for(std::chrono::milliseconds(40));
    }
  };

  auto job1 = [&bars, &bar6, &sixth_job, &job6]() {
    while (true) {
      bars[0].tick();
      if (bars[0].is_completed()) {
        bars[0].set_option(option::PrefixText{"5c90d4a2d1a8: Pull complete "});
        // bar1 is completed, adding bar6
        auto i = bars.push_back(bar6);
        sixth_job = std::thread(job6, i);
        sixth_job.join();
        break;
      }
      std::this_thread::sleep_for(std::chrono::milliseconds(140));
    }
  };

  auto job2 = [&bars, &bar5, &fifth_job, &job5]() {
    while (true) {
      bars[1].tick();
      if (bars[1].is_completed()) {
        bars[1].set_option(option::PrefixText{"22337bfd13a9: Pull complete "});
        // bar2 is completed, adding bar5
        auto i = bars.push_back(bar5);
        fifth_job = std::thread(job5, i);
        fifth_job.join();
        break;
      }
      std::this_thread::sleep_for(std::chrono::milliseconds(25));
    }
  };

  auto job3 = [&bars, &bar4, &fourth_job, &job4]() {
    while (true) {
      bars[2].tick();
      if (bars[2].is_completed()) {
        bars[2].set_option(option::PrefixText{"10f26c680a34: Pull complete "});
        // bar3 is completed, adding bar4
        auto i = bars.push_back(bar4);
        fourth_job = std::thread(job4, i);
        fourth_job.join();
        break;
      }
      std::this_thread::sleep_for(std::chrono::milliseconds(50));
    }
  };

  std::thread first_job(job1);
  std::thread second_job(job2);
  std::thread third_job(job3);

  third_job.join();
  second_job.join();
  first_job.join();

  std::cout << termcolor::bold << termcolor::green << "✔ Downloaded image foo/bar:baz" << std::endl;
  std::cout << termcolor::reset;

  return 0;
}

In the above code, notice the option bars.set_option(option::HideBarWhenComplete{true});. Yes, you can hide progress bars as and when they complete by setting this option to true. If you do so, the above example will look like this:

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:

{prefix} {spinner} {percentage} [{elapsed}<{remaining}] {postfix}

ProgressSpinner has a vector of strings: spinner_states. At each update, the spinner will pick the next string from this sequence to print to the console. The spinner state can be updated similarly to ProgressBars: Using either tick() or set_progress(value).

#include <indicators/progress_spinner.hpp>

int main() {
  using namespace indicators;
  indicators::ProgressSpinner spinner{
    option::PostfixText{"Checking credentials"},
    option::ForegroundColor{Color::yellow},
    option::SpinnerStates{std::vector<std::string>{"", "", "", "", "", "", "", ""}},
    option::FontStyles{std::vector<FontStyle>{FontStyle::bold}}
  };
 
  // Update spinner state
  auto job = [&spinner]() {
    while (true) {
      if (spinner.is_completed()) {
        spinner.set_option(option::ForegroundColor{Color::green});
        spinner.set_option(option::PrefixText{""});
        spinner.set_option(option::ShowSpinner{false});
        spinner.set_option(option::ShowPercentage{false});
        spinner.set_option(option::PostfixText{"Authenticated!"});
        spinner.mark_as_completed();	
        break;
      } else
        spinner.tick();
      std::this_thread::sleep_for(std::chrono::milliseconds(40));
    }
  };
  std::thread thread(job);
  thread.join();  

  return 0;
}

Decremental Progress

indicators allows you to easily control the progress direction, i.e., incremental or decremental progress by using option::ProgressType. To program a countdown progress bar, use option::ProgressType::decremental

#include <chrono>
#include <indicators/progress_bar.hpp>
#include <thread>
using namespace indicators;

int main() {

  ProgressBar bar{option::BarWidth{50},
                  option::ProgressType{ProgressType::decremental},
                  option::Start{"["},
                  option::Fill{""},
                  option::Lead{""},
                  option::Remainder{"-"},
                  option::End{"]"},
                  option::PostfixText{"Reverting System Restore"},
                  option::ForegroundColor{Color::yellow},
                  option::FontStyles{std::vector<FontStyle>{FontStyle::bold}}};

  // Update bar state
  while (true) {
    bar.tick();
    if (bar.is_completed())
      break;
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
  }

  std::cout << termcolor::bold << termcolor::white
            << "Task Failed Successfully\n" << termcolor::reset;

  return 0;
}

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:

#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;
}

Unicode Support

indicators supports multi-byte unicode characters in progress bars.

If the option::BarWidth is set, the library aims to respect this setting. When filling the bar, if the next Fill string has a display width that would exceed the bar width, then the library will fill the remainder of the bar with ' ' space characters instead.

See below an example of some progress bars, each with a bar width of 50, displaying different unicode characters:

#include <chrono>
#include <indicators/progress_bar.hpp>
#include <indicators/indeterminate_progress_bar.hpp>
#include <indicators/cursor_control.hpp>
#include <thread>

int main() {

    indicators::show_console_cursor(false);

    std::this_thread::sleep_for(std::chrono::milliseconds(2000));

    {
        // Plain old ASCII
        indicators::ProgressBar bar{
            indicators::option::BarWidth{50},
            indicators::option::Start{"["},
            indicators::option::Fill{"="},
            indicators::option::Lead{">"},
            indicators::option::Remainder{" "},
            indicators::option::End{" ]"},
            indicators::option::PostfixText{"Plain-old ASCII"},
            indicators::option::ForegroundColor{indicators::Color::green},
            indicators::option::FontStyles{
                std::vector<indicators::FontStyle>{indicators::FontStyle::bold}}
        };

        // Update bar state
        while (true) {
            bar.tick();
            if (bar.is_completed())
            break;
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }
    }

    {
        // Unicode
        indicators::ProgressBar bar{
            indicators::option::BarWidth{50},
            indicators::option::Start{"["},
            indicators::option::Fill{"驚くばかり"},
            indicators::option::Lead{">"},
            indicators::option::Remainder{" "},
            indicators::option::End{" ]"},
            indicators::option::PostfixText{"Japanese"},
            indicators::option::ForegroundColor{indicators::Color::yellow},
            indicators::option::FontStyles{
                std::vector<indicators::FontStyle>{indicators::FontStyle::bold}}
        };

        // Update bar state
        while (true) {
            bar.tick();
            if (bar.is_completed())
            break;
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }
    }

    {
        // Russian
        indicators::ProgressBar bar{
            indicators::option::BarWidth{50},
            indicators::option::Start{"["},
            indicators::option::Fill{"Потрясающие"},
            indicators::option::Remainder{" "},
            indicators::option::End{" ]"},
            indicators::option::PostfixText{"Russian"},
            indicators::option::ForegroundColor{indicators::Color::red},
            indicators::option::FontStyles{
                std::vector<indicators::FontStyle>{indicators::FontStyle::bold}}
        };

        // Update bar state
        while (true) {
            bar.tick();
            if (bar.is_completed())
            break;
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }
    }

    {
        // Greek
        indicators::ProgressBar bar{
            indicators::option::BarWidth{50},
            indicators::option::Start{"["},
            indicators::option::Fill{"Φοβερός"},
            indicators::option::Remainder{" "},
            indicators::option::End{" ]"},
            indicators::option::PostfixText{"Greek"},
            indicators::option::ForegroundColor{indicators::Color::cyan},
            indicators::option::FontStyles{
                std::vector<indicators::FontStyle>{indicators::FontStyle::bold}}
        };

        // Update bar state
        while (true) {
            bar.tick();
            if (bar.is_completed())
            break;
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }
    }

    {
        // Chinese
        indicators::ProgressBar bar{
            indicators::option::BarWidth{50},
            indicators::option::Start{"["},
            indicators::option::Fill{"太棒了"},
            indicators::option::Remainder{" "},
            indicators::option::End{" ]"},
            indicators::option::PostfixText{"Chinese"},
            indicators::option::ForegroundColor{indicators::Color::green},
            indicators::option::FontStyles{
                std::vector<indicators::FontStyle>{indicators::FontStyle::bold}}
        };

        // Update bar state
        while (true) {
            bar.tick();
            if (bar.is_completed())
            break;
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }        
    }

    {
        // Emojis
        indicators::ProgressBar bar{
            indicators::option::BarWidth{50},
            indicators::option::Start{"["},
            indicators::option::Fill{"🔥"},
            indicators::option::Lead{"🔥"},
            indicators::option::Remainder{" "},
            indicators::option::End{" ]"},
            indicators::option::PostfixText{"Emojis"},
            indicators::option::ForegroundColor{indicators::Color::white},
            indicators::option::FontStyles{
                std::vector<indicators::FontStyle>{indicators::FontStyle::bold}}
        };

        // Update bar state
        while (true) {
            bar.tick();
            if (bar.is_completed())
            break;
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }
    }

    {
        // Indeterminate progress bar
        indicators::IndeterminateProgressBar bar{
            indicators::option::BarWidth{50},
            indicators::option::Start{"["},
            indicators::option::Fill{""},
            indicators::option::Lead{"載入中"},
            indicators::option::End{" ]"},
            indicators::option::PostfixText{"Loading Progress Bar"},
            indicators::option::ForegroundColor{indicators::Color::yellow},
            indicators::option::FontStyles{
                std::vector<indicators::FontStyle>{indicators::FontStyle::bold}}
        };

        auto job = [&bar]() {
            std::this_thread::sleep_for(std::chrono::milliseconds(10000));
            bar.mark_as_completed();
        };
        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;
}

Building Samples

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

python3 utils/amalgamate/amalgamate.py -c single_include.json -s .

Contributing

Contributions are welcome, have a look at the CONTRIBUTING.md document for more information.

License

The project is available under the MIT license.

Comments
  • Make errors

    Make errors

    Just trying to build the source and examples - but using make - get the following error:

    johughes@ubuntu:~/Downloads/indicators-master/build$ make [ 3%] Building CXX object demo/CMakeFiles/demo.dir/demo.cpp.o /home/johughes/Downloads/indicators-master/demo/demo.cpp:1:10: fatal error: indicators.hpp: No such file or directory #include "indicators.hpp" ^~~~~~~~~~~~~~~~ compilation terminated. demo/CMakeFiles/demo.dir/build.make:62: recipe for target 'demo/CMakeFiles/demo.dir/demo.cpp.o' failed make[2]: *** [demo/CMakeFiles/demo.dir/demo.cpp.o] Error 1 CMakeFiles/Makefile2:85: recipe for target 'demo/CMakeFiles/demo.dir/all' failed make[1]: *** [demo/CMakeFiles/demo.dir/all] Error 2 Makefile:151: recipe for target 'all' failed make: *** [all] Error 2

    the previous cmake did not report any errors.

    opened by johughes99 11
  • API change - progress bar can be constructed with proper settings.

    API change - progress bar can be constructed with proper settings.

    Hi there!

    I would like to ask whether you would be open to the following changes.

    The rationale behind them is to make it possible, to create ProgressBar object with options given as constructor parameters, as with current approach it would extremaly difficult to do so.

    opened by dawidpilarski 7
  • Postfix string length grows

    Postfix string length grows

    Hello!

    I use prefix and postfix for my interface I use about 30 characters for postfix, but it prints 70 or more like this: -- Info Checksum is correct·········································

    My limit is 84 characters. Why does string length increase with empty characters?

    opened by dd4e 6
  • ProgressBar::tick() prints progress even if nothing has changed

    ProgressBar::tick() prints progress even if nothing has changed

    From my understanding calling tick() method will trigger the print function which will re-print the progress status regardless. Is this correct? Can I open a PR to update only if something has changed?

    https://github.com/p-ranav/indicators/blob/2291c8c39c031dda6007a68f8e725a0be5ba2ca7/include/indicators/progress_bar.hpp#L112-L119

    opened by amallia 6
  • remove bold output and default color to unspecified

    remove bold output and default color to unspecified

    Hi @p-ranav this is probably a bit controversial but I have modified the code so that a "unspecified" color is available (just the default color from the terminal) and made it the default. I also removed the default of making the font bold.

    Let me know if you don't want me to make these two things the default.

    Maybe we can add a setting for bold, and italic?

    opened by wolfv 5
  • "error: 'mutex' in namespace 'std' does not name a type"

    on windows, when I run the code, it will throw this error : "error: 'mutex' in namespace 'std' does not name a type". I google for it , somebody say "#include" cannt work on windows. I wanna know if there some solutions to solve this problem. thanks a lot.

    opened by qzylalala 5
  • Memoryleak on ProgressSpinner

    Memoryleak on ProgressSpinner

    D (03:00:03.997) HEAP: Iteration: 232000 (diff 304 bytes) V (03:00:04.006) Spinner: Created: 1407943886 V (03:00:04.011) Spinner: Destroyed: 1407943886 D (03:00:04.016) HEAP: Iteration: 231700 (diff 300 bytes) V (03:00:04.025) Spinner: Created: -1271674128 V (03:00:04.030) Spinner: Destroyed: -1271674128 D (03:00:04.035) HEAP: Iteration: 231396 (diff 304 bytes) V (03:00:04.044) Spinner: Created: 72749701 V (03:00:04.049) Spinner: Destroyed: 72749701 D (03:00:04.053) HEAP: Iteration: 231096 (diff 300 bytes) V (03:00:04.063) Spinner: Created: -1957109953 V (03:00:04.067) Spinner: Destroyed: -1957109953 D (03:00:04.073) HEAP: Iteration: 230792 (diff 304 bytes) V (03:00:04.082) Spinner: Created: 569508829 V (03:00:04.086) Spinner: Destroyed: 569508829 D (03:00:04.091) HEAP: Iteration: 230492 (diff 300 bytes)

    every instance 304 or 300 bytes leaked

    opened by drony 4
  • Can i re-use a prior defined bar rather than define two separated bars?

    Can i re-use a prior defined bar rather than define two separated bars?

    Is it possible to re-use a prior defined bar? as follows:

    using namespace indicators;
    indicators::ProgressBar bar {
            option::BarWidth{45},
            option::Start{"["},
            option::Fill{"■"},
            option::Lead{"■"},
            option::Remainder{" "},
            option::End{"]"},
            option::ShowPercentage{true},
            option::ShowElapsedTime{true},
            option::ShowRemainingTime{true},
            option::PrefixText{""}
    };
    
    bar.set_progress(0);
    for(int i = 0; i < 100; i++){
        bar.set_progress(i+1);
    }
    
    #re-use the bar again
    bar.set_progress(0);
    for(int j = 0; j < 100; j++){
        bar.set_progress(j+1);
    }
    

    The first works fine, but the second bar will be printed in a single new line for each update. So i am just wondering if there is a solution for this problem?

    Thanks.

    opened by YinLiLin 3
  • How to let indicator don't cover the print message?

    How to let indicator don't cover the print message?

    indicators is a great tool.

    it show the process dynamically, but when I need to print message in my code.

    the indicators bar will cover my print message will bar. and my message is disappeared.

    Is there any method can let me see the message, and indicators bar process meantime?

    opened by nickhuangxinyu 3
  • ProgressBar broken

    ProgressBar broken

    What could possibly be causing the progress bar to behave this way?

    image

    PS: I only updated the output to cerr instead of cout, but it should still work, right? If I use cout it doesn't print anything at all.

    opened by mirand863 3
  • Windows cursor movements

    Windows cursor movements

    The dynamic progress bar uses ANSI escape codes for moving up and erasing lines.

    This doesn't work on Windows (and I could not make it work using SetConsoleMode( ENABLE_VIRTUAL_TERMINAL_PROCESSING | ENABLE_VIRTUAL_TERMINAL_INPUT ) either).

    I found the following library for go which seems great: https://github.com/k0kubun/go-ansi

    The following code works fine on Windows:

    namespace cursor
    {
        void move_up(int lines)
        {
            move(0, -lines);
        }
    
        void move_down(int lines)
        {
            move(0, -lines);
        }
    
        void move_left(int cols)
        {
            move(-cols, 0);
        }
    
        void move_up(int cols)
        {
            move(cols, 0);
        }
    
        void move(int x, int y) {
            auto hStdout = GetStdHandle(STD_OUTPUT_HANDLE); 
            if (!hStdout) return;
    
            CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
            GetConsoleScreenBufferInfo(hStdout, &csbiInfo);
    
            COORD cursor;
    
            cursor.X = csbiInfo.dwCursorPosition.X + x;
            cursor.Y = csbiInfo.dwCursorPosition.Y + y;
            SetConsoleCursorPosition(hStdout, cursor);
        }
    
    }
    

    It would be nice to have more abstractions (also around finding the terminal windows size). Do you want to integrate these facilities into this library or should we create another one?

    opened by wolfv 3
  • conversion to ‘float’ from ‘double’ may alter its value [-Werror=float-conversion]

    conversion to ‘float’ from ‘double’ may alter its value [-Werror=float-conversion]

    warning while converting double to float

    .../indicators/include/indicators/progress_bar.hpp: In member function ‘void indicators::ProgressBar::print_progress(bool)’: .../indicators/include/indicators/progress_bar.hpp:325:79: error: conversion to ‘float’ from ‘double’ may alter its value [-Werror=float-conversion] writer.write(double(progress_) / double(max_progress) * 100.0f); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~ cc1plus: all warnings being treated as errors

    opened by IdoSagiv 0
  • Passing boost::optional ProgressBar handle (from inside DynamicProgress) to function for mutation

    Passing boost::optional ProgressBar handle (from inside DynamicProgress) to function for mutation

    Loving this repo so far, thanks for all your hard work. Any advice would be greatly appreciated. I've got a possible enhancement, but want to make sure I'm not missing anything on how I could do this via a workaround.

    In short, I'd like to have worker functions which can modify an optionally (via boost::optional) passed-in ProgressBar, which is inside a DynamicProgress in the application-level code.

    Say I have a a ProgressBars that I then pass into DynamicProgress dbar, like so:

    indicators::ProgressBar bar1{
          indicators::option::BarWidth{40},
          indicators::option::PrefixText{"progress bar 1"},
          indicators::option::PostfixText{"not mutated by function yet"}
    };
    indicators::ProgressBar bar2{
          indicators::option::BarWidth{40},
          indicators::option::PrefixText{"progress bar 2"},
          indicators::option::PostfixText{"not mutated by function yet"}
      };
    indicators::DynamicProgress<indicators::ProgressBar> dbar;
    dbar.push_back(bar1);
    dbar.push_back(bar2);
    

    I would then like to be able to pass the ProgressBar at dbar[0] to a function which mutates it, e.g. changes the progress or text, without having to pass the parent DynamicProgress. Being forced to pass the parent DynamicProgress is messy: it means that worker functions can't be passed individual progress bars without unnecessary code (e.g. having to first put the single progressbar in a dynamicprogress at the application level), and forces a clunky interface to the worker function because you also have to pass in the index of the bar inside the DynamicProgress.

    Minimum (not) working example of what I'd like to do:

    #include <indicators/progress_bar.hpp>
    #include <indicators/dynamic_progress.hpp>
    #include <boost/optional.hpp>
    
    void pbar_mutation_function(boost::optional<indicators::ProgressBar*> bar=boost::none);
    
    int main() {
        // build progressbars
        indicators::ProgressBar bar1{
            indicators::option::BarWidth{40},
            indicators::option::PrefixText{"progress bar 1"},
            indicators::option::PostfixText{"not mutated by function yet"}
        };
        indicators::ProgressBar bar2{
            indicators::option::BarWidth{40},
            indicators::option::PrefixText{"progress bar 2"},
            indicators::option::PostfixText{"not mutated by function yet"}
        };
        // insert it into a dynamic progress container
        indicators::DynamicProgress<indicators::ProgressBar> dbar;
        dbar.push_back(bar1);
        dbar.push_back(bar2);
        // pass the child progressbar "bar1" into mutation function
        pbar_mutation_function(&(dbar[0])); // this doesn't work :(
        return 0;
    }
    
    void pbar_mutation_function(boost::optional<indicators::ProgressBar*> bar){
        // update bar postfix text to notify you're in the mutation function
        if(bar){
          (*(*bar)).set_option(indicators::option::PostfixText{"inside bar mutation function"});
        }
        // in loop iterate up bar
        for(uint i=0; i<=100; i++){
          if(bar){
            (*(*bar)).set_option(indicators::option::PostfixText{"inside bar mutation function: i="+std::to_string(i)});
            (*(*bar)).tick();
          }
          std::this_thread::sleep_for(std::chrono::milliseconds(5));
        }
        // mark bar as complete
        if(bar){
          (*(*bar)).mark_as_completed();
        }
    }
    

    Desired behavior of above example Two progress bars are initialized on the console, but only bar1 gets iterated up.

    Observed behavior Neither bar gets modified. image

    opened by tmcg0 0
  • [bug] Cannot compile the sample codes with MSVC compiler on Windows.

    [bug] Cannot compile the sample codes with MSVC compiler on Windows.

    Building Commands

    git clone https://github.com/p-ranav/indicators
    cd indicators
    mkdir build && cd build
    vcvarsall x64
    cmake -DINDICATORS_SAMPLES=ON -DINDICATORS_DEMO=ON -GNinja ..
    cmake --build .
    

    Platform and Version

    • OS+System: Windows 11
    • CMake Version: 3.21.2
    • Ninja Version: 1.10.2
    • Compiler+Version: MSVC 2019

    Logs

    • Click to expand log
      C:\CPackages\indicators>git clone https://github.com/p-ranav/indicators
      Cloning into 'indicators'...
      remote: Enumerating objects: 1997, done.
      remote: Counting objects: 100% (171/171), done.
      remote: Compressing objects: 100% (41/41), done.
      remote: Total 1997 (delta 83), reused 162 (delta 83), pack-reused 1826
      Receiving objects: 100% (1997/1997), 34.55 MiB | 7.26 MiB/s, done.
      Resolving deltas: 100% (1120/1120), done.
      
      C:\CPackages\indicators>cd indicators
      
      C:\CPackages\indicators\indicators>mkdir build && cd build
      
      C:\CPackages\indicators\indicators\build>vcvarsall x64
      **********************************************************************
      ** Visual Studio 2019 Developer Command Prompt v16.11.11
      ** Copyright (c) 2021 Microsoft Corporation
      **********************************************************************
      [vcvarsall.bat] Environment initialized for: 'x64'
      
      C:\CPackages\indicators\indicators\build>cmake -DINDICATORS_SAMPLES=ON -DINDICATORS_DEMO=ON -GNinja ..
      -- The CXX compiler identification is MSVC 19.29.30141.0
      -- Detecting CXX compiler ABI info
      -- Detecting CXX compiler ABI info - done
      -- Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/MSVC/14.29.30133/bin/Hostx64/x64/cl.exe - skipped
      -- Detecting CXX compile features
      -- Detecting CXX compile features - done
      -- Looking for C++ include pthread.h
      -- Looking for C++ include pthread.h - not found
      -- Found Threads: TRUE
      -- Configuring done
      -- Generating done
      -- Build files have been written to: C:/CPackages/indicators/indicators/build
      
      C:\CPackages\indicators\indicators\build>cmake --build .
      
    • Log of cmake --build . is too long, so I save it into a .txt file and upload it:

      CompileError.txt

    Screenshots

    image

    opened by hwhsu1231 0
  • [question] An `std::range_error` exception in `intermediate_progress_bar.cpp`.

    [question] An `std::range_error` exception in `intermediate_progress_bar.cpp`.

    LINK: https://github.com/p-ranav/indicators/blob/master/samples/indeterminate_progress_bar.cpp

    Source Code (in case of updating)

    Click to expand the Source Code
    #include <chrono>
    #include <indicators/cursor_control.hpp>
    #include <indicators/indeterminate_progress_bar.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;
    }
    

    Screenshots

    image

    opened by hwhsu1231 0
  • No percentage indication on Windows

    No percentage indication on Windows

    When I try your very first example on Windows, there is no percentage indicator: image

    In PowerShell and Windows console, the progress bar does not even stay on the same line: image

    Is this the normal behavior on windows?

    opened by F-I-D-O 1
  • Compile error

    Compile error

    Hello I have the following error during compilation : D:\www\QT\untitled35\indicators\include\indicators\setting.hpp:184: erreur : C2955: 'indicators::details::option_idx': use of class template requires template argument list

    I'm just trying to compile the demo.cpp with qt creator (MSVC2019 64bits). I added the demo file and next setup the includepath in the .pro file. Any clue ? Regards

    opened by bzctoons 0
Releases(v2.2)
  • v2.2(May 3, 2021)

    • Fixed the NOMINMAX issue in MinGW build of indicators #76
    • Replaced #pragma once with #ifndef-define pairs to fix the single_include generation and avoid multiple-definition errors
    Source code(tar.gz)
    Source code(zip)
  • v2.1(May 3, 2021)

  • v2.0(Jan 7, 2021)

    • Closed #63 - Use unicode::display_width instead of os.str().size() in helper functions
    • Elevated #includes from being nested in the namespace.
    • Support older compilers with missing header.
    • Closed #67 - typo in terminal_size.hpp
    • Closed #68 - TERMCOLOR_HPP_ defined twice
    • Merged #69 to fix mingw compilation
    • Closed #72 - Using _WIN32 instead of _MSC_VER in macro and defining NOMINMAX correctly
    • Mitigated overflow when calculating ETA
    • Using floating point for remaining time calculation
    • Closed #80
    Source code(tar.gz)
    Source code(zip)
  • v1.9(May 25, 2020)

    • Fixed build issues in g++ caused by missing header #54
    • Auto-detecting terminal width to fill the remainder of the progress bar with empty spaces #56
      • Previously this was hard-coded to 10 spaces
    • Fixed multiple definitions in helper functions, e.g., cursor control #58
    • Implemented option::ProgressType which can be incremental or decremental - Provides an easy interface to implement decremental progress (a regressing bar) #59
    • Updated to latest version of termcolor #60
    • Improved Unicode support in progress bar
    Source code(tar.gz)
    Source code(zip)
  • v1.8(May 16, 2020)

    • IndeterminateProgressBar for modeling bars with unknown totals #43 #51
    • option::MaxProgress to configure the maximum progress for the bar. Default is 100. This enables sweeping over iterables, e.g., a vector of numbers. Example.
    • option::Stream to configure the output stream of progress bars, e.g., using std::stringstream or std::cerr instead of std::cout #22
    • option::FontStyles. The user can specify a vector of font styles, e.g., bold, italic etc. for the progress bar #38
    • New default for progress bar color: Color::unspecified
    • Abstraction for Cursor Movements to work better with Windows #48
    • Show/hide console cursor - Enables hiding the console cursor when progress bar is ticking - Removes the annoying flicker #48
    • Using amalgamate to generate single_include header file.
    Source code(tar.gz)
    Source code(zip)
  • v1.7(Feb 21, 2020)

    • Added DynamicProgress class for managing multiple progress bars dynamically https://github.com/p-ranav/indicators/pull/32
    • Fixed code style - Member names starting with underscore _ https://github.com/p-ranav/indicators/issues/24
    Source code(tar.gz)
    Source code(zip)
  • v1.6(Feb 11, 2020)

    • API Change - Progress bars can be constructed with a Settings object - create ProgressBar object with options given as constructor parameters #21
    • Added pkg-config file to make it easier to consume this package in build systems that support it, such as autotools, Meson, waf, SCons and build2 #27
    • In MultiProgress, elapsed time of each bar is now updated independently, instead of together #18
    • Remove code duplication and refactored for reuse #14 #15 #16 #17
    Source code(tar.gz)
    Source code(zip)
  • v1.5(Dec 18, 2019)

  • v1.4(Dec 18, 2019)

  • v1.3(Dec 17, 2019)

  • v1.2(Dec 17, 2019)

  • v1.1(Dec 16, 2019)

Owner
Pranav
Pranav
A library for interactive command line interfaces in modern C++

cli A cross-platform header only C++14 library for interactive command line interfaces (Cisco style) Features Header only Cross-platform (linux and wi

Daniele Pallastrelli 888 Dec 31, 2022
Table Maker for Modern C++

Source for the above image can be found here Table of Contents Quick Start Formatting Options Style Inheritance Model Word Wrapping Font Alignment Fon

Pranav 1.4k Dec 30, 2022
Contour - A modern C++ Terminal Emulator

contour is a modern terminal emulator, for everyday use. It is aiming for power users with a modern feature mindset.

Contour Terminal Emulator 1.1k Dec 28, 2022
ssheven - A modern SSH client for Mac OS 7/8/9.

ssheven - A modern SSH client for Mac OS 7/8/9.

null 480 Dec 29, 2022
Argument Parser for Modern C++

Highlights Single header file Requires C++17 MIT License Quick Start Simply include argparse.hpp and you're good to go. #include <argparse/argparse.hp

Pranav 1.5k Jan 1, 2023
easy to use, powerful & expressive command line argument parsing for modern C++ / single header / usage & doc generation

clipp - command line interfaces for modern C++ Easy to use, powerful and expressive command line argument handling for C++11/14/17 contained in a sing

André Müller 977 Dec 29, 2022
A modern frontend for Neovim.

A modern frontend for Neovim.

Rohit Pradhan 1.6k Jan 2, 2023
Free open-source modern C++17 / C++20 framework to create console, forms (GUI like WinForms) and unit test applications on Microsoft Windows, Apple macOS and Linux.

xtd Modern C++17/20 framework to create console (CLI), forms (GUI like WinForms) and tunit (unit tests like Microsoft Unit Testing Framework) applicat

Gammasoft 434 Dec 30, 2022
Modern C++ Undo / Redo framework

History Hello Developers! I present to you History, a modern C++ (C++17) Undo / Redo framework. My goal was to create a non-intrusive, compact and int

null 18 Dec 7, 2022
Activity Indicators for Modern C++

Highlights Thread-safe progress bars and spinners Header-only library. Grab a copy of include/indicators. Single-header version in single_include/indi

Pranav 2.3k Jan 9, 2023
TulipCell is an Excel add-in providing 100+ technical analysis indicators.

Tulip Cell Introduction Tulip Cell is an Excel add-in that provides the technical analysis functions from the Tulip Indicators library. Building Build

Tulip Charts LLC 28 Nov 8, 2022
Graphs the activity of a chia harvester in a linux terminal.

Chia Harvest Graph Monitor for Chia Harvesting Introduction The chiaharvestgraph tool will graph Chia Harvesting activity in a linux terminal. Use a 2

Bram Stolk 215 Dec 11, 2022
KDevelop plugin for automatic time tracking and metrics generated from your programming activity.

Wakatime KDevelop Plugin Installation instructions Make sure the project is configured to install to the directory of your choice: In KDevelop, select

snotr 6 Oct 13, 2021
A C-Beginner Project for Winter Code Activity

Whale Market - Winter Code From Jiacai Cui Email: [email protected] 1 Introduction 详细内容见:https://cui-jiacai.gitbook.io/whale-market/ 2 Tutori

Cui Jiacai 70 Jan 4, 2023
A modern day direct port of BOOM 2.02 for modern times. Aiming to tastefully continue the development of BOOM, in the style of TeamTNT.

ReBOOM ReBOOM is a continuation of the BOOM source port, version 2.02. what is it ReBOOM is a source port, directly ported from BOOM 2.02 with additio

Gibbon 12 Jul 27, 2022
C-based/Cached/Core Computer Vision Library, A Modern Computer Vision Library

Build Status Travis CI VM: Linux x64: Raspberry Pi 3: Jetson TX2: Backstory I set to build ccv with a minimalism inspiration. That was back in 2010, o

Liu Liu 6.9k Jan 6, 2023
Header-only, event based, tiny and easy to use libuv wrapper in modern C++ - now available as also shared/static library!

Do you have a question that doesn't require you to open an issue? Join the gitter channel. If you use uvw and you want to say thanks or support the pr

Michele Caini 1.5k Jan 1, 2023
A library for interactive command line interfaces in modern C++

cli A cross-platform header only C++14 library for interactive command line interfaces (Cisco style) Features Header only Cross-platform (linux and wi

Daniele Pallastrelli 888 Dec 31, 2022
Table Maker for Modern C++

Source for the above image can be found here Table of Contents Quick Start Formatting Options Style Inheritance Model Word Wrapping Font Alignment Fon

Pranav 1.4k Dec 30, 2022
Modern concurrency for C++. Tasks, executors, timers and C++20 coroutines to rule them all

concurrencpp, the C++ concurrency library concurrencpp is a tasking library for C++ allowing developers to write highly concurrent applications easily

David Haim 1.2k Jan 3, 2023