{"id":13480972,"url":"https://github.com/p-ranav/indicators","last_synced_at":"2025-05-14T16:14:16.568Z","repository":{"id":41478247,"uuid":"225650140","full_name":"p-ranav/indicators","owner":"p-ranav","description":"Activity Indicators for Modern C++","archived":false,"fork":false,"pushed_at":"2024-08-05T13:08:01.000Z","size":35418,"stargazers_count":3015,"open_issues_count":34,"forks_count":237,"subscribers_count":60,"default_branch":"master","last_synced_at":"2024-10-29T15:35:01.266Z","etag":null,"topics":["activity-indicator","cpp","cpp11","elapsed-time","format","formatted-text","header-only","library","lightweight","loading-animations","loading-indicator","mit-license","multiprogress","progress-bar","progress-spinner","single-header","single-header-lib","spinners","termcolor","terminal-colors"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/p-ranav.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-12-03T15:14:14.000Z","updated_at":"2024-10-29T13:12:55.000Z","dependencies_parsed_at":"2024-11-19T11:02:17.225Z","dependency_job_id":"82ea6634-f3bf-43ad-b723-a443eb05e0b3","html_url":"https://github.com/p-ranav/indicators","commit_stats":{"total_commits":349,"total_committers":25,"mean_commits":13.96,"dds":"0.15186246418338112","last_synced_commit":"4ea716116d37a4797feca81104b20a3aad3e0b63"},"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/p-ranav%2Findicators","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/p-ranav%2Findicators/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/p-ranav%2Findicators/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/p-ranav%2Findicators/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/p-ranav","download_url":"https://codeload.github.com/p-ranav/indicators/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248161242,"owners_count":21057552,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["activity-indicator","cpp","cpp11","elapsed-time","format","formatted-text","header-only","library","lightweight","loading-animations","loading-indicator","mit-license","multiprogress","progress-bar","progress-spinner","single-header","single-header-lib","spinners","termcolor","terminal-colors"],"created_at":"2024-07-31T17:00:47.146Z","updated_at":"2025-05-14T16:14:16.562Z","avatar_url":"https://github.com/p-ranav.png","language":"C++","readme":"\u003cp align=\"center\"\u003e\n  \u003cimg height=\"70\" src=\"img/logo.png\"/\u003e  \n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://www.codacy.com/manual/p-ranav/indicators?utm_source=github.com\u0026amp;utm_medium=referral\u0026amp;utm_content=p-ranav/indicators\u0026amp;utm_campaign=Badge_Grade\"\u003e\n    \u003cimg src=\"https://api.codacy.com/project/badge/Grade/93401e73f250407cb32445afec4e3e99\" alt=\"codacy\"/\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/p-ranav/indicators/blob/master/LICENSE\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/License-MIT-yellow.svg\" alt=\"license\"/\u003e\n  \u003c/a\u003e\n  \u003cimg src=\"https://img.shields.io/badge/version-2.3-blue.svg?cacheSeconds=2592000\" alt=\"version\"/\u003e\n\u003c/p\u003e\n\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"img/demo.gif\"/\u003e \n\u003c/p\u003e\n\n## Highlights\n\n* Thread-safe progress bars and spinners\n* Header-only library. Grab a copy of `include/indicators`. \n* Single-header version in `single_include/indicators`.\n* Source for the above GIF can be found [here](demo/demo.cpp)\n* MIT License\n\n## Table of Contents\n\n*    Supported Indicators\n     *    [Basic Progress Bar](#basic-progress-bar)\n     *    [Indeterminate Progress Bar](#indeterminate-progress-bar)\n     *    [Block Progress Bar](#block-progress-bar)\n     *    [Multi Progress](#multiprogress)\n     *    [Dynamic Progress](#dynamicprogress)\n     *    [Progress Spinner](#progress-spinner)\n*    Additional Samples\n     *    [Decremental Progress](#decremental-progress)\n     *    [Working with Iterables](#working-with-iterables)\n     *    [Unicode Support](#unicode-support)\n*    [Building Samples](#building-samples)\n*    [Generating Single Header](#generating-single-header)\n*    [Contributing](#contributing)\n*    [License](#license)\n\n## Basic Progress bar\n\nTo 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:\n\n```\n{prefix} {start} {fill} {lead} {remaining} {end} {percentage} [{elapsed}\u003c{remaining}] {postfix}\n         ^^^^^^^^^^^^^ Bar Width ^^^^^^^^^^^^^^^   \n```\n\nThe amount of progress in ProgressBar is maintained as a `size_t` in range `[0, 100]`. When progress reaches 100, the progression is complete. \n\nFrom application-level code, there are two ways in which you can update this progress:\n\n### Update progress using `bar.tick()`\n\nYou can update the progress bar using `bar.tick()` which increments progress by exactly `1%`.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"img/progress_bar_tick.gif\"/\u003e  \n\u003c/p\u003e\n\n```cpp\n#include \u003cindicators/progress_bar.hpp\u003e\n#include \u003cthread\u003e\n#include \u003cchrono\u003e\n\nint main() {\n  using namespace indicators;\n  ProgressBar bar{\n    option::BarWidth{50},\n    option::Start{\"[\"},\n    option::Fill{\"=\"},\n    option::Lead{\"\u003e\"},\n    option::Remainder{\" \"},\n    option::End{\"]\"},\n    option::PostfixText{\"Extracting Archive\"},\n    option::ForegroundColor{Color::green},\n    option::ShowPercentage{true},\n    option::FontStyles{std::vector\u003cFontStyle\u003e{FontStyle::bold}}\n  };\n  \n  // Update bar state\n  while (true) {\n    bar.tick();\n    if (bar.is_completed())\n      break;\n    std::this_thread::sleep_for(std::chrono::milliseconds(100));\n  }\n\n  return 0;\n}\n```\n\nThe above code will print a progress bar that goes from 0 to 100% at the rate of 1% every 100 ms.\n\n### Updating progress using `bar.set_progress(value)`\n\nIf you'd rather control progress of the bar in discrete steps, consider using `bar.set_progress(value)`. Example:\n\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"img/progress_bar_set_progress.gif\"/\u003e  \n\u003c/p\u003e\n\n```cpp\n#include \u003cchrono\u003e\n#include \u003cindicators/cursor_control.hpp\u003e\n#include \u003cindicators/progress_bar.hpp\u003e\n#include \u003cthread\u003e\n\nint main() {\n  using namespace indicators;\n\n  // Hide cursor\n  show_console_cursor(false);\n\n  ProgressBar bar{\n    option::BarWidth{50},\n    option::Start{\"[\"},\n    option::Fill{\"■\"},\n    option::Lead{\"■\"},\n    option::Remainder{\"-\"},\n    option::End{\" ]\"},\n    option::PostfixText{\"Loading dependency 1/4\"},\n    option::ForegroundColor{Color::cyan},\n    option::ShowPercentage{true},\n    option::FontStyles{std::vector\u003cFontStyle\u003e{FontStyle::bold}}  };\n\n  // Update bar state\n  bar.set_progress(10); // 10% done\n\n  // do some work\n  std::this_thread::sleep_for(std::chrono::milliseconds(800));\n\n  bar.set_option(option::PostfixText{\"Loading dependency 2/4\"});  \n\n  bar.set_progress(30); // 30% done\n\n  // do some more work\n  std::this_thread::sleep_for(std::chrono::milliseconds(700));\n\n  bar.set_option(option::PostfixText{\"Loading dependency 3/4\"});  \n\n  bar.set_progress(65); // 65% done\n\n  // do final bit of work\n  std::this_thread::sleep_for(std::chrono::milliseconds(900));\n\n  bar.set_option(option::PostfixText{\"Loaded dependencies!\"});\n\n  bar.set_progress(100); // all done\n\n  // Show cursor\n  show_console_cursor(true);\n\n  return 0;\n}\n```\n\n### Showing Time Elapsed/Remaining\n\nAll progress bars and spinners in `indicators` support showing time elapsed and time remaining. Inspired by python's [tqdm](https://github.com/tqdm/tqdm) module, the format of this meter is `[{elapsed}\u003c{remaining}]`:\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"img/time_meter.gif\"/\u003e  \n\u003c/p\u003e\n\n```cpp\n#include \u003cchrono\u003e\n#include \u003cindicators/cursor_control.hpp\u003e\n#include \u003cindicators/progress_bar.hpp\u003e\n#include \u003cthread\u003e\n\nint main() {\n  using namespace indicators;\n\n  // Hide cursor\n  show_console_cursor(false);\n\n  indicators::ProgressBar bar{\n    option::BarWidth{50},\n    option::Start{\" [\"},\n    option::Fill{\"█\"},\n    option::Lead{\"█\"},\n    option::Remainder{\"-\"},\n    option::End{\"]\"},\n    option::PrefixText{\"Training Gaze Network 👀\"},\n    option::ForegroundColor{Color::yellow},\n    option::ShowPercentage{true},\n    option::ShowElapsedTime{true},\n    option::ShowRemainingTime{true},\n    option::FontStyles{std::vector\u003cFontStyle\u003e{FontStyle::bold}}\n  };\n\n  // Update bar state\n  while (true) {\n    bar.tick();\n    if (bar.is_completed())\n      break;\n    std::this_thread::sleep_for(std::chrono::milliseconds(1000));\n  }\n\n  // Show cursor\n  show_console_cursor(true);\n\n  return 0;\n}\n```\n\n## Indeterminate Progress Bar\n\nYou 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. \n\nUse 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. \n\nWhen you know progress is complete, simply call `bar.mark_as_completed()`. \n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"img/indeterminate_progress_bar.gif\"/\u003e  \n\u003c/p\u003e\n\n```cpp\n#include \u003cchrono\u003e\n#include \u003cindicators/indeterminate_progress_bar.hpp\u003e\n#include \u003cindicators/cursor_control.hpp\u003e\n#include \u003cindicators/termcolor.hpp\u003e\n#include \u003cthread\u003e\n\nint main() {\n  indicators::IndeterminateProgressBar bar{\n      indicators::option::BarWidth{40},\n      indicators::option::Start{\"[\"},\n      indicators::option::Fill{\"·\"},\n      indicators::option::Lead{\"\u003c==\u003e\"},\n      indicators::option::End{\"]\"},\n      indicators::option::PostfixText{\"Checking for Updates\"},\n      indicators::option::ForegroundColor{indicators::Color::yellow},\n      indicators::option::FontStyles{\n          std::vector\u003cindicators::FontStyle\u003e{indicators::FontStyle::bold}}\n  };\n\n  indicators::show_console_cursor(false);\n\n  auto job = [\u0026bar]() {\n    std::this_thread::sleep_for(std::chrono::milliseconds(10000));\n    bar.mark_as_completed();\n    std::cout \u003c\u003c termcolor::bold \u003c\u003c termcolor::green \n        \u003c\u003c \"System is up to date!\\n\" \u003c\u003c termcolor::reset;\n  };\n  std::thread job_completion_thread(job);\n\n  // Update bar state\n  while (!bar.is_completed()) {\n    bar.tick();\n    std::this_thread::sleep_for(std::chrono::milliseconds(100));\n  }\n\n  job_completion_thread.join();\n  \n  indicators::show_console_cursor(true);  \n  return 0;\n}\n```\n\n## Block Progress Bar\n\nAre you in need of a smooth block progress bar using [unicode block elements](https://en.wikipedia.org/wiki/Block_Elements)? Use `BlockProgressBar` instead of `ProgressBar`. Thanks to [this blog post](https://mike42.me/blog/2018-06-make-better-cli-progress-bars-with-unicode-block-characters) for making `BlockProgressBar` an easy addition to the library. \n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"img/block_progress_bar.gif\"/\u003e  \n\u003c/p\u003e\n\n```cpp\n#include \u003cindicators/block_progress_bar.hpp\u003e\n#include \u003cindicators/cursor_control.hpp\u003e\n#include \u003cthread\u003e\n#include \u003cchrono\u003e\n\nint main() {\n\n  using namespace indicators;\n\n  // Hide cursor\n  show_console_cursor(false);\n\n  BlockProgressBar bar{\n    option::BarWidth{80},\n    option::Start{\"[\"},\n    option::End{\"]\"},\n    option::ForegroundColor{Color::white}  ,\n    option::ShowPercentage{true},\n    option::FontStyles{std::vector\u003cFontStyle\u003e{FontStyle::bold}}\n  };\n  \n  // Update bar state\n  auto progress = 0.0f;\n  while (true) {\n    bar.set_progress(progress);\n    progress += 0.25f;\n    if (bar.is_completed())\n      break;\n    std::this_thread::sleep_for(std::chrono::milliseconds(50));\n  }\n\n  // Show cursor\n  show_console_cursor(true);\n\n  return 0;\n}\n```\n\n## MultiProgress\n\n`indicators` supports management of multiple progress bars with the `MultiProgress` class template. \n\n`template \u003ctypename Indicator, size_t count\u003e 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.\n\nUse this class if you know the number of progress bars to manage at compile time.\n\nBelow is an example `MultiProgress` object that manages three `ProgressBar` objects.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"img/multi_progress.gif\"/\u003e  \n\u003c/p\u003e\n\n```cpp\n#include \u003cindicators/multi_progress.hpp\u003e\n#include \u003cindicators/progress_bar.hpp\u003e\n\nint main() {\n  using namespace indicators;\n  // Configure first progress bar\n  ProgressBar bar1{\n    option::BarWidth{50},\n    option::Start{\"[\"},\n    option::Fill{\"■\"},\n    option::Lead{\"■\"},\n    option::Remainder{\" \"},\n    option::End{\" ]\"},\n    option::ForegroundColor{Color::yellow},\n    option::ShowPercentage{true},\n    option::ShowElapsedTime{true},\n    option::ShowRemainingTime{true},\n    option::PrefixText{\"Progress Bar #1 \"},\n    option::FontStyles{std::vector\u003cFontStyle\u003e{FontStyle::bold}}\n  };\n\n  // Configure second progress bar\n\n  ProgressBar bar2{\n    option::BarWidth{50},\n    option::Start{\"[\"},\n    option::Fill{\"=\"},\n    option::Lead{\"\u003e\"},\n    option::Remainder{\" \"},\n    option::End{\" ]\"},\n    option::ForegroundColor{Color::cyan},\n    option::ShowPercentage{true},\n    option::ShowElapsedTime{true},\n    option::ShowRemainingTime{true},\n    option::PrefixText{\"Progress Bar #2 \"},\n    option::FontStyles{std::vector\u003cFontStyle\u003e{FontStyle::bold}}\n  };\n  \n  // Configure third progress bar\n  indicators::ProgressBar bar3{\n    option::BarWidth{50},\n    option::Start{\"[\"},\n    option::Fill{\"#\"},\n    option::Lead{\"#\"},\n    option::Remainder{\" \"},\n    option::End{\" ]\"},\n    option::ForegroundColor{Color::red},\n    option::ShowPercentage{true},\n    option::ShowElapsedTime{true},\n    option::ShowRemainingTime{true},\n    option::PrefixText{\"Progress Bar #3 \"},\n    option::FontStyles{std::vector\u003cFontStyle\u003e{FontStyle::bold}}\n  };\n\n  // Construct MultiProgress object\n  indicators::MultiProgress\u003cindicators::ProgressBar, 3\u003e bars(bar1, bar2, bar3);\n\n  std::cout \u003c\u003c \"Multiple Progress Bars:\\n\";\n\n  auto job1 = [\u0026bars]() {\n    while (true) {\n      bars.tick\u003c0\u003e();\n      if (bars.is_completed\u003c0\u003e())\n        break;\n      std::this_thread::sleep_for(std::chrono::milliseconds(100));\n    }\n  };\n\n  auto job2 = [\u0026bars]() {\n    while (true) {\n      bars.tick\u003c1\u003e();\n      if (bars.is_completed\u003c1\u003e())\n        break;\n      std::this_thread::sleep_for(std::chrono::milliseconds(200));\n    }\n  };\n\n  auto job3 = [\u0026bars]() {\n    while (true) {\n      bars.tick\u003c2\u003e();\n      if (bars.is_completed\u003c2\u003e())\n        break;\n      std::this_thread::sleep_for(std::chrono::milliseconds(60));\n    }\n  };\n\n  std::thread first_job(job1);\n  std::thread second_job(job2);\n  std::thread third_job(job3);\n\n  first_job.join();\n  second_job.join();\n  third_job.join();\n\n  return 0;\n}\n```\n\n## DynamicProgress\n\n`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. \n\nTo 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)`.  \n\nUse this class if you don't know the number of progress bars at compile time.\n\nBelow is an example `DynamicProgress` object that manages six `ProgressBar` objects. Three of these bars are added dynamically.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"img/dynamic_progress_bar.gif\"/\u003e  \n\u003c/p\u003e\n\n```cpp\n#include \u003cindicators/dynamic_progress.hpp\u003e\n#include \u003cindicators/progress_bar.hpp\u003e\nusing namespace indicators;\n\nint main() {\n\n  auto bar1 = std::make_unique\u003cProgressBar\u003e(option::BarWidth{50},\n                   option::ForegroundColor{Color::red},\n                   option::ShowElapsedTime{true},\n                   option::ShowRemainingTime{true},\n                   option::PrefixText{\"5c90d4a2d1a8: Downloading \"},\n                   indicators::option::FontStyles{\n                       std::vector\u003cindicators::FontStyle\u003e{indicators::FontStyle::bold}});\n\n  auto bar2 = std::make_unique\u003cProgressBar\u003e(option::BarWidth{50},\n                   option::ForegroundColor{Color::yellow},\n                   option::ShowElapsedTime{true},\n                   option::ShowRemainingTime{true},\n                   option::PrefixText{\"22337bfd13a9: Downloading \"},\n                   indicators::option::FontStyles{\n                       std::vector\u003cindicators::FontStyle\u003e{indicators::FontStyle::bold}});\n\n  auto bar3 = std::make_unique\u003cProgressBar\u003e(option::BarWidth{50},\n                   option::ForegroundColor{Color::green},\n                   option::ShowElapsedTime{true},\n                   option::ShowRemainingTime{true},\n                   option::PrefixText{\"10f26c680a34: Downloading \"},\n                   indicators::option::FontStyles{\n                       std::vector\u003cindicators::FontStyle\u003e{indicators::FontStyle::bold}});\n\n  auto bar4 = std::make_unique\u003cProgressBar\u003e(option::BarWidth{50},\n                   option::ForegroundColor{Color::white},\n                   option::ShowElapsedTime{true},\n                   option::ShowRemainingTime{true},\n                   option::PrefixText{\"6364e0d7a283: Downloading \"},\n                   indicators::option::FontStyles{\n                       std::vector\u003cindicators::FontStyle\u003e{indicators::FontStyle::bold}});\n\n  auto bar5 = std::make_unique\u003cProgressBar\u003e(option::BarWidth{50},\n                   option::ForegroundColor{Color::blue},\n                   option::ShowElapsedTime{true},\n                   option::ShowRemainingTime{true},\n                   option::PrefixText{\"ff1356ba118b: Downloading \"},\n                   indicators::option::FontStyles{\n                       std::vector\u003cindicators::FontStyle\u003e{indicators::FontStyle::bold}});\n\n  auto bar6 = std::make_unique\u003cProgressBar\u003e(option::BarWidth{50},\n                   option::ForegroundColor{Color::cyan},\n                   option::ShowElapsedTime{true},\n                   option::ShowRemainingTime{true},\n                   option::PrefixText{\"5a17453338b4: Downloading \"},\n                   indicators::option::FontStyles{\n                       std::vector\u003cindicators::FontStyle\u003e{indicators::FontStyle::bold}});\n\n  std::cout \u003c\u003c termcolor::bold \u003c\u003c termcolor::white \u003c\u003c \"Pulling image foo:bar/baz\\n\";\n\n  // Construct with 3 progress bars. We'll add 3 more at a later point\n  DynamicProgress\u003cProgressBar\u003e bars(bar1, bar2, bar3);\n\n  // Do not hide bars when completed\n  bars.set_option(option::HideBarWhenComplete{false});\n\n  std::thread fourth_job, fifth_job, sixth_job;\n\n  auto job4 = [\u0026bars](size_t i) {\n    while (true) {\n      bars[i].tick();\n      if (bars[i].is_completed()) {\n        bars[i].set_option(option::PrefixText{\"6364e0d7a283: Pull complete \"});\n        bars[i].mark_as_completed();\n        break;\n      }\n      std::this_thread::sleep_for(std::chrono::milliseconds(50));\n    }\n  };\n\n  auto job5 = [\u0026bars](size_t i) {\n    while (true) {\n      bars[i].tick();\n      if (bars[i].is_completed()) {\n        bars[i].set_option(option::PrefixText{\"ff1356ba118b: Pull complete \"});\n        bars[i].mark_as_completed();\n        break;\n      }\n      std::this_thread::sleep_for(std::chrono::milliseconds(100));\n    }\n  };\n\n  auto job6 = [\u0026bars](size_t i) {\n    while (true) {\n      bars[i].tick();\n      if (bars[i].is_completed()) {\n        bars[i].set_option(option::PrefixText{\"5a17453338b4: Pull complete \"});\n        bars[i].mark_as_completed();\n        break;\n      }\n      std::this_thread::sleep_for(std::chrono::milliseconds(40));\n    }\n  };\n\n  auto job1 = [\u0026bars, \u0026bar6, \u0026sixth_job, \u0026job6]() {\n    while (true) {\n      bars[0].tick();\n      if (bars[0].is_completed()) {\n        bars[0].set_option(option::PrefixText{\"5c90d4a2d1a8: Pull complete \"});\n        // bar1 is completed, adding bar6\n        auto i = bars.push_back(std::move(bar6));\n        sixth_job = std::thread(job6, i);\n        sixth_job.join();\n        break;\n      }\n      std::this_thread::sleep_for(std::chrono::milliseconds(140));\n    }\n  };\n\n  auto job2 = [\u0026bars, \u0026bar5, \u0026fifth_job, \u0026job5]() {\n    while (true) {\n      bars[1].tick();\n      if (bars[1].is_completed()) {\n        bars[1].set_option(option::PrefixText{\"22337bfd13a9: Pull complete \"});\n        // bar2 is completed, adding bar5\n        auto i = bars.push_back(std::move(bar5));\n        fifth_job = std::thread(job5, i);\n        fifth_job.join();\n        break;\n      }\n      std::this_thread::sleep_for(std::chrono::milliseconds(25));\n    }\n  };\n\n  auto job3 = [\u0026bars, \u0026bar4, \u0026fourth_job, \u0026job4]() {\n    while (true) {\n      bars[2].tick();\n      if (bars[2].is_completed()) {\n        bars[2].set_option(option::PrefixText{\"10f26c680a34: Pull complete \"});\n        // bar3 is completed, adding bar4\n        auto i = bars.push_back(std::move(bar4));\n        fourth_job = std::thread(job4, i);\n        fourth_job.join();\n        break;\n      }\n      std::this_thread::sleep_for(std::chrono::milliseconds(50));\n    }\n  };\n\n  std::thread first_job(job1);\n  std::thread second_job(job2);\n  std::thread third_job(job3);\n\n  third_job.join();\n  second_job.join();\n  first_job.join();\n\n  std::cout \u003c\u003c termcolor::bold \u003c\u003c termcolor::green \u003c\u003c \"✔ Downloaded image foo/bar:baz\" \u003c\u003c std::endl;\n  std::cout \u003c\u003c termcolor::reset;\n\n  return 0;\n}\n```\n\nIn 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:\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"img/dynamic_progress_bar_hide_completed.gif\"/\u003e  \n\u003c/p\u003e\n\n## Progress Spinner\n\nTo 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:\n\n```\n{prefix} {spinner} {percentage} [{elapsed}\u003c{remaining}] {postfix}\n```\n\nProgressSpinner 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)`. \n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"img/progress_spinner.gif\"/\u003e  \n\u003c/p\u003e\n\n```cpp\n#include \u003cindicators/progress_spinner.hpp\u003e\n\nint main() {\n  using namespace indicators;\n  indicators::ProgressSpinner spinner{\n    option::PostfixText{\"Checking credentials\"},\n    option::ForegroundColor{Color::yellow},\n    option::SpinnerStates{std::vector\u003cstd::string\u003e{\"⠈\", \"⠐\", \"⠠\", \"⢀\", \"⡀\", \"⠄\", \"⠂\", \"⠁\"}},\n    option::FontStyles{std::vector\u003cFontStyle\u003e{FontStyle::bold}}\n  };\n \n  // Update spinner state\n  auto job = [\u0026spinner]() {\n    while (true) {\n      if (spinner.is_completed()) {\n        spinner.set_option(option::ForegroundColor{Color::green});\n        spinner.set_option(option::PrefixText{\"✔\"});\n        spinner.set_option(option::ShowSpinner{false});\n        spinner.set_option(option::ShowPercentage{false});\n        spinner.set_option(option::PostfixText{\"Authenticated!\"});\n        spinner.mark_as_completed();\t\n        break;\n      } else\n        spinner.tick();\n      std::this_thread::sleep_for(std::chrono::milliseconds(40));\n    }\n  };\n  std::thread thread(job);\n  thread.join();  \n\n  return 0;\n}\n```\n\n## Decremental Progress\n\n`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`\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"img/progress_bar_countdown.gif\"/\u003e  \n\u003c/p\u003e\n\n```cpp\n#include \u003cchrono\u003e\n#include \u003cindicators/progress_bar.hpp\u003e\n#include \u003cthread\u003e\nusing namespace indicators;\n\nint main() {\n\n  ProgressBar bar{option::BarWidth{50},\n                  option::ProgressType{ProgressType::decremental},\n                  option::Start{\"[\"},\n                  option::Fill{\"■\"},\n                  option::Lead{\"■\"},\n                  option::Remainder{\"-\"},\n                  option::End{\"]\"},\n                  option::PostfixText{\"Reverting System Restore\"},\n                  option::ForegroundColor{Color::yellow},\n                  option::FontStyles{std::vector\u003cFontStyle\u003e{FontStyle::bold}}};\n\n  // Update bar state\n  while (true) {\n    bar.tick();\n    if (bar.is_completed())\n      break;\n    std::this_thread::sleep_for(std::chrono::milliseconds(100));\n  }\n\n  std::cout \u003c\u003c termcolor::bold \u003c\u003c termcolor::white\n            \u003c\u003c \"Task Failed Successfully\\n\" \u003c\u003c termcolor::reset;\n\n  return 0;\n}\n```\n\n## Working with Iterables\n\nIf you'd like to use progress bars to indicate progress while iterating over iterables, e.g., a list of numbers, this\ncan be achieved by using the `option::MaxProgress`:\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"img/block_progress_bar_iterable.gif\"/\u003e  \n\u003c/p\u003e\n\n```cpp\n#include \u003cchrono\u003e\n#include \u003cindicators/block_progress_bar.hpp\u003e\n#include \u003cindicators/cursor_control.hpp\u003e\n#include \u003cthread\u003e\n\nint main() {\n\n  // Hide cursor\n  indicators::show_console_cursor(false);\n\n  // Random list of numbers\n  std::vector\u003csize_t\u003e numbers;\n  for (size_t i = 0; i \u003c 1259438; ++i) {\n      numbers.push_back(i);\n  }\n\n  using namespace indicators;\n  BlockProgressBar bar{\n    option::BarWidth{80},\n    option::ForegroundColor{Color::white},\n    option::ShowPercentage{true},\n    option::FontStyles{\n          std::vector\u003cFontStyle\u003e{FontStyle::bold}},\n    option::MaxProgress{numbers.size()}\n  };\n\n  std::cout \u003c\u003c \"Iterating over a list of numbers (size = \"\n            \u003c\u003c numbers.size() \u003c\u003c \")\\n\";\n\n  std::vector\u003csize_t\u003e result;\n  for (size_t i = 0; i \u003c numbers.size(); ++i) {\n\n    // Perform some computation\n    result.push_back(numbers[i] * numbers[i]);\n\n    // Show iteration as postfix text\n    bar.set_option(option::PostfixText{\n      std::to_string(i) + \"/\" + std::to_string(numbers.size())\n    });\n\n    // update progress bar\n    bar.tick();\n  }\n\n  bar.mark_as_completed();\n\n  // Show cursor\n  indicators::show_console_cursor(true);\n\n  return 0;\n}\n```\n\n## Unicode Support\n\n`indicators` supports multi-byte unicode characters in progress bars. \n\nIf 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. \n\nSee below an example of some progress bars, each with a bar width of 50, displaying different unicode characters:\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"img/unicode.gif\"/\u003e  \n\u003c/p\u003e\n\n```cpp\n#include \u003cchrono\u003e\n#include \u003cindicators/progress_bar.hpp\u003e\n#include \u003cindicators/indeterminate_progress_bar.hpp\u003e\n#include \u003cindicators/cursor_control.hpp\u003e\n#include \u003cthread\u003e\n\nint main() {\n\n    indicators::show_console_cursor(false);\n\n    std::this_thread::sleep_for(std::chrono::milliseconds(2000));\n\n    {\n        // Plain old ASCII\n        indicators::ProgressBar bar{\n            indicators::option::BarWidth{50},\n            indicators::option::Start{\"[\"},\n            indicators::option::Fill{\"=\"},\n            indicators::option::Lead{\"\u003e\"},\n            indicators::option::Remainder{\" \"},\n            indicators::option::End{\" ]\"},\n            indicators::option::PostfixText{\"Plain-old ASCII\"},\n            indicators::option::ForegroundColor{indicators::Color::green},\n            indicators::option::FontStyles{\n                std::vector\u003cindicators::FontStyle\u003e{indicators::FontStyle::bold}}\n        };\n\n        // Update bar state\n        while (true) {\n            bar.tick();\n            if (bar.is_completed())\n            break;\n            std::this_thread::sleep_for(std::chrono::milliseconds(10));\n        }\n    }\n\n    {\n        // Unicode\n        indicators::ProgressBar bar{\n            indicators::option::BarWidth{50},\n            indicators::option::Start{\"[\"},\n            indicators::option::Fill{\"驚くばかり\"},\n            indicators::option::Lead{\"\u003e\"},\n            indicators::option::Remainder{\" \"},\n            indicators::option::End{\" ]\"},\n            indicators::option::PostfixText{\"Japanese\"},\n            indicators::option::ForegroundColor{indicators::Color::yellow},\n            indicators::option::FontStyles{\n                std::vector\u003cindicators::FontStyle\u003e{indicators::FontStyle::bold}}\n        };\n\n        // Update bar state\n        while (true) {\n            bar.tick();\n            if (bar.is_completed())\n            break;\n            std::this_thread::sleep_for(std::chrono::milliseconds(10));\n        }\n    }\n\n    {\n        // Russian\n        indicators::ProgressBar bar{\n            indicators::option::BarWidth{50},\n            indicators::option::Start{\"[\"},\n            indicators::option::Fill{\"Потрясающие\"},\n            indicators::option::Remainder{\" \"},\n            indicators::option::End{\" ]\"},\n            indicators::option::PostfixText{\"Russian\"},\n            indicators::option::ForegroundColor{indicators::Color::red},\n            indicators::option::FontStyles{\n                std::vector\u003cindicators::FontStyle\u003e{indicators::FontStyle::bold}}\n        };\n\n        // Update bar state\n        while (true) {\n            bar.tick();\n            if (bar.is_completed())\n            break;\n            std::this_thread::sleep_for(std::chrono::milliseconds(10));\n        }\n    }\n\n    {\n        // Greek\n        indicators::ProgressBar bar{\n            indicators::option::BarWidth{50},\n            indicators::option::Start{\"[\"},\n            indicators::option::Fill{\"Φοβερός\"},\n            indicators::option::Remainder{\" \"},\n            indicators::option::End{\" ]\"},\n            indicators::option::PostfixText{\"Greek\"},\n            indicators::option::ForegroundColor{indicators::Color::cyan},\n            indicators::option::FontStyles{\n                std::vector\u003cindicators::FontStyle\u003e{indicators::FontStyle::bold}}\n        };\n\n        // Update bar state\n        while (true) {\n            bar.tick();\n            if (bar.is_completed())\n            break;\n            std::this_thread::sleep_for(std::chrono::milliseconds(10));\n        }\n    }\n\n    {\n        // Chinese\n        indicators::ProgressBar bar{\n            indicators::option::BarWidth{50},\n            indicators::option::Start{\"[\"},\n            indicators::option::Fill{\"太棒了\"},\n            indicators::option::Remainder{\" \"},\n            indicators::option::End{\" ]\"},\n            indicators::option::PostfixText{\"Chinese\"},\n            indicators::option::ForegroundColor{indicators::Color::green},\n            indicators::option::FontStyles{\n                std::vector\u003cindicators::FontStyle\u003e{indicators::FontStyle::bold}}\n        };\n\n        // Update bar state\n        while (true) {\n            bar.tick();\n            if (bar.is_completed())\n            break;\n            std::this_thread::sleep_for(std::chrono::milliseconds(10));\n        }        \n    }\n\n    {\n        // Emojis\n        indicators::ProgressBar bar{\n            indicators::option::BarWidth{50},\n            indicators::option::Start{\"[\"},\n            indicators::option::Fill{\"🔥\"},\n            indicators::option::Lead{\"🔥\"},\n            indicators::option::Remainder{\" \"},\n            indicators::option::End{\" ]\"},\n            indicators::option::PostfixText{\"Emojis\"},\n            indicators::option::ForegroundColor{indicators::Color::white},\n            indicators::option::FontStyles{\n                std::vector\u003cindicators::FontStyle\u003e{indicators::FontStyle::bold}}\n        };\n\n        // Update bar state\n        while (true) {\n            bar.tick();\n            if (bar.is_completed())\n            break;\n            std::this_thread::sleep_for(std::chrono::milliseconds(10));\n        }\n    }\n\n    {\n        // Indeterminate progress bar\n        indicators::IndeterminateProgressBar bar{\n            indicators::option::BarWidth{50},\n            indicators::option::Start{\"[\"},\n            indicators::option::Fill{\"✯\"},\n            indicators::option::Lead{\"載入中\"},\n            indicators::option::End{\" ]\"},\n            indicators::option::PostfixText{\"Loading Progress Bar\"},\n            indicators::option::ForegroundColor{indicators::Color::yellow},\n            indicators::option::FontStyles{\n                std::vector\u003cindicators::FontStyle\u003e{indicators::FontStyle::bold}}\n        };\n\n        auto job = [\u0026bar]() {\n            std::this_thread::sleep_for(std::chrono::milliseconds(10000));\n            bar.mark_as_completed();\n        };\n        std::thread job_completion_thread(job);\n\n        // Update bar state\n        while (!bar.is_completed()) {\n            bar.tick();\n            std::this_thread::sleep_for(std::chrono::milliseconds(100));\n        }\n\n        job_completion_thread.join();\n    }\n\n    indicators::show_console_cursor(true);\n\n  return 0;\n}\n```\n\n## Building Samples\n\n```bash\ngit clone https://github.com/p-ranav/indicators\ncd indicators\nmkdir build \u0026\u0026 cd build\ncmake -DINDICATORS_SAMPLES=ON -DINDICATORS_DEMO=ON ..\nmake\n```\n\n### WinLibs + MinGW\n\nFor Windows, if you use WinLibs like I do, the cmake command would look like this:\n\n```console\nfoo@bar:~$ mkdir build \u0026\u0026 cd build\nfoo@bar:~$ cmake -G \"MinGW Makefiles\" -DCMAKE_CXX_COMPILER=\"C:/WinLibs/mingw64/bin/g++.exe\" -DINDICATORS_SAMPLES=ON -DINDICATORS_DEMO=ON ..\nfoo@bar:~$ make -j4\n```\n\n## Generating Single Header\n\n```bash\npython3 utils/amalgamate/amalgamate.py -c single_include.json -s .\n```\n\n## Contributing\nContributions are welcome, have a look at the [CONTRIBUTING.md](CONTRIBUTING.md) document for more information.\n\n## License\nThe project is available under the [MIT](https://opensource.org/licenses/MIT) license.\n","funding_links":[],"categories":["C++","CLI","C/C++","Terminal Utilities","Libraries","C/C++ ⚙️"],"sub_categories":["Misc"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fp-ranav%2Findicators","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fp-ranav%2Findicators","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fp-ranav%2Findicators/lists"}