Code Monkey home page Code Monkey logo

indicators's Introduction

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 <indicators/cursor_control.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

WinLibs + MinGW

For Windows, if you use WinLibs like I do, the cmake command would look like this:

foo@bar:~$ mkdir build && cd build
foo@bar:~$ cmake -G "MinGW Makefiles" -DCMAKE_CXX_COMPILER="C:/WinLibs/mingw64/bin/g++.exe" -DINDICATORS_SAMPLES=ON -DINDICATORS_DEMO=ON ..
foo@bar:~$ make -j4

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.

indicators's People

Contributors

avighnac avatar chuvi-w avatar csparker247 avatar data-man avatar dawidpilarski avatar duncanmcn avatar felixguendling avatar godbyk avatar hyperxor avatar jsttzsf avatar lesleylai avatar madebr avatar myd7349 avatar offa avatar p-ranav avatar sean2077 avatar sheepgomeh avatar svgsponer avatar tocic avatar turuslan avatar usama-makhzoum avatar wolfv avatar xbreak avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

indicators's Issues

You should check out block drawing characters for a smooth animation

Hi, just heard about this libray from CppCast, and it looks sweet. I wondered, have you heard of the block drawing characters at https://en.wikipedia.org/wiki/Block_Elements? There are characters for 1/8th width blocks, 2/8th width blocks, 3/8th width blocks, etc. which can be used to make really smooth progress bars.

I used them for a progress bar I made for a python application:

screen-rec

The first few characters are full-width blocks, while the last character is whichever block character appropriate.

Initializing time for dynamic progress

We already have a property is_started, but currently time is accessed in the progress bar even if it's not initialized (started).

This happens when a progress bar is printed from a dynamic multi (or probably also regular multi) bar, but no set_progress has been called.

Instead it should either print 00:00, or --:-- for elapsed time if is_started is still false.

Utility like pv

It would be nice to have a utility like pv bundled with the library. Example:

gzip -c you.file | indicators [opts] > you.file.gz

Or some kind of option (for example, combine samples into one utility with options and screw on to this at the same time https://github.com/p-ranav/argparse).

Time Remaining overflow error

I'm seeing an overflow issue with the Time Remaining display for progress bars with long run times and large progress values. The Time Remaining starts at a reasonable run time (lets say 7 hours), decreases normally for a bit, then jumps down to zero and begins counting up. At some point, it resets back to zero and begins counting up again. This final cycle repeats for the duration of the process.

It takes awhile for my process to start up, so it's been hard to capture an example of the beginning state, but here's what it looks like when it cyclically resets back to zero:

indicator-reset

This seems like an integer overflow scenario in progress_bar.hpp:257:

        auto eta = std::chrono::nanoseconds(
            progress_ > 0 ? static_cast<long long>(elapsed_.count() *
                                                   max_progress / progress_)
                          : 0);

It doesn't take long (in nanoseconds) for elapsed_.count() * 1325697865 to overflow long long and my specific scenario can be quickly fixed by enforcing a specific order of operations: elapsed_.count() * (max_progress / progress_). I'm happy to submit this as a patch, but this only shifts the issue to an even larger value of max_progress. Should there also be some mention of this issue in the documentation?

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?

"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.

cursor_control.hpp show_console_cursor - multiple defintions

Not really looked into this - as I have a work around. But if you have multiple includes of cursor_control.hpp in separate source files you get the error:

pkcs11_progress.cpp:(.text+0x0): multiple definition of indicators::show_console_cursor(bool)'
pkcs11_ec_ecdsaAttacks.o:pkcs11_ec_ecdsaAttacks.cpp:(.text+0x376): first defined here
`

Single-header version

This is a really nice library. When deploying though it was a little bit more work than expected, given the library size. One possibility would be to have a single-header version of the library.
For example, CLI11 ( https://github.com/CLIUtils/CLI11) of JSON for modern C++ (https://github.com/nlohmann/json) follow this approach.

The single-header version can be generated with an amalgamation script. But, by looking at your code, it seems that it may be easier to use a single file, since many of the file have only a few lines of code.

If there is interest, but not enough development time, I would be happy to try to produce the one-file version by manually merging the existing code.

Including indicators library can trigger the byte symbol ambiguity problem on Windows

Example:

C:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\shared\rpcndr.h(192): error C2872: 'byte': ambiguous symbol
C:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\shared\rpcndr.h(191): note: could be 'unsigned char byte'
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29333\include\cstddef(29): note: or       'std::byte'
C:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\shared\rpcndr.h(962): error C2872: 'byte': ambiguous symbol
C:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\shared\rpcndr.h(191): note: could be 'unsigned char byte'
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29333\include\cstddef(29): note: or       'std::byte'
C:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\shared\rpcndr.h(970): error C2872: 'byte': ambiguous symbol
C:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\shared\rpcndr.h(191): note: could be 'unsigned char byte'
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29333\include\cstddef(29): note: or       'std::byte'
C:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\shared\wtypesbase.h(437): error C2872: 'byte': ambiguous symbol
C:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\shared\rpcndr.h(191): note: could be 'unsigned char byte'
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29333\include\cstddef(29): note: or       'std::byte'
C:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\shared\wtypesbase.h(462): error C2872: 'byte': ambiguous symbol
C:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\shared\rpcndr.h(191): note: could be 'unsigned char byte'
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29333\include\cstddef(29): note: or       'std::byte'
C:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\shared\wtypesbase.h(479): error C2872: 'byte': ambiguous symbol
C:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\shared\rpcndr.h(191): note: could be 'unsigned char byte'
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29333\include\cstddef(29): note: or       'std::byte'

And so on...

Currently, I resolved it using this solution: https://stackoverflow.com/questions/45957830/gdipluspath-throws-ambiguous-byte-for-cstddef-and-rpcndr-h

Specifically, the #define byte win_byte_override and #undef byte.

But my impression is that this should be solved in the library itself.

`apt`-like progress bar

I'm wondering if it's possible to achieve the same progress bar style that's being using in Ubuntu during the installation of the packages, i.e., this. Basically, the progress bar stick to the bottom of the terminal, and doesn't break the output.

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

Please don't re-define versions once published

It seems like the version 1.9 got re-tagged after it was published first.

This is a huge problem and causes trust isues.

It breaks package manager like Conan who check downloads against checksums (ref. conan-io/conan-center-index#4135)

and it raises the question of stability and trustworthy. "Is this a bug? Has the project been hacked?"

So please don't do this again. Once a version is tagged it should never be redefined.

font color unchanged

Kill the programme with Ctrl+C while it is running. The terminal can't change back to the original font color in Xshell.

bug

Windows - New line after each update

With this library, the progress bar is printed on a new line after each update. I've tried both cmd and PowerShell. Is Windows/its consoles supported?

TERMCOLOR_HPP_ define twice?

Why do you need to define TERMCOLOR_HPP_ twice in the header file in single_include, they are located on line 15 and line 667, which puzzles me

Doesn't work on Windows 10 (1909)

Hi,
Is this expected to work on Windows and Window 10?

Running on Windows 10 Pro: 10.0.18363 (1909) the contents of the progress bars contain lots of invalid characters:
image

The binary was built using Visual Studio 2019 16.6.0, cmake folders build, vanilla configure with samples enabled.

[Build Error] Missing header

While compiling the code from scratch, the compiler complains the following:

In file included from /Libraries/indicators/include/indicators/dynamic_progress.hpp:31,
                 from /Libraries/indicators/samples/dynamic_progress.cpp:1:
/Libraries/indicators/include/indicators/setting.hpp:199:27: error: ‘vector’ is not a member of ‘std’
  199 |     details::Setting<std::vector<std::string>, details::ProgressBarOption::spinner_states>;

The easy fix is to add #include <vector> to setting.hpp. This worked for me.

]MultiProgress API is not usable in real world scenarios

Because everything in MultiProgress Bar is templated it makes it not usable in cases, where amount of progress bars is not known at compile-time and this is a common case.

for example:

  • imagine cp program, that prints the progress. Amount of files is not known at compile time
  • article of bfilipek: https://www.bfilipek.com/2020/02/inidicators.html (where you are the author) shows docker progress bars. A number of those bars is not known at compile time.

Compilation failed with MinGW

mingw-w64-gcc 9.2
windows 10

error info:
indicators/terminal_size.hpp:22:10: fatal error: sys/ioctl.h: No such file or directory

Dynamic progress bar only prints when accessing progress bar

The current implementation only prints when indexing into the progress bar and doesn't expose the print_progress method.

This leads to problems when the last access to the progress bar sets e.g. an option to make the postfix text to "Finalize" it's not going to be printed for the last-to-finish bar.

I think the most formally correct way to implement this would be with either a proxy object (instead of returning a real reference from the accessor, or with a set_option / set_progress method that also takes an index.

What do you think?

#define NOMINMAX

Use the following define before #include <windows.h> to avoid build errors on Windows using Visual Studio:

#define NOMINMAX

More info here.

P.S.
I'm using single_include version.

Issues with mingw-w64 gcc 10.2.0 on windows 10

Hey, first of all, awesome work! 😃

I ran into some issues when building and running the demo and I would like to share my workarounds.

First error (among many others caused by the missing header)
$ mingw32-make.exe
g++ -pthread -std=c++11 -I../include -o demo demo.cpp
In file included from ../include/indicators/details/stream_helper.hpp:6,
                 from ../include/indicators/progress_bar.hpp:4,
                 from demo.cpp:4:
../include/indicators/termcolor.hpp: In function 'std::ostream& termcolor::red(std::ostream&)':
../include/indicators/termcolor.hpp:287:17: error: 'FOREGROUND_RED' was not declared in this scope
  287 |                 FOREGROUND_RED
      |                 ^~~~~~~~~~~~~~
../include/indicators/termcolor.hpp:287:17: note: the macro 'FOREGROUND_RED' had not yet been defined
In file included from c:\winlibs-x86_64-posix-seh-gcc-10.2.0-llvm-11.0.0-mingw-w64-8.0.0-r3\mingw64\x86_64-w64-mingw32\include\windows.h:74,
                 from ../include/indicators/terminal_size.hpp:7,
                 from ../include/indicators/progress_bar.hpp:12,
                 from demo.cpp:4:
c:\winlibs-x86_64-posix-seh-gcc-10.2.0-llvm-11.0.0-mingw-w64-8.0.0-r3\mingw64\x86_64-w64-mingw32\include\wincon.h:121: note: it was later defined here
  121 | #define FOREGROUND_RED 0x4

In indicators/termcolor.hpp, some Windows-specific headers are not included. I changed lines 36-44 (moved an endif) to this:

#elif defined(TERMCOLOR_OS_WINDOWS)
#if defined(_MSC_VER)
#if !defined(NOMINMAX)
#define NOMINMAX
#endif
#endif
#   include <io.h>
#   include <windows.h>
#endif

The second issue encountered was the from_bytes conversion in function std::wstring utf8_decode(const std::string &str) from indicators/display_width.hpp. I replaced it with the function from this answer. Though I'm not sure if this second workaround is portable.

Second issue appears when using an emoji as lead in the nested progress bar example
$ ./demo.exe
[■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ] Buying more snacks
Reading package list... Done
[==================================================] Done
{ 97% } ⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠸⠧ Restoring system state
{ ERROR } 98% Failed to restore system
[■-------------------------------------------------] Reverting system restore
⡀ 101% Checking credentials
✔ Authenticated!
  Compiling mission
 - ✔ Searching for the Moon
 - ✔ Contacting Kerbal headquarters
 - ✔ Designing spaceship
 - ✔ Launching rocket
 - 🌎terminate called after throwing an instance of 'std::range_error'
  what():  wstring_convert::from_bytes
Also posting it here if the stackoverflow answer gets deleted
// credits: https://stackoverflow.com/a/7154226
static inline std::wstring utf8_decode(const std::string& utf8)
{
    std::vector unicode;
    size_t i = 0;
    while (i < utf8.size())
    {
        unsigned long uni;
        size_t todo;
        bool error = false;
        unsigned char ch = utf8[i++];
        if (ch <= 0x7F)
        {
            uni = ch;
            todo = 0;
        }
        else if (ch <= 0xBF)
        {
            throw std::logic_error("not a UTF-8 string");
        }
        else if (ch <= 0xDF)
        {
            uni = ch&0x1F;
            todo = 1;
        }
        else if (ch <= 0xEF)
        {
            uni = ch&0x0F;
            todo = 2;
        }
        else if (ch <= 0xF7)
        {
            uni = ch&0x07;
            todo = 3;
        }
        else
        {
            throw std::logic_error("not a UTF-8 string");
        }
        for (size_t j = 0; j < todo; ++j)
        {
            if (i == utf8.size())
                throw std::logic_error("not a UTF-8 string");
            unsigned char ch = utf8[i++];
            if (ch < 0x80 || ch > 0xBF)
                throw std::logic_error("not a UTF-8 string");
            uni <<= 6;
            uni += ch & 0x3F;
        }
        if (uni >= 0xD800 && uni <= 0xDFFF)
            throw std::logic_error("not a UTF-8 string");
        if (uni > 0x10FFFF)
            throw std::logic_error("not a UTF-8 string");
        unicode.push_back(uni);
    }
    std::wstring utf16;
    for (size_t i = 0; i < unicode.size(); ++i)
    {
        unsigned long uni = unicode[i];
        if (uni <= 0xFFFF)
        {
            utf16 += (wchar_t)uni;
        }
        else
        {
            uni -= 0x10000;
            utf16 += (wchar_t)((uni >> 10) + 0xD800);
            utf16 += (wchar_t)((uni & 0x3FF) + 0xDC00);
        }
    }
    return utf16;
}

An #include <vector> would also be necessary for the above workaround.

My current environment is the following:

  • Windows 10 2004
  • terminus with WSL profile
  • indicators latest commit (af7c004 as of 11 november 2020)
  • mingw-w64 gcc from winlibs.com
$ g++ -v
Using built-in specs.
COLLECT_GCC=C:\winlibs-x86_64-posix-seh-gcc-10.2.0-llvm-11.0.0-mingw-w64-8.0.0-r3\mingw64\bin\g++.exe 
COLLECT_LTO_WRAPPER=c:/winlibs-x86_64-posix-seh-gcc-10.2.0-llvm-11.0.0-mingw-w64-8.0.0-r3/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/10.2.0/lto-wrapper.exe
Target: x86_64-w64-mingw32
Configured with: ../configure --prefix=/R/winlibs64_stage/inst_gcc-10.2.0/share/gcc --build=x86_64-w64-mingw32 --host=x86_64-w64-mingw32 --with-pkgversion='MinGW-W64 x86_64-posix-seh, built by Brecht Sanders' --with-tune=generic --enable-checking=release --enable-threads=posix --disable-sjlj-exceptions --disable-libunwind-exceptions --enable-serial-configure --disable-bootstrap --enable-host-shared --enable-plugin --enable-default-ssp --disable-rpath --disable-libstdcxx-pch --enable-libstdcxx-time=yes --disable-libstdcxx-debug --disable-version-specific-runtime-libs --with-stabs --disable-symvers --enable-languages=c,c++,fortran,lto,objc,obj-c++,d --disable-gold --disable-nls --disable-stage1-checking --disable-win32-registry --disable-multilib --enable-ld --enable-libquadmath --enable-libada --enable-libssp --enable-libstdcxx --enable-lto --enable-fully-dynamic-string --enable-libgomp --enable-graphite 
--enable-mingw-wildcard --with-mpc=/d/Prog/winlibs64_stage/custombuilt --with-mpfr=/d/Prog/winlibs64_stage/custombuilt --with-gmp=/d/Prog/winlibs64_stage/custombuilt --with-isl=/d/Prog/winlibs64_stage/custombuilt --enable-install-libiberty --enable-__cxa_atexit 
--without-included-gettext --with-diagnostics-color=auto --with-libiconv --with-system-zlib --with-build-sysroot=/R/winlibs64_stage/gcc-10.2.0/build_mingw/mingw-w64
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 10.2.0 (MinGW-W64 x86_64-posix-seh, built by Brecht Sanders)

Fix readme gif

The readme gif ends with a Kerbal mun landing. However we all know kerbals only landcrash on the mun

Please fix this so that the correct system state is indicated by indicator. 🌕🚀💥

[Code Style] member names start with underscore.

It is the dangerous naming convention, since implementations reserve all names starting with a double underscore and with single underscores following capital letters.

Even though it is not the case here, member names are started with an underscore and capital letter, it might be easy to fall into a trap.

It would be good to change the naming convention for underscores to follow the member name rather than precede the member name.

Indeterminate Progress Bar - update message

I want to use the Indeterminate Progress Bar in my program - but where I update the message to indicate the stage an algorithm is in. In the example the text "Checking for Updates" is shown. Is it possible to change this message dynamically whilst the bar is active?

cmake package config

os:windows

when build the package, we use
```
find_package(indicators 1.9.0 REQUIRED)
```
but the indicators_INCLUDE_PATH is empty.
can your solve my problem? 

and size_t terminal_width() can be defined as static or will cause the redefine problem

Can I set an interval time?

I use indicators in a Computationally intensive task, I find using the indicators will make the task slower. if I do not use the indicators, it will take 1min. If I use the indicators, it will take 22min.

I want the tick() not print the bar. Can I set an interval time? Such as print the bar every 5 seconds. I don't kown how to config it.

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.

free print progress

print_progress on the progress bars is a private function but if one desires to implement their own multi progress bar it's not easy without forking the project (as one can't externally declare a friend).

Is it really necessary for the function to be private?

I think there are legitimate use-cases not covered by the multi-progress implementations.

progress bar with unknown total

I have the case that for some downloads the total bytes are not advertised by the server. So instead of a regular progress bar I would like to have something going from left to right, e.g.

two frames:

[....<==>.....]
[........<==>.]

etc.

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?

terminal_size.hpp error

cols = csbi.srWindow.Right - csbi.srWindow.Left + 1; rows = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; return {static_cast<size_t>(rows), static_cast<size_t>(columns)};
columns should be cols

Indicator with set_progress does not display properly (cursor issue?)

Screenshot 2021-02-08 at 08 46 34

  using namespace indicators;

    // Hide cursor
    show_console_cursor(false);

    ProgressBar bar{
      option::BarWidth{50},
      option::Start{"["},
      option::Fill{"■"},
      option::Lead{"■"},
      option::Remainder{"-"},
      option::End{" ]"},
      option::PostfixText{"Starting simulator"},
      option::ForegroundColor{Color::cyan},
      option::FontStyles{std::vector<FontStyle>{FontStyle::bold}}
    };

here is the code for the first 10%

if ( !VLOG_IS_ON( 1 ) && Environment::isMasterRank() )
    {
        bar.set_option( option::PostfixText{ "Configuring "s}  );
        bar.set_progress( 10 );
    }

the same for the rest

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.