COMPASS  5.4.4
End-to-end AO simulation tool using GPU acceleration
carma_indicators.hpp
1 
2 // code source from https://github.com/p-ranav/indicators
3 // MIT License
4 //
5 // Indicators
6 // ==========
7 //
8 // Activity Indicators for Modern C++
9 //
10 // Indicators is a header-only C++17 library for displaying various indicators
11 // during the program execution. It is intended to be used in console
12 // applications to report about current progress and status.
13 //
14 // Indicators is a cross-platform library and provides consistent output both
15 // on Windows and Unix systems.
16 //
17 // Indicators is written in Modern C++ and highly optimized for performance.
18 // It is designed to be as fast as possible and it strives to be a
19 // performance-wise alternative to existing activity indicators libraries
20 // written in C.
21 //
22 // Indicators is a header-only library. All you need to do is to download
23 // `indicators.hpp` and include it into your project.
24 
25 
26 #ifndef INDICATORS_COLOR
27 #define INDICATORS_COLOR
28 
29 namespace indicators {
31 }
32 
33 #endif
34 
35 
36 
37 #ifndef INDICATORS_FONT_STYLE
38 #define INDICATORS_FONT_STYLE
39 
40 namespace indicators {
42 }
43 
44 #endif
45 
46 
47 
48 #ifndef INDICATORS_PROGRESS_TYPE
49 #define INDICATORS_PROGRESS_TYPE
50 
51 namespace indicators {
53 }
54 
55 #endif
56 
67 
68 #ifndef TERMCOLOR_HPP_
69 #define TERMCOLOR_HPP_
70 
71 #include <iostream>
72 #include <cstdio>
73 #include <cstdint>
74 
75 // Detect target's platform and set some macros in order to wrap platform
76 // specific code this library depends on.
77 #if defined(_WIN32) || defined(_WIN64)
78 # define TERMCOLOR_TARGET_WINDOWS
79 #elif defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))
80 # define TERMCOLOR_TARGET_POSIX
81 #endif
82 
83 // If implementation has not been explicitly set, try to choose one based on
84 // target platform.
85 #if !defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) && !defined(TERMCOLOR_USE_WINDOWS_API) && !defined(TERMCOLOR_USE_NOOP)
86 # if defined(TERMCOLOR_TARGET_POSIX)
87 # define TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES
88 # define TERMCOLOR_AUTODETECTED_IMPLEMENTATION
89 # elif defined(TERMCOLOR_TARGET_WINDOWS)
90 # define TERMCOLOR_USE_WINDOWS_API
91 # define TERMCOLOR_AUTODETECTED_IMPLEMENTATION
92 # endif
93 #endif
94 
95 // These headers provide isatty()/fileno() functions, which are used for
96 // testing whether a standard stream refers to the terminal.
97 #if defined(TERMCOLOR_TARGET_POSIX)
98 # include <unistd.h>
99 #elif defined(TERMCOLOR_TARGET_WINDOWS)
100 #if defined(_MSC_VER)
101 #if !defined(NOMINMAX)
102 #define NOMINMAX
103 #endif
104 #endif
105 # include <io.h>
106 # include <windows.h>
107 #endif
108 
109 
110 namespace termcolor
111 {
112  // Forward declaration of the `_internal` namespace.
113  // All comments are below.
114  namespace _internal
115  {
116  inline int colorize_index();
117  inline FILE* get_standard_stream(const std::ostream& stream);
118  inline bool is_colorized(std::ostream& stream);
119  inline bool is_atty(const std::ostream& stream);
120 
121  #if defined(TERMCOLOR_TARGET_WINDOWS)
122  inline void win_change_attributes(std::ostream& stream, int foreground, int background=-1);
123  #endif
124  }
125 
126  inline
127  std::ostream& colorize(std::ostream& stream)
128  {
129  stream.iword(_internal::colorize_index()) = 1L;
130  return stream;
131  }
132 
133  inline
134  std::ostream& nocolorize(std::ostream& stream)
135  {
136  stream.iword(_internal::colorize_index()) = 0L;
137  return stream;
138  }
139 
140  inline
141  std::ostream& reset(std::ostream& stream)
142  {
143  if (_internal::is_colorized(stream))
144  {
145  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
146  stream << "\033[00m";
147  #elif defined(TERMCOLOR_USE_WINDOWS_API)
148  _internal::win_change_attributes(stream, -1, -1);
149  #endif
150  }
151  return stream;
152  }
153 
154  inline
155  std::ostream& bold(std::ostream& stream)
156  {
157  if (_internal::is_colorized(stream))
158  {
159  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
160  stream << "\033[1m";
161  #elif defined(TERMCOLOR_USE_WINDOWS_API)
162  #endif
163  }
164  return stream;
165  }
166 
167  inline
168  std::ostream& dark(std::ostream& stream)
169  {
170  if (_internal::is_colorized(stream))
171  {
172  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
173  stream << "\033[2m";
174  #elif defined(TERMCOLOR_USE_WINDOWS_API)
175  #endif
176  }
177  return stream;
178  }
179 
180  inline
181  std::ostream& italic(std::ostream& stream)
182  {
183  if (_internal::is_colorized(stream))
184  {
185  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
186  stream << "\033[3m";
187  #elif defined(TERMCOLOR_USE_WINDOWS_API)
188  #endif
189  }
190  return stream;
191  }
192 
193  inline
194  std::ostream& underline(std::ostream& stream)
195  {
196  if (_internal::is_colorized(stream))
197  {
198  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
199  stream << "\033[4m";
200  #elif defined(TERMCOLOR_USE_WINDOWS_API)
201  _internal::win_change_attributes(stream, -1, COMMON_LVB_UNDERSCORE);
202  #endif
203  }
204  return stream;
205  }
206 
207  inline
208  std::ostream& blink(std::ostream& stream)
209  {
210  if (_internal::is_colorized(stream))
211  {
212  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
213  stream << "\033[5m";
214  #elif defined(TERMCOLOR_USE_WINDOWS_API)
215  #endif
216  }
217  return stream;
218  }
219 
220  inline
221  std::ostream& reverse(std::ostream& stream)
222  {
223  if (_internal::is_colorized(stream))
224  {
225  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
226  stream << "\033[7m";
227  #elif defined(TERMCOLOR_USE_WINDOWS_API)
228  #endif
229  }
230  return stream;
231  }
232 
233  inline
234  std::ostream& concealed(std::ostream& stream)
235  {
236  if (_internal::is_colorized(stream))
237  {
238  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
239  stream << "\033[8m";
240  #elif defined(TERMCOLOR_USE_WINDOWS_API)
241  #endif
242  }
243  return stream;
244  }
245 
246  inline
247  std::ostream& crossed(std::ostream& stream)
248  {
249  if (_internal::is_colorized(stream))
250  {
251  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
252  stream << "\033[9m";
253  #elif defined(TERMCOLOR_USE_WINDOWS_API)
254  #endif
255  }
256  return stream;
257  }
258 
259  template <uint8_t code> inline
260  std::ostream& color(std::ostream& stream)
261  {
262  if (_internal::is_colorized(stream))
263  {
264  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
265  char command[12];
266  std::snprintf(command, sizeof(command), "\033[38;5;%dm", code);
267  stream << command;
268  #elif defined(TERMCOLOR_USE_WINDOWS_API)
269  #endif
270  }
271  return stream;
272  }
273 
274  template <uint8_t code> inline
275  std::ostream& on_color(std::ostream& stream)
276  {
277  if (_internal::is_colorized(stream))
278  {
279  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
280  char command[12];
281  std::snprintf(command, sizeof(command), "\033[48;5;%dm", code);
282  stream << command;
283  #elif defined(TERMCOLOR_USE_WINDOWS_API)
284  #endif
285  }
286  return stream;
287  }
288 
289  template <uint8_t r, uint8_t g, uint8_t b> inline
290  std::ostream& color(std::ostream& stream)
291  {
292  if (_internal::is_colorized(stream))
293  {
294  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
295  char command[20];
296  std::snprintf(command, sizeof(command), "\033[38;2;%d;%d;%dm", r, g, b);
297  stream << command;
298  #elif defined(TERMCOLOR_USE_WINDOWS_API)
299  #endif
300  }
301  return stream;
302  }
303 
304  template <uint8_t r, uint8_t g, uint8_t b> inline
305  std::ostream& on_color(std::ostream& stream)
306  {
307  if (_internal::is_colorized(stream))
308  {
309  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
310  char command[20];
311  std::snprintf(command, sizeof(command), "\033[48;2;%d;%d;%dm", r, g, b);
312  stream << command;
313  #elif defined(TERMCOLOR_USE_WINDOWS_API)
314  #endif
315  }
316  return stream;
317  }
318 
319  inline
320  std::ostream& grey(std::ostream& stream)
321  {
322  if (_internal::is_colorized(stream))
323  {
324  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
325  stream << "\033[30m";
326  #elif defined(TERMCOLOR_USE_WINDOWS_API)
327  _internal::win_change_attributes(stream,
328  0 // grey (black)
329  );
330  #endif
331  }
332  return stream;
333  }
334 
335  inline
336  std::ostream& red(std::ostream& stream)
337  {
338  if (_internal::is_colorized(stream))
339  {
340  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
341  stream << "\033[31m";
342  #elif defined(TERMCOLOR_USE_WINDOWS_API)
343  _internal::win_change_attributes(stream,
344  FOREGROUND_RED
345  );
346  #endif
347  }
348  return stream;
349  }
350 
351  inline
352  std::ostream& green(std::ostream& stream)
353  {
354  if (_internal::is_colorized(stream))
355  {
356  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
357  stream << "\033[32m";
358  #elif defined(TERMCOLOR_USE_WINDOWS_API)
359  _internal::win_change_attributes(stream,
360  FOREGROUND_GREEN
361  );
362  #endif
363  }
364  return stream;
365  }
366 
367  inline
368  std::ostream& yellow(std::ostream& stream)
369  {
370  if (_internal::is_colorized(stream))
371  {
372  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
373  stream << "\033[33m";
374  #elif defined(TERMCOLOR_USE_WINDOWS_API)
375  _internal::win_change_attributes(stream,
376  FOREGROUND_GREEN | FOREGROUND_RED
377  );
378  #endif
379  }
380  return stream;
381  }
382 
383  inline
384  std::ostream& blue(std::ostream& stream)
385  {
386  if (_internal::is_colorized(stream))
387  {
388  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
389  stream << "\033[34m";
390  #elif defined(TERMCOLOR_USE_WINDOWS_API)
391  _internal::win_change_attributes(stream,
392  FOREGROUND_BLUE
393  );
394  #endif
395  }
396  return stream;
397  }
398 
399  inline
400  std::ostream& magenta(std::ostream& stream)
401  {
402  if (_internal::is_colorized(stream))
403  {
404  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
405  stream << "\033[35m";
406  #elif defined(TERMCOLOR_USE_WINDOWS_API)
407  _internal::win_change_attributes(stream,
408  FOREGROUND_BLUE | FOREGROUND_RED
409  );
410  #endif
411  }
412  return stream;
413  }
414 
415  inline
416  std::ostream& cyan(std::ostream& stream)
417  {
418  if (_internal::is_colorized(stream))
419  {
420  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
421  stream << "\033[36m";
422  #elif defined(TERMCOLOR_USE_WINDOWS_API)
423  _internal::win_change_attributes(stream,
424  FOREGROUND_BLUE | FOREGROUND_GREEN
425  );
426  #endif
427  }
428  return stream;
429  }
430 
431  inline
432  std::ostream& white(std::ostream& stream)
433  {
434  if (_internal::is_colorized(stream))
435  {
436  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
437  stream << "\033[37m";
438  #elif defined(TERMCOLOR_USE_WINDOWS_API)
439  _internal::win_change_attributes(stream,
440  FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED
441  );
442  #endif
443  }
444  return stream;
445  }
446 
447 
448  inline
449  std::ostream& bright_grey(std::ostream& stream)
450  {
451  if (_internal::is_colorized(stream))
452  {
453  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
454  stream << "\033[90m";
455  #elif defined(TERMCOLOR_USE_WINDOWS_API)
456  _internal::win_change_attributes(stream,
457  0 | FOREGROUND_INTENSITY // grey (black)
458  );
459  #endif
460  }
461  return stream;
462  }
463 
464  inline
465  std::ostream& bright_red(std::ostream& stream)
466  {
467  if (_internal::is_colorized(stream))
468  {
469  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
470  stream << "\033[91m";
471  #elif defined(TERMCOLOR_USE_WINDOWS_API)
472  _internal::win_change_attributes(stream,
473  FOREGROUND_RED | FOREGROUND_INTENSITY
474  );
475  #endif
476  }
477  return stream;
478  }
479 
480  inline
481  std::ostream& bright_green(std::ostream& stream)
482  {
483  if (_internal::is_colorized(stream))
484  {
485  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
486  stream << "\033[92m";
487  #elif defined(TERMCOLOR_USE_WINDOWS_API)
488  _internal::win_change_attributes(stream,
489  FOREGROUND_GREEN | FOREGROUND_INTENSITY
490  );
491  #endif
492  }
493  return stream;
494  }
495 
496  inline
497  std::ostream& bright_yellow(std::ostream& stream)
498  {
499  if (_internal::is_colorized(stream))
500  {
501  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
502  stream << "\033[93m";
503  #elif defined(TERMCOLOR_USE_WINDOWS_API)
504  _internal::win_change_attributes(stream,
505  FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY
506  );
507  #endif
508  }
509  return stream;
510  }
511 
512  inline
513  std::ostream& bright_blue(std::ostream& stream)
514  {
515  if (_internal::is_colorized(stream))
516  {
517  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
518  stream << "\033[94m";
519  #elif defined(TERMCOLOR_USE_WINDOWS_API)
520  _internal::win_change_attributes(stream,
521  FOREGROUND_BLUE | FOREGROUND_INTENSITY
522  );
523  #endif
524  }
525  return stream;
526  }
527 
528  inline
529  std::ostream& bright_magenta(std::ostream& stream)
530  {
531  if (_internal::is_colorized(stream))
532  {
533  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
534  stream << "\033[95m";
535  #elif defined(TERMCOLOR_USE_WINDOWS_API)
536  _internal::win_change_attributes(stream,
537  FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY
538  );
539  #endif
540  }
541  return stream;
542  }
543 
544  inline
545  std::ostream& bright_cyan(std::ostream& stream)
546  {
547  if (_internal::is_colorized(stream))
548  {
549  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
550  stream << "\033[96m";
551  #elif defined(TERMCOLOR_USE_WINDOWS_API)
552  _internal::win_change_attributes(stream,
553  FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY
554  );
555  #endif
556  }
557  return stream;
558  }
559 
560  inline
561  std::ostream& bright_white(std::ostream& stream)
562  {
563  if (_internal::is_colorized(stream))
564  {
565  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
566  stream << "\033[97m";
567  #elif defined(TERMCOLOR_USE_WINDOWS_API)
568  _internal::win_change_attributes(stream,
569  FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY
570  );
571  #endif
572  }
573  return stream;
574  }
575 
576 
577  inline
578  std::ostream& on_grey(std::ostream& stream)
579  {
580  if (_internal::is_colorized(stream))
581  {
582  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
583  stream << "\033[40m";
584  #elif defined(TERMCOLOR_USE_WINDOWS_API)
585  _internal::win_change_attributes(stream, -1,
586  0 // grey (black)
587  );
588  #endif
589  }
590  return stream;
591  }
592 
593  inline
594  std::ostream& on_red(std::ostream& stream)
595  {
596  if (_internal::is_colorized(stream))
597  {
598  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
599  stream << "\033[41m";
600  #elif defined(TERMCOLOR_USE_WINDOWS_API)
601  _internal::win_change_attributes(stream, -1,
602  BACKGROUND_RED
603  );
604  #endif
605  }
606  return stream;
607  }
608 
609  inline
610  std::ostream& on_green(std::ostream& stream)
611  {
612  if (_internal::is_colorized(stream))
613  {
614  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
615  stream << "\033[42m";
616  #elif defined(TERMCOLOR_USE_WINDOWS_API)
617  _internal::win_change_attributes(stream, -1,
618  BACKGROUND_GREEN
619  );
620  #endif
621  }
622  return stream;
623  }
624 
625  inline
626  std::ostream& on_yellow(std::ostream& stream)
627  {
628  if (_internal::is_colorized(stream))
629  {
630  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
631  stream << "\033[43m";
632  #elif defined(TERMCOLOR_USE_WINDOWS_API)
633  _internal::win_change_attributes(stream, -1,
634  BACKGROUND_GREEN | BACKGROUND_RED
635  );
636  #endif
637  }
638  return stream;
639  }
640 
641  inline
642  std::ostream& on_blue(std::ostream& stream)
643  {
644  if (_internal::is_colorized(stream))
645  {
646  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
647  stream << "\033[44m";
648  #elif defined(TERMCOLOR_USE_WINDOWS_API)
649  _internal::win_change_attributes(stream, -1,
650  BACKGROUND_BLUE
651  );
652  #endif
653  }
654  return stream;
655  }
656 
657  inline
658  std::ostream& on_magenta(std::ostream& stream)
659  {
660  if (_internal::is_colorized(stream))
661  {
662  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
663  stream << "\033[45m";
664  #elif defined(TERMCOLOR_USE_WINDOWS_API)
665  _internal::win_change_attributes(stream, -1,
666  BACKGROUND_BLUE | BACKGROUND_RED
667  );
668  #endif
669  }
670  return stream;
671  }
672 
673  inline
674  std::ostream& on_cyan(std::ostream& stream)
675  {
676  if (_internal::is_colorized(stream))
677  {
678  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
679  stream << "\033[46m";
680  #elif defined(TERMCOLOR_USE_WINDOWS_API)
681  _internal::win_change_attributes(stream, -1,
682  BACKGROUND_GREEN | BACKGROUND_BLUE
683  );
684  #endif
685  }
686  return stream;
687  }
688 
689  inline
690  std::ostream& on_white(std::ostream& stream)
691  {
692  if (_internal::is_colorized(stream))
693  {
694  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
695  stream << "\033[47m";
696  #elif defined(TERMCOLOR_USE_WINDOWS_API)
697  _internal::win_change_attributes(stream, -1,
698  BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED
699  );
700  #endif
701  }
702 
703  return stream;
704  }
705 
706 
707  inline
708  std::ostream& on_bright_grey(std::ostream& stream)
709  {
710  if (_internal::is_colorized(stream))
711  {
712  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
713  stream << "\033[100m";
714  #elif defined(TERMCOLOR_USE_WINDOWS_API)
715  _internal::win_change_attributes(stream, -1,
716  0 | BACKGROUND_INTENSITY // grey (black)
717  );
718  #endif
719  }
720  return stream;
721  }
722 
723  inline
724  std::ostream& on_bright_red(std::ostream& stream)
725  {
726  if (_internal::is_colorized(stream))
727  {
728  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
729  stream << "\033[101m";
730  #elif defined(TERMCOLOR_USE_WINDOWS_API)
731  _internal::win_change_attributes(stream, -1,
732  BACKGROUND_RED | BACKGROUND_INTENSITY
733  );
734  #endif
735  }
736  return stream;
737  }
738 
739  inline
740  std::ostream& on_bright_green(std::ostream& stream)
741  {
742  if (_internal::is_colorized(stream))
743  {
744  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
745  stream << "\033[102m";
746  #elif defined(TERMCOLOR_USE_WINDOWS_API)
747  _internal::win_change_attributes(stream, -1,
748  BACKGROUND_GREEN | BACKGROUND_INTENSITY
749  );
750  #endif
751  }
752  return stream;
753  }
754 
755  inline
756  std::ostream& on_bright_yellow(std::ostream& stream)
757  {
758  if (_internal::is_colorized(stream))
759  {
760  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
761  stream << "\033[103m";
762  #elif defined(TERMCOLOR_USE_WINDOWS_API)
763  _internal::win_change_attributes(stream, -1,
764  BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY
765  );
766  #endif
767  }
768  return stream;
769  }
770 
771  inline
772  std::ostream& on_bright_blue(std::ostream& stream)
773  {
774  if (_internal::is_colorized(stream))
775  {
776  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
777  stream << "\033[104m";
778  #elif defined(TERMCOLOR_USE_WINDOWS_API)
779  _internal::win_change_attributes(stream, -1,
780  BACKGROUND_BLUE | BACKGROUND_INTENSITY
781  );
782  #endif
783  }
784  return stream;
785  }
786 
787  inline
788  std::ostream& on_bright_magenta(std::ostream& stream)
789  {
790  if (_internal::is_colorized(stream))
791  {
792  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
793  stream << "\033[105m";
794  #elif defined(TERMCOLOR_USE_WINDOWS_API)
795  _internal::win_change_attributes(stream, -1,
796  BACKGROUND_BLUE | BACKGROUND_RED | BACKGROUND_INTENSITY
797  );
798  #endif
799  }
800  return stream;
801  }
802 
803  inline
804  std::ostream& on_bright_cyan(std::ostream& stream)
805  {
806  if (_internal::is_colorized(stream))
807  {
808  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
809  stream << "\033[106m";
810  #elif defined(TERMCOLOR_USE_WINDOWS_API)
811  _internal::win_change_attributes(stream, -1,
812  BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY
813  );
814  #endif
815  }
816  return stream;
817  }
818 
819  inline
820  std::ostream& on_bright_white(std::ostream& stream)
821  {
822  if (_internal::is_colorized(stream))
823  {
824  #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES)
825  stream << "\033[107m";
826  #elif defined(TERMCOLOR_USE_WINDOWS_API)
827  _internal::win_change_attributes(stream, -1,
828  BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED | BACKGROUND_INTENSITY
829  );
830  #endif
831  }
832 
833  return stream;
834  }
835 
836 
837 
842  namespace _internal
843  {
844  // An index to be used to access a private storage of I/O streams. See
845  // colorize / nocolorize I/O manipulators for details. Due to the fact
846  // that static variables ain't shared between translation units, inline
847  // function with local static variable is used to do the trick and share
848  // the variable value between translation units.
849  inline int colorize_index()
850  {
851  static int colorize_index = std::ios_base::xalloc();
852  return colorize_index;
853  }
854 
858  inline
859  FILE* get_standard_stream(const std::ostream& stream)
860  {
861  if (&stream == &std::cout)
862  return stdout;
863  else if ((&stream == &std::cerr) || (&stream == &std::clog))
864  return stderr;
865 
866  return nullptr;
867  }
868 
869  // Say whether a given stream should be colorized or not. It's always
870  // true for ATTY streams and may be true for streams marked with
871  // colorize flag.
872  inline
873  bool is_colorized(std::ostream& stream)
874  {
875  return is_atty(stream) || static_cast<bool>(stream.iword(colorize_index()));
876  }
877 
880  inline
881  bool is_atty(const std::ostream& stream)
882  {
883  FILE* std_stream = get_standard_stream(stream);
884 
885  // Unfortunately, fileno() ends with segmentation fault
886  // if invalid file descriptor is passed. So we need to
887  // handle this case gracefully and assume it's not a tty
888  // if standard stream is not detected, and 0 is returned.
889  if (!std_stream)
890  return false;
891 
892  #if defined(TERMCOLOR_TARGET_POSIX)
893  return ::isatty(fileno(std_stream));
894  #elif defined(TERMCOLOR_TARGET_WINDOWS)
895  return ::_isatty(_fileno(std_stream));
896  #else
897  return false;
898  #endif
899  }
900 
901  #if defined(TERMCOLOR_TARGET_WINDOWS)
904  inline void win_change_attributes(std::ostream& stream, int foreground, int background)
905  {
906  // yeah, i know.. it's ugly, it's windows.
907  static WORD defaultAttributes = 0;
908 
909  // Windows doesn't have ANSI escape sequences and so we use special
910  // API to change Terminal output color. That means we can't
911  // manipulate colors by means of "std::stringstream" and hence
912  // should do nothing in this case.
913  if (!_internal::is_atty(stream))
914  return;
915 
916  // get terminal handle
917  HANDLE hTerminal = INVALID_HANDLE_VALUE;
918  if (&stream == &std::cout)
919  hTerminal = GetStdHandle(STD_OUTPUT_HANDLE);
920  else if (&stream == &std::cerr)
921  hTerminal = GetStdHandle(STD_ERROR_HANDLE);
922 
923  // save default terminal attributes if it unsaved
924  if (!defaultAttributes)
925  {
926  CONSOLE_SCREEN_BUFFER_INFO info;
927  if (!GetConsoleScreenBufferInfo(hTerminal, &info))
928  return;
929  defaultAttributes = info.wAttributes;
930  }
931 
932  // restore all default settings
933  if (foreground == -1 && background == -1)
934  {
935  SetConsoleTextAttribute(hTerminal, defaultAttributes);
936  return;
937  }
938 
939  // get current settings
940  CONSOLE_SCREEN_BUFFER_INFO info;
941  if (!GetConsoleScreenBufferInfo(hTerminal, &info))
942  return;
943 
944  if (foreground != -1)
945  {
946  info.wAttributes &= ~(info.wAttributes & 0x0F);
947  info.wAttributes |= static_cast<WORD>(foreground);
948  }
949 
950  if (background != -1)
951  {
952  info.wAttributes &= ~(info.wAttributes & 0xF0);
953  info.wAttributes |= static_cast<WORD>(background);
954  }
955 
956  SetConsoleTextAttribute(hTerminal, info.wAttributes);
957  }
958  #endif // TERMCOLOR_TARGET_WINDOWS
959 
960  } // namespace _internal
961 
962 } // namespace termcolor
963 
964 
965 #undef TERMCOLOR_TARGET_POSIX
966 #undef TERMCOLOR_TARGET_WINDOWS
967 
968 #if defined(TERMCOLOR_AUTODETECTED_IMPLEMENTATION)
969 # undef TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES
970 # undef TERMCOLOR_USE_WINDOWS_API
971 #endif
972 
973 #endif // TERMCOLOR_HPP_
974 
975 
976 
977 #ifndef INDICATORS_TERMINAL_SIZE
978 #define INDICATORS_TERMINAL_SIZE
979 #include <utility>
980 
981 
982 #if defined(_WIN32)
983 #include <windows.h>
984 
985 namespace indicators {
986 
987 static inline std::pair<size_t, size_t> terminal_size() {
988  CONSOLE_SCREEN_BUFFER_INFO csbi;
989  int cols, rows;
990  GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
991  cols = csbi.srWindow.Right - csbi.srWindow.Left + 1;
992  rows = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
993  return {static_cast<size_t>(rows), static_cast<size_t>(cols)};
994 }
995 
996 static inline size_t terminal_width() { return terminal_size().second; }
997 
998 } // namespace indicators
999 
1000 #else
1001 
1002 #include <sys/ioctl.h> //ioctl() and TIOCGWINSZ
1003 #include <unistd.h> // for STDOUT_FILENO
1004 
1005 namespace indicators {
1006 
1007 static inline std::pair<size_t, size_t> terminal_size() {
1008  struct winsize size{};
1009  ioctl(STDOUT_FILENO, TIOCGWINSZ, &size);
1010  return {static_cast<size_t>(size.ws_row), static_cast<size_t>(size.ws_col)};
1011 }
1012 
1013 static inline size_t terminal_width() { return terminal_size().second; }
1014 
1015 } // namespace indicators
1016 
1017 #endif
1018 
1019 #endif
1020 
1021 
1022 /*
1023 Activity Indicators for Modern C++
1024 https://github.com/p-ranav/indicators
1025 
1026 Licensed under the MIT License <http://opensource.org/licenses/MIT>.
1027 SPDX-License-Identifier: MIT
1028 Copyright (c) 2019 Dawid Pilarski <dawid.pilarski@panicsoftware.com>.
1029 
1030 Permission is hereby granted, free of charge, to any person obtaining a copy
1031 of this software and associated documentation files (the "Software"), to deal
1032 in the Software without restriction, including without limitation the rights
1033 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1034 copies of the Software, and to permit persons to whom the Software is
1035 furnished to do so, subject to the following conditions:
1036 
1037 The above copyright notice and this permission notice shall be included in all
1038 copies or substantial portions of the Software.
1039 
1040 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1041 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1042 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1043 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1044 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1045 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1046 SOFTWARE.
1047 */
1048 #ifndef INDICATORS_SETTING
1049 #define INDICATORS_SETTING
1050 
1051 #include <cstddef>
1052 // #include <indicators/color.hpp>
1053 // #include <indicators/font_style.hpp>
1054 // #include <indicators/progress_type.hpp>
1055 #include <string>
1056 #include <tuple>
1057 #include <type_traits>
1058 #include <utility>
1059 #include <vector>
1060 
1061 namespace indicators {
1062 
1063 namespace details {
1064 
1065 template <bool condition> struct if_else;
1066 
1067 template <> struct if_else<true> { using type = std::true_type; };
1068 
1069 template <> struct if_else<false> { using type = std::false_type; };
1070 
1071 template <bool condition, typename True, typename False> struct if_else_type;
1072 
1073 template <typename True, typename False> struct if_else_type<true, True, False> {
1074  using type = True;
1075 };
1076 
1077 template <typename True, typename False> struct if_else_type<false, True, False> {
1078  using type = False;
1079 };
1080 
1081 template <typename... Ops> struct conjuction;
1082 
1083 template <> struct conjuction<> : std::true_type {};
1084 
1085 template <typename Op, typename... TailOps>
1086 struct conjuction<Op, TailOps...>
1087  : if_else_type<!Op::value, std::false_type, conjuction<TailOps...>>::type {};
1088 
1089 template <typename... Ops> struct disjunction;
1090 
1091 template <> struct disjunction<> : std::false_type {};
1092 
1093 template <typename Op, typename... TailOps>
1094 struct disjunction<Op, TailOps...>
1095  : if_else_type<Op::value, std::true_type, disjunction<TailOps...>>::type {};
1096 
1097 enum class ProgressBarOption {
1098  bar_width = 0,
1099  prefix_text,
1100  postfix_text,
1101  start,
1102  end,
1103  fill,
1104  lead,
1105  remainder,
1106  max_postfix_text_len,
1107  completed,
1108  show_percentage,
1109  show_elapsed_time,
1110  show_remaining_time,
1111  saved_start_time,
1112  foreground_color,
1113  spinner_show,
1114  spinner_states,
1115  font_styles,
1116  hide_bar_when_complete,
1117  min_progress,
1118  max_progress,
1119  progress_type,
1120  stream
1121 };
1122 
1123 template <typename T, ProgressBarOption Id> struct Setting {
1124  template <typename... Args,
1125  typename = typename std::enable_if<std::is_constructible<T, Args...>::value>::type>
1126  explicit Setting(Args &&... args) : value(std::forward<Args>(args)...) {}
1127  Setting(const Setting &) = default;
1128  Setting(Setting &&) = default;
1129 
1130  static constexpr auto id = Id;
1131  using type = T;
1132 
1133  T value{};
1134 };
1135 
1136 template <typename T> struct is_setting : std::false_type {};
1137 
1138 template <ProgressBarOption Id, typename T> struct is_setting<Setting<T, Id>> : std::true_type {};
1139 
1140 template <typename... Args>
1141 struct are_settings : if_else<conjuction<is_setting<Args>...>::value>::type {};
1142 
1143 template <> struct are_settings<> : std::true_type {};
1144 
1145 template <typename Setting, typename Tuple> struct is_setting_from_tuple;
1146 
1147 template <typename Setting> struct is_setting_from_tuple<Setting, std::tuple<>> : std::true_type {};
1148 
1149 template <typename Setting, typename... TupleTypes>
1150 struct is_setting_from_tuple<Setting, std::tuple<TupleTypes...>>
1151  : if_else<disjunction<std::is_same<Setting, TupleTypes>...>::value>::type {};
1152 
1153 template <typename Tuple, typename... Settings>
1154 struct are_settings_from_tuple
1155  : if_else<conjuction<is_setting_from_tuple<Settings, Tuple>...>::value>::type {};
1156 
1157 template <ProgressBarOption Id> struct always_true { static constexpr auto value = true; };
1158 
1159 template <ProgressBarOption Id, typename Default> Default &&get_impl(Default &&def) {
1160  return std::forward<Default>(def);
1161 }
1162 
1163 template <ProgressBarOption Id, typename Default, typename T, typename... Args>
1164 auto get_impl(Default && /*def*/, T &&first, Args &&... /*tail*/) ->
1165  typename std::enable_if<(std::decay<T>::type::id == Id),
1166  decltype(std::forward<T>(first))>::type {
1167  return std::forward<T>(first);
1168 }
1169 
1170 template <ProgressBarOption Id, typename Default, typename T, typename... Args>
1171 auto get_impl(Default &&def, T && /*first*/, Args &&... tail) ->
1172  typename std::enable_if<(std::decay<T>::type::id != Id),
1173  decltype(get_impl<Id>(std::forward<Default>(def),
1174  std::forward<Args>(tail)...))>::type {
1175  return get_impl<Id>(std::forward<Default>(def), std::forward<Args>(tail)...);
1176 }
1177 
1178 template <ProgressBarOption Id, typename Default, typename... Args,
1179  typename = typename std::enable_if<are_settings<Args...>::value, void>::type>
1180 auto get(Default &&def, Args &&... args)
1181  -> decltype(details::get_impl<Id>(std::forward<Default>(def), std::forward<Args>(args)...)) {
1182  return details::get_impl<Id>(std::forward<Default>(def), std::forward<Args>(args)...);
1183 }
1184 
1185 template <ProgressBarOption Id> using StringSetting = Setting<std::string, Id>;
1186 
1187 template <ProgressBarOption Id> using IntegerSetting = Setting<std::size_t, Id>;
1188 
1189 template <ProgressBarOption Id> using BooleanSetting = Setting<bool, Id>;
1190 
1191 template <ProgressBarOption Id, typename Tuple, std::size_t counter = 0> struct option_idx;
1192 
1193 template <ProgressBarOption Id, typename T, typename... Settings, std::size_t counter>
1194 struct option_idx<Id, std::tuple<T, Settings...>, counter>
1195  : if_else_type<(Id == T::id), std::integral_constant<std::size_t, counter>,
1196  option_idx<Id, std::tuple<Settings...>, counter + 1>>::type {};
1197 
1198 template <ProgressBarOption Id, std::size_t counter> struct option_idx<Id, std::tuple<>, counter> {
1199  static_assert(always_true<(ProgressBarOption)Id>::value, "No such option was found");
1200 };
1201 
1202 template <ProgressBarOption Id, typename Settings>
1203 auto get_value(Settings &&settings)
1204  -> decltype((std::get<option_idx<Id, typename std::decay<Settings>::type>::value>(
1205  std::declval<Settings &&>()))) {
1206  return std::get<option_idx<Id, typename std::decay<Settings>::type>::value>(
1207  std::forward<Settings>(settings));
1208 }
1209 
1210 } // namespace details
1211 
1212 namespace option {
1213 using BarWidth = details::IntegerSetting<details::ProgressBarOption::bar_width>;
1214 using PrefixText = details::StringSetting<details::ProgressBarOption::prefix_text>;
1215 using PostfixText = details::StringSetting<details::ProgressBarOption::postfix_text>;
1216 using Start = details::StringSetting<details::ProgressBarOption::start>;
1217 using End = details::StringSetting<details::ProgressBarOption::end>;
1218 using Fill = details::StringSetting<details::ProgressBarOption::fill>;
1219 using Lead = details::StringSetting<details::ProgressBarOption::lead>;
1220 using Remainder = details::StringSetting<details::ProgressBarOption::remainder>;
1221 using MaxPostfixTextLen = details::IntegerSetting<details::ProgressBarOption::max_postfix_text_len>;
1222 using Completed = details::BooleanSetting<details::ProgressBarOption::completed>;
1223 using ShowPercentage = details::BooleanSetting<details::ProgressBarOption::show_percentage>;
1224 using ShowElapsedTime = details::BooleanSetting<details::ProgressBarOption::show_elapsed_time>;
1225 using ShowRemainingTime = details::BooleanSetting<details::ProgressBarOption::show_remaining_time>;
1226 using SavedStartTime = details::BooleanSetting<details::ProgressBarOption::saved_start_time>;
1227 using ForegroundColor = details::Setting<Color, details::ProgressBarOption::foreground_color>;
1228 using ShowSpinner = details::BooleanSetting<details::ProgressBarOption::spinner_show>;
1229 using SpinnerStates =
1230  details::Setting<std::vector<std::string>, details::ProgressBarOption::spinner_states>;
1231 using HideBarWhenComplete =
1232  details::BooleanSetting<details::ProgressBarOption::hide_bar_when_complete>;
1233 using FontStyles =
1234  details::Setting<std::vector<FontStyle>, details::ProgressBarOption::font_styles>;
1235 using MinProgress = details::IntegerSetting<details::ProgressBarOption::min_progress>;
1236 using MaxProgress = details::IntegerSetting<details::ProgressBarOption::max_progress>;
1237 using ProgressType = details::Setting<ProgressType, details::ProgressBarOption::progress_type>;
1238 using Stream = details::Setting<std::ostream &, details::ProgressBarOption::stream>;
1239 } // namespace option
1240 } // namespace indicators
1241 
1242 #endif
1243 
1244 
1245 #ifndef INDICATORS_CURSOR_CONTROL
1246 #define INDICATORS_CURSOR_CONTROL
1247 
1248 #if defined(_MSC_VER)
1249 #if !defined(NOMINMAX)
1250 #define NOMINMAX
1251 #endif
1252 #include <io.h>
1253 #include <windows.h>
1254 #else
1255 #include <cstdio>
1256 #endif
1257 
1258 namespace indicators {
1259 
1260 #if defined(_MSC_VER)
1261 
1262 static inline void show_console_cursor(bool const show) {
1263  HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
1264 
1265  CONSOLE_CURSOR_INFO cursorInfo;
1266 
1267  GetConsoleCursorInfo(out, &cursorInfo);
1268  cursorInfo.bVisible = show; // set the cursor visibility
1269  SetConsoleCursorInfo(out, &cursorInfo);
1270 }
1271 
1272 static inline void erase_line() {
1273  auto hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1274  if (!hStdout)
1275  return;
1276 
1277  CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
1278  GetConsoleScreenBufferInfo(hStdout, &csbiInfo);
1279 
1280  COORD cursor;
1281 
1282  cursor.X = 0;
1283  cursor.Y = csbiInfo.dwCursorPosition.Y;
1284 
1285  DWORD count = 0;
1286 
1287  FillConsoleOutputCharacterA(hStdout, ' ', csbiInfo.dwSize.X, cursor, &count);
1288 
1289  FillConsoleOutputAttribute(hStdout, csbiInfo.wAttributes, csbiInfo.dwSize.X,
1290  cursor, &count);
1291 
1292  SetConsoleCursorPosition(hStdout, cursor);
1293 }
1294 
1295 #else
1296 
1297 static inline void show_console_cursor(bool const show) {
1298  std::fputs(show ? "\033[?25h" : "\033[?25l", stdout);
1299 }
1300 
1301 static inline void erase_line() {
1302  std::fputs("\r\033[K", stdout);
1303 }
1304 
1305 #endif
1306 
1307 } // namespace indicators
1308 
1309 #endif
1310 
1311 
1312 #ifndef INDICATORS_CURSOR_MOVEMENT
1313 #define INDICATORS_CURSOR_MOVEMENT
1314 
1315 #if defined(_MSC_VER)
1316 #if !defined(NOMINMAX)
1317 #define NOMINMAX
1318 #endif
1319 #include <io.h>
1320 #include <windows.h>
1321 #else
1322 #include <iostream>
1323 #endif
1324 
1325 namespace indicators {
1326 
1327 #ifdef _MSC_VER
1328 
1329 static inline void move(int x, int y) {
1330  auto hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1331  if (!hStdout)
1332  return;
1333 
1334  CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
1335  GetConsoleScreenBufferInfo(hStdout, &csbiInfo);
1336 
1337  COORD cursor;
1338 
1339  cursor.X = csbiInfo.dwCursorPosition.X + x;
1340  cursor.Y = csbiInfo.dwCursorPosition.Y + y;
1341  SetConsoleCursorPosition(hStdout, cursor);
1342 }
1343 
1344 static inline void move_up(int lines) { move(0, -lines); }
1345 static inline void move_down(int lines) { move(0, -lines); }
1346 static inline void move_right(int cols) { move(cols, 0); }
1347 static inline void move_left(int cols) { move(-cols, 0); }
1348 
1349 #else
1350 
1351 static inline void move_up(int lines) { std::cout << "\033[" << lines << "A"; }
1352 static inline void move_down(int lines) { std::cout << "\033[" << lines << "B"; }
1353 static inline void move_right(int cols) { std::cout << "\033[" << cols << "C"; }
1354 static inline void move_left(int cols) { std::cout << "\033[" << cols << "D"; }
1355 
1356 #endif
1357 
1358 } // namespace indicators
1359 
1360 #endif
1361 
1362 
1363 #ifndef INDICATORS_STREAM_HELPER
1364 #define INDICATORS_STREAM_HELPER
1365 
1366 // #include <indicators/display_width.hpp>
1367 #ifndef INDICATORS_DISPLAY_WIDTH
1368 #define INDICATORS_DISPLAY_WIDTH
1369 
1370 #include <clocale>
1371 #include <cstdlib>
1372 #include <locale>
1373 #include <string>
1374 #include <wchar.h>
1375 
1376 namespace unicode {
1377 
1378 namespace details {
1379 
1380 /*
1381  * This is an implementation of wcwidth() and wcswidth() (defined in
1382  * IEEE Std 1002.1-2001) for Unicode.
1383  *
1384  * http://www.opengroup.org/onlinepubs/007904975/functions/wcwidth.html
1385  * http://www.opengroup.org/onlinepubs/007904975/functions/wcswidth.html
1386  *
1387  * In fixed-width output devices, Latin characters all occupy a single
1388  * "cell" position of equal width, whereas ideographic CJK characters
1389  * occupy two such cells. Interoperability between terminal-line
1390  * applications and (teletype-style) character terminals using the
1391  * UTF-8 encoding requires agreement on which character should advance
1392  * the cursor by how many cell positions. No established formal
1393  * standards exist at present on which Unicode character shall occupy
1394  * how many cell positions on character terminals. These routines are
1395  * a first attempt of defining such behavior based on simple rules
1396  * applied to data provided by the Unicode Consortium.
1397  *
1398  * For some graphical characters, the Unicode standard explicitly
1399  * defines a character-cell width via the definition of the East Asian
1400  * FullWidth (F), Wide (W), Half-width (H), and Narrow (Na) classes.
1401  * In all these cases, there is no ambiguity about which width a
1402  * terminal shall use. For characters in the East Asian Ambiguous (A)
1403  * class, the width choice depends purely on a preference of backward
1404  * compatibility with either historic CJK or Western practice.
1405  * Choosing single-width for these characters is easy to justify as
1406  * the appropriate long-term solution, as the CJK practice of
1407  * displaying these characters as double-width comes from historic
1408  * implementation simplicity (8-bit encoded characters were displayed
1409  * single-width and 16-bit ones double-width, even for Greek,
1410  * Cyrillic, etc.) and not any typographic considerations.
1411  *
1412  * Much less clear is the choice of width for the Not East Asian
1413  * (Neutral) class. Existing practice does not dictate a width for any
1414  * of these characters. It would nevertheless make sense
1415  * typographically to allocate two character cells to characters such
1416  * as for instance EM SPACE or VOLUME INTEGRAL, which cannot be
1417  * represented adequately with a single-width glyph. The following
1418  * routines at present merely assign a single-cell width to all
1419  * neutral characters, in the interest of simplicity. This is not
1420  * entirely satisfactory and should be reconsidered before
1421  * establishing a formal standard in this area. At the moment, the
1422  * decision which Not East Asian (Neutral) characters should be
1423  * represented by double-width glyphs cannot yet be answered by
1424  * applying a simple rule from the Unicode database content. Setting
1425  * up a proper standard for the behavior of UTF-8 character terminals
1426  * will require a careful analysis not only of each Unicode character,
1427  * but also of each presentation form, something the author of these
1428  * routines has avoided to do so far.
1429  *
1430  * http://www.unicode.org/unicode/reports/tr11/
1431  *
1432  * Markus Kuhn -- 2007-05-26 (Unicode 5.0)
1433  *
1434  * Permission to use, copy, modify, and distribute this software
1435  * for any purpose and without fee is hereby granted. The author
1436  * disclaims all warranties with regard to this software.
1437  *
1438  * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
1439  */
1440 
1441 struct interval {
1442  int first;
1443  int last;
1444 };
1445 
1446 /* auxiliary function for binary search in interval table */
1447 static inline int bisearch(wchar_t ucs, const struct interval *table, int max) {
1448  int min = 0;
1449  int mid;
1450 
1451  if (ucs < table[0].first || ucs > table[max].last)
1452  return 0;
1453  while (max >= min) {
1454  mid = (min + max) / 2;
1455  if (ucs > table[mid].last)
1456  min = mid + 1;
1457  else if (ucs < table[mid].first)
1458  max = mid - 1;
1459  else
1460  return 1;
1461  }
1462 
1463  return 0;
1464 }
1465 
1466 /* The following two functions define the column width of an ISO 10646
1467  * character as follows:
1468  *
1469  * - The null character (U+0000) has a column width of 0.
1470  *
1471  * - Other C0/C1 control characters and DEL will lead to a return
1472  * value of -1.
1473  *
1474  * - Non-spacing and enclosing combining characters (general
1475  * category code Mn or Me in the Unicode database) have a
1476  * column width of 0.
1477  *
1478  * - SOFT HYPHEN (U+00AD) has a column width of 1.
1479  *
1480  * - Other format characters (general category code Cf in the Unicode
1481  * database) and ZERO WIDTH SPACE (U+200B) have a column width of 0.
1482  *
1483  * - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF)
1484  * have a column width of 0.
1485  *
1486  * - Spacing characters in the East Asian Wide (W) or East Asian
1487  * Full-width (F) category as defined in Unicode Technical
1488  * Report #11 have a column width of 2.
1489  *
1490  * - All remaining characters (including all printable
1491  * ISO 8859-1 and WGL4 characters, Unicode control characters,
1492  * etc.) have a column width of 1.
1493  *
1494  * This implementation assumes that wchar_t characters are encoded
1495  * in ISO 10646.
1496  */
1497 
1498 static inline int mk_wcwidth(wchar_t ucs) {
1499  /* sorted list of non-overlapping intervals of non-spacing characters */
1500  /* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */
1501  static const struct interval combining[] = {
1502  {0x0300, 0x036F}, {0x0483, 0x0486}, {0x0488, 0x0489},
1503  {0x0591, 0x05BD}, {0x05BF, 0x05BF}, {0x05C1, 0x05C2},
1504  {0x05C4, 0x05C5}, {0x05C7, 0x05C7}, {0x0600, 0x0603},
1505  {0x0610, 0x0615}, {0x064B, 0x065E}, {0x0670, 0x0670},
1506  {0x06D6, 0x06E4}, {0x06E7, 0x06E8}, {0x06EA, 0x06ED},
1507  {0x070F, 0x070F}, {0x0711, 0x0711}, {0x0730, 0x074A},
1508  {0x07A6, 0x07B0}, {0x07EB, 0x07F3}, {0x0901, 0x0902},
1509  {0x093C, 0x093C}, {0x0941, 0x0948}, {0x094D, 0x094D},
1510  {0x0951, 0x0954}, {0x0962, 0x0963}, {0x0981, 0x0981},
1511  {0x09BC, 0x09BC}, {0x09C1, 0x09C4}, {0x09CD, 0x09CD},
1512  {0x09E2, 0x09E3}, {0x0A01, 0x0A02}, {0x0A3C, 0x0A3C},
1513  {0x0A41, 0x0A42}, {0x0A47, 0x0A48}, {0x0A4B, 0x0A4D},
1514  {0x0A70, 0x0A71}, {0x0A81, 0x0A82}, {0x0ABC, 0x0ABC},
1515  {0x0AC1, 0x0AC5}, {0x0AC7, 0x0AC8}, {0x0ACD, 0x0ACD},
1516  {0x0AE2, 0x0AE3}, {0x0B01, 0x0B01}, {0x0B3C, 0x0B3C},
1517  {0x0B3F, 0x0B3F}, {0x0B41, 0x0B43}, {0x0B4D, 0x0B4D},
1518  {0x0B56, 0x0B56}, {0x0B82, 0x0B82}, {0x0BC0, 0x0BC0},
1519  {0x0BCD, 0x0BCD}, {0x0C3E, 0x0C40}, {0x0C46, 0x0C48},
1520  {0x0C4A, 0x0C4D}, {0x0C55, 0x0C56}, {0x0CBC, 0x0CBC},
1521  {0x0CBF, 0x0CBF}, {0x0CC6, 0x0CC6}, {0x0CCC, 0x0CCD},
1522  {0x0CE2, 0x0CE3}, {0x0D41, 0x0D43}, {0x0D4D, 0x0D4D},
1523  {0x0DCA, 0x0DCA}, {0x0DD2, 0x0DD4}, {0x0DD6, 0x0DD6},
1524  {0x0E31, 0x0E31}, {0x0E34, 0x0E3A}, {0x0E47, 0x0E4E},
1525  {0x0EB1, 0x0EB1}, {0x0EB4, 0x0EB9}, {0x0EBB, 0x0EBC},
1526  {0x0EC8, 0x0ECD}, {0x0F18, 0x0F19}, {0x0F35, 0x0F35},
1527  {0x0F37, 0x0F37}, {0x0F39, 0x0F39}, {0x0F71, 0x0F7E},
1528  {0x0F80, 0x0F84}, {0x0F86, 0x0F87}, {0x0F90, 0x0F97},
1529  {0x0F99, 0x0FBC}, {0x0FC6, 0x0FC6}, {0x102D, 0x1030},
1530  {0x1032, 0x1032}, {0x1036, 0x1037}, {0x1039, 0x1039},
1531  {0x1058, 0x1059}, {0x1160, 0x11FF}, {0x135F, 0x135F},
1532  {0x1712, 0x1714}, {0x1732, 0x1734}, {0x1752, 0x1753},
1533  {0x1772, 0x1773}, {0x17B4, 0x17B5}, {0x17B7, 0x17BD},
1534  {0x17C6, 0x17C6}, {0x17C9, 0x17D3}, {0x17DD, 0x17DD},
1535  {0x180B, 0x180D}, {0x18A9, 0x18A9}, {0x1920, 0x1922},
1536  {0x1927, 0x1928}, {0x1932, 0x1932}, {0x1939, 0x193B},
1537  {0x1A17, 0x1A18}, {0x1B00, 0x1B03}, {0x1B34, 0x1B34},
1538  {0x1B36, 0x1B3A}, {0x1B3C, 0x1B3C}, {0x1B42, 0x1B42},
1539  {0x1B6B, 0x1B73}, {0x1DC0, 0x1DCA}, {0x1DFE, 0x1DFF},
1540  {0x200B, 0x200F}, {0x202A, 0x202E}, {0x2060, 0x2063},
1541  {0x206A, 0x206F}, {0x20D0, 0x20EF}, {0x302A, 0x302F},
1542  {0x3099, 0x309A}, {0xA806, 0xA806}, {0xA80B, 0xA80B},
1543  {0xA825, 0xA826}, {0xFB1E, 0xFB1E}, {0xFE00, 0xFE0F},
1544  {0xFE20, 0xFE23}, {0xFEFF, 0xFEFF}, {0xFFF9, 0xFFFB},
1545  {0x10A01, 0x10A03}, {0x10A05, 0x10A06}, {0x10A0C, 0x10A0F},
1546  {0x10A38, 0x10A3A}, {0x10A3F, 0x10A3F}, {0x1D167, 0x1D169},
1547  {0x1D173, 0x1D182}, {0x1D185, 0x1D18B}, {0x1D1AA, 0x1D1AD},
1548  {0x1D242, 0x1D244}, {0xE0001, 0xE0001}, {0xE0020, 0xE007F},
1549  {0xE0100, 0xE01EF}};
1550 
1551  /* test for 8-bit control characters */
1552  if (ucs == 0)
1553  return 0;
1554  if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0))
1555  return -1;
1556 
1557  /* binary search in table of non-spacing characters */
1558  if (bisearch(ucs, combining, sizeof(combining) / sizeof(struct interval) - 1))
1559  return 0;
1560 
1561  /* if we arrive here, ucs is not a combining or C0/C1 control character */
1562 
1563  return 1 +
1564  (ucs >= 0x1100 &&
1565  (ucs <= 0x115f || /* Hangul Jamo init. consonants */
1566  ucs == 0x2329 || ucs == 0x232a ||
1567  (ucs >= 0x2e80 && ucs <= 0xa4cf && ucs != 0x303f) || /* CJK ... Yi */
1568  (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */
1569  (ucs >= 0xf900 &&
1570  ucs <= 0xfaff) || /* CJK Compatibility Ideographs */
1571  (ucs >= 0xfe10 && ucs <= 0xfe19) || /* Vertical forms */
1572  (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */
1573  (ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */
1574  (ucs >= 0xffe0 && ucs <= 0xffe6) ||
1575  (ucs >= 0x20000 && ucs <= 0x2fffd) ||
1576  (ucs >= 0x30000 && ucs <= 0x3fffd)));
1577 }
1578 
1579 static inline int mk_wcswidth(const wchar_t *pwcs, size_t n) {
1580  int w, width = 0;
1581 
1582  for (; *pwcs && n-- > 0; pwcs++)
1583  if ((w = mk_wcwidth(*pwcs)) < 0)
1584  return -1;
1585  else
1586  width += w;
1587 
1588  return width;
1589 }
1590 
1591 /*
1592  * The following functions are the same as mk_wcwidth() and
1593  * mk_wcswidth(), except that spacing characters in the East Asian
1594  * Ambiguous (A) category as defined in Unicode Technical Report #11
1595  * have a column width of 2. This variant might be useful for users of
1596  * CJK legacy encodings who want to migrate to UCS without changing
1597  * the traditional terminal character-width behaviour. It is not
1598  * otherwise recommended for general use.
1599  */
1600 static inline int mk_wcwidth_cjk(wchar_t ucs) {
1601  /* sorted list of non-overlapping intervals of East Asian Ambiguous
1602  * characters, generated by "uniset +WIDTH-A -cat=Me -cat=Mn -cat=Cf c" */
1603  static const struct interval ambiguous[] = {
1604  {0x00A1, 0x00A1}, {0x00A4, 0x00A4}, {0x00A7, 0x00A8},
1605  {0x00AA, 0x00AA}, {0x00AE, 0x00AE}, {0x00B0, 0x00B4},
1606  {0x00B6, 0x00BA}, {0x00BC, 0x00BF}, {0x00C6, 0x00C6},
1607  {0x00D0, 0x00D0}, {0x00D7, 0x00D8}, {0x00DE, 0x00E1},
1608  {0x00E6, 0x00E6}, {0x00E8, 0x00EA}, {0x00EC, 0x00ED},
1609  {0x00F0, 0x00F0}, {0x00F2, 0x00F3}, {0x00F7, 0x00FA},
1610  {0x00FC, 0x00FC}, {0x00FE, 0x00FE}, {0x0101, 0x0101},
1611  {0x0111, 0x0111}, {0x0113, 0x0113}, {0x011B, 0x011B},
1612  {0x0126, 0x0127}, {0x012B, 0x012B}, {0x0131, 0x0133},
1613  {0x0138, 0x0138}, {0x013F, 0x0142}, {0x0144, 0x0144},
1614  {0x0148, 0x014B}, {0x014D, 0x014D}, {0x0152, 0x0153},
1615  {0x0166, 0x0167}, {0x016B, 0x016B}, {0x01CE, 0x01CE},
1616  {0x01D0, 0x01D0}, {0x01D2, 0x01D2}, {0x01D4, 0x01D4},
1617  {0x01D6, 0x01D6}, {0x01D8, 0x01D8}, {0x01DA, 0x01DA},
1618  {0x01DC, 0x01DC}, {0x0251, 0x0251}, {0x0261, 0x0261},
1619  {0x02C4, 0x02C4}, {0x02C7, 0x02C7}, {0x02C9, 0x02CB},
1620  {0x02CD, 0x02CD}, {0x02D0, 0x02D0}, {0x02D8, 0x02DB},
1621  {0x02DD, 0x02DD}, {0x02DF, 0x02DF}, {0x0391, 0x03A1},
1622  {0x03A3, 0x03A9}, {0x03B1, 0x03C1}, {0x03C3, 0x03C9},
1623  {0x0401, 0x0401}, {0x0410, 0x044F}, {0x0451, 0x0451},
1624  {0x2010, 0x2010}, {0x2013, 0x2016}, {0x2018, 0x2019},
1625  {0x201C, 0x201D}, {0x2020, 0x2022}, {0x2024, 0x2027},
1626  {0x2030, 0x2030}, {0x2032, 0x2033}, {0x2035, 0x2035},
1627  {0x203B, 0x203B}, {0x203E, 0x203E}, {0x2074, 0x2074},
1628  {0x207F, 0x207F}, {0x2081, 0x2084}, {0x20AC, 0x20AC},
1629  {0x2103, 0x2103}, {0x2105, 0x2105}, {0x2109, 0x2109},
1630  {0x2113, 0x2113}, {0x2116, 0x2116}, {0x2121, 0x2122},
1631  {0x2126, 0x2126}, {0x212B, 0x212B}, {0x2153, 0x2154},
1632  {0x215B, 0x215E}, {0x2160, 0x216B}, {0x2170, 0x2179},
1633  {0x2190, 0x2199}, {0x21B8, 0x21B9}, {0x21D2, 0x21D2},
1634  {0x21D4, 0x21D4}, {0x21E7, 0x21E7}, {0x2200, 0x2200},
1635  {0x2202, 0x2203}, {0x2207, 0x2208}, {0x220B, 0x220B},
1636  {0x220F, 0x220F}, {0x2211, 0x2211}, {0x2215, 0x2215},
1637  {0x221A, 0x221A}, {0x221D, 0x2220}, {0x2223, 0x2223},
1638  {0x2225, 0x2225}, {0x2227, 0x222C}, {0x222E, 0x222E},
1639  {0x2234, 0x2237}, {0x223C, 0x223D}, {0x2248, 0x2248},
1640  {0x224C, 0x224C}, {0x2252, 0x2252}, {0x2260, 0x2261},
1641  {0x2264, 0x2267}, {0x226A, 0x226B}, {0x226E, 0x226F},
1642  {0x2282, 0x2283}, {0x2286, 0x2287}, {0x2295, 0x2295},
1643  {0x2299, 0x2299}, {0x22A5, 0x22A5}, {0x22BF, 0x22BF},
1644  {0x2312, 0x2312}, {0x2460, 0x24E9}, {0x24EB, 0x254B},
1645  {0x2550, 0x2573}, {0x2580, 0x258F}, {0x2592, 0x2595},
1646  {0x25A0, 0x25A1}, {0x25A3, 0x25A9}, {0x25B2, 0x25B3},
1647  {0x25B6, 0x25B7}, {0x25BC, 0x25BD}, {0x25C0, 0x25C1},
1648  {0x25C6, 0x25C8}, {0x25CB, 0x25CB}, {0x25CE, 0x25D1},
1649  {0x25E2, 0x25E5}, {0x25EF, 0x25EF}, {0x2605, 0x2606},
1650  {0x2609, 0x2609}, {0x260E, 0x260F}, {0x2614, 0x2615},
1651  {0x261C, 0x261C}, {0x261E, 0x261E}, {0x2640, 0x2640},
1652  {0x2642, 0x2642}, {0x2660, 0x2661}, {0x2663, 0x2665},
1653  {0x2667, 0x266A}, {0x266C, 0x266D}, {0x266F, 0x266F},
1654  {0x273D, 0x273D}, {0x2776, 0x277F}, {0xE000, 0xF8FF},
1655  {0xFFFD, 0xFFFD}, {0xF0000, 0xFFFFD}, {0x100000, 0x10FFFD}};
1656 
1657  /* binary search in table of non-spacing characters */
1658  if (bisearch(ucs, ambiguous, sizeof(ambiguous) / sizeof(struct interval) - 1))
1659  return 2;
1660 
1661  return mk_wcwidth(ucs);
1662 }
1663 
1664 static inline int mk_wcswidth_cjk(const wchar_t *pwcs, size_t n) {
1665  int w, width = 0;
1666 
1667  for (; *pwcs && n-- > 0; pwcs++)
1668  if ((w = mk_wcwidth_cjk(*pwcs)) < 0)
1669  return -1;
1670  else
1671  width += w;
1672 
1673  return width;
1674 }
1675 
1676 // convert UTF-8 string to wstring
1677 #ifdef _MSC_VER
1678 static inline std::wstring utf8_decode(const std::string& s) {
1679  std::string curLocale = setlocale(LC_ALL, "");
1680  const char* _Source = s.c_str();
1681  size_t _Dsize = std::strlen(_Source) + 1;
1682  wchar_t* _Dest = new wchar_t[_Dsize];
1683  size_t _Osize;
1684  mbstowcs_s(&_Osize, _Dest, _Dsize, _Source, _Dsize);
1685  std::wstring result = _Dest;
1686  delete[] _Dest;
1687  setlocale(LC_ALL, curLocale.c_str());
1688  return result;
1689 }
1690 #else
1691 static inline std::wstring utf8_decode(const std::string& s) {
1692  std::string curLocale = setlocale(LC_ALL, "");
1693  const char* _Source = s.c_str();
1694  size_t _Dsize = mbstowcs(NULL, _Source, 0) + 1;
1695  wchar_t* _Dest = new wchar_t[_Dsize];
1696  wmemset(_Dest, 0, _Dsize);
1697  mbstowcs(_Dest, _Source, _Dsize);
1698  std::wstring result = _Dest;
1699  delete[] _Dest;
1700  setlocale(LC_ALL, curLocale.c_str());
1701  return result;
1702 }
1703 #endif
1704 
1705 } // namespace details
1706 
1707 static inline int display_width(const std::string &input) {
1708  using namespace unicode::details;
1709  return mk_wcswidth(utf8_decode(input).c_str(), input.size());
1710 }
1711 
1712 static inline int display_width(const std::wstring &input) {
1713  return details::mk_wcswidth(input.c_str(), input.size());
1714 }
1715 
1716 } // namespace unicode
1717 
1718 #endif
1719 // #include <indicators/setting.hpp>
1720 // #include <indicators/termcolor.hpp>
1721 
1722 #include <algorithm>
1723 #include <chrono>
1724 #include <iomanip>
1725 #include <ostream>
1726 #include <string>
1727 #include <vector>
1728 
1729 #include <cassert>
1730 #include <cmath>
1731 
1732 namespace indicators {
1733 namespace details {
1734 
1735 inline void set_stream_color(std::ostream &os, Color color) {
1736  switch (color) {
1737  case Color::grey:
1738  os << termcolor::grey;
1739  break;
1740  case Color::red:
1741  os << termcolor::red;
1742  break;
1743  case Color::green:
1744  os << termcolor::green;
1745  break;
1746  case Color::yellow:
1747  os << termcolor::yellow;
1748  break;
1749  case Color::blue:
1750  os << termcolor::blue;
1751  break;
1752  case Color::magenta:
1753  os << termcolor::magenta;
1754  break;
1755  case Color::cyan:
1756  os << termcolor::cyan;
1757  break;
1758  case Color::white:
1759  os << termcolor::white;
1760  break;
1761  default:
1762  assert(false);
1763  }
1764 }
1765 
1766 inline void set_font_style(std::ostream &os, FontStyle style) {
1767  switch (style) {
1768  case FontStyle::bold:
1769  os << termcolor::bold;
1770  break;
1771  case FontStyle::dark:
1772  os << termcolor::dark;
1773  break;
1774  case FontStyle::italic:
1775  os << termcolor::italic;
1776  break;
1777  case FontStyle::underline:
1778  os << termcolor::underline;
1779  break;
1780  case FontStyle::blink:
1781  os << termcolor::blink;
1782  break;
1783  case FontStyle::reverse:
1784  os << termcolor::reverse;
1785  break;
1786  case FontStyle::concealed:
1787  os << termcolor::concealed;
1788  break;
1789  case FontStyle::crossed:
1790  os << termcolor::crossed;
1791  break;
1792  default:
1793  break;
1794  }
1795 }
1796 
1797 inline std::ostream &write_duration(std::ostream &os, std::chrono::nanoseconds ns) {
1798  using namespace std;
1799  using namespace std::chrono;
1800  using days = duration<int, ratio<86400>>;
1801  char fill = os.fill();
1802  os.fill('0');
1803  auto d = duration_cast<days>(ns);
1804  ns -= d;
1805  auto h = duration_cast<hours>(ns);
1806  ns -= h;
1807  auto m = duration_cast<minutes>(ns);
1808  ns -= m;
1809  auto s = duration_cast<seconds>(ns);
1810  if (d.count() > 0)
1811  os << setw(2) << d.count() << "d:";
1812  if (h.count() > 0)
1813  os << setw(2) << h.count() << "h:";
1814  os << setw(2) << m.count() << "m:" << setw(2) << s.count() << 's';
1815  os.fill(fill);
1816  return os;
1817 }
1818 
1819 class BlockProgressScaleWriter {
1820 public:
1821  BlockProgressScaleWriter(std::ostream &os, size_t bar_width) : os(os), bar_width(bar_width) {}
1822 
1823  std::ostream &write(float progress) {
1824  std::string fill_text{"█"};
1825  std::vector<std::string> lead_characters{" ", "▏", "▎", "▍", "▌", "▋", "▊", "▉"};
1826  auto value = (std::min)(1.0f, (std::max)(0.0f, progress / 100.0f));
1827  auto whole_width = std::floor(value * bar_width);
1828  auto remainder_width = fmod((value * bar_width), 1.0f);
1829  auto part_width = std::floor(remainder_width * lead_characters.size());
1830  std::string lead_text = lead_characters[size_t(part_width)];
1831  if ((bar_width - whole_width - 1) < 0)
1832  lead_text = "";
1833  for (size_t i = 0; i < whole_width; ++i)
1834  os << fill_text;
1835  os << lead_text;
1836  for (size_t i = 0; i < (bar_width - whole_width - 1); ++i)
1837  os << " ";
1838  return os;
1839  }
1840 
1841 private:
1842  std::ostream &os;
1843  size_t bar_width = 0;
1844 };
1845 
1846 class ProgressScaleWriter {
1847 public:
1848  ProgressScaleWriter(std::ostream &os, size_t bar_width, const std::string &fill,
1849  const std::string &lead, const std::string &remainder)
1850  : os(os), bar_width(bar_width), fill(fill), lead(lead), remainder(remainder) {}
1851 
1852  std::ostream &write(float progress) {
1853  auto pos = static_cast<size_t>(progress * bar_width / 100.0);
1854  for (size_t i = 0, current_display_width = 0; i < bar_width;) {
1855  std::string next;
1856 
1857  if (i < pos) {
1858  next = fill;
1859  current_display_width = unicode::display_width(fill);
1860  } else if (i == pos) {
1861  next = lead;
1862  current_display_width = unicode::display_width(lead);
1863  } else {
1864  next = remainder;
1865  current_display_width = unicode::display_width(remainder);
1866  }
1867 
1868  i += current_display_width;
1869 
1870  if (i > bar_width) {
1871  // `next` is larger than the allowed bar width
1872  // fill with empty space instead
1873  os << std::string((bar_width - (i - current_display_width)), ' ');
1874  break;
1875  }
1876 
1877  os << next;
1878  }
1879  return os;
1880  }
1881 
1882 private:
1883  std::ostream &os;
1884  size_t bar_width = 0;
1885  std::string fill;
1886  std::string lead;
1887  std::string remainder;
1888 };
1889 
1890 class IndeterminateProgressScaleWriter {
1891 public:
1892  IndeterminateProgressScaleWriter(std::ostream &os, size_t bar_width, const std::string &fill,
1893  const std::string &lead)
1894  : os(os), bar_width(bar_width), fill(fill), lead(lead) {}
1895 
1896  std::ostream &write(size_t progress) {
1897  for (size_t i = 0; i < bar_width;) {
1898  std::string next;
1899  size_t current_display_width = 0;
1900 
1901  if (i < progress) {
1902  next = fill;
1903  current_display_width = unicode::display_width(fill);
1904  } else if (i == progress) {
1905  next = lead;
1906  current_display_width = unicode::display_width(lead);
1907  } else {
1908  next = fill;
1909  current_display_width = unicode::display_width(fill);
1910  }
1911 
1912  i += current_display_width;
1913 
1914  if (i > bar_width) {
1915  // `next` is larger than the allowed bar width
1916  // fill with empty space instead
1917  os << std::string((bar_width - (i - current_display_width)), ' ');
1918  break;
1919  }
1920 
1921  os << next;
1922  }
1923  return os;
1924  }
1925 
1926 private:
1927  std::ostream &os;
1928  size_t bar_width = 0;
1929  std::string fill;
1930  std::string lead;
1931 };
1932 
1933 } // namespace details
1934 } // namespace indicators
1935 
1936 #endif
1937 
1938 
1939 #ifndef INDICATORS_PROGRESS_BAR
1940 #define INDICATORS_PROGRESS_BAR
1941 
1942 // #include <indicators/details/stream_helper.hpp>
1943 
1944 #include <algorithm>
1945 #include <atomic>
1946 #include <chrono>
1947 #include <cmath>
1948 // #include <indicators/color.hpp>
1949 // #include <indicators/setting.hpp>
1950 // #include <indicators/terminal_size.hpp>
1951 #include <iomanip>
1952 #include <iostream>
1953 #include <sstream>
1954 #include <mutex>
1955 #include <string>
1956 #include <thread>
1957 #include <tuple>
1958 #include <type_traits>
1959 #include <utility>
1960 
1961 namespace indicators {
1962 
1963 class ProgressBar {
1964  using Settings =
1965  std::tuple<option::BarWidth, option::PrefixText, option::PostfixText,
1966  option::Start, option::End, option::Fill, option::Lead,
1967  option::Remainder, option::MaxPostfixTextLen,
1968  option::Completed, option::ShowPercentage,
1969  option::ShowElapsedTime, option::ShowRemainingTime,
1970  option::SavedStartTime, option::ForegroundColor,
1971  option::FontStyles, option::MinProgress, option::MaxProgress,
1972  option::ProgressType, option::Stream>;
1973 
1974 public:
1975  template <typename... Args,
1976  typename std::enable_if<
1977  details::are_settings_from_tuple<
1978  Settings, typename std::decay<Args>::type...>::value,
1979  void *>::type = nullptr>
1980  explicit ProgressBar(Args &&... args)
1981  : settings_(
1982  details::get<details::ProgressBarOption::bar_width>(
1983  option::BarWidth{100}, std::forward<Args>(args)...),
1984  details::get<details::ProgressBarOption::prefix_text>(
1985  option::PrefixText{}, std::forward<Args>(args)...),
1986  details::get<details::ProgressBarOption::postfix_text>(
1987  option::PostfixText{}, std::forward<Args>(args)...),
1988  details::get<details::ProgressBarOption::start>(
1989  option::Start{"["}, std::forward<Args>(args)...),
1990  details::get<details::ProgressBarOption::end>(
1991  option::End{"]"}, std::forward<Args>(args)...),
1992  details::get<details::ProgressBarOption::fill>(
1993  option::Fill{"="}, std::forward<Args>(args)...),
1994  details::get<details::ProgressBarOption::lead>(
1995  option::Lead{">"}, std::forward<Args>(args)...),
1996  details::get<details::ProgressBarOption::remainder>(
1997  option::Remainder{" "}, std::forward<Args>(args)...),
1998  details::get<details::ProgressBarOption::max_postfix_text_len>(
1999  option::MaxPostfixTextLen{0}, std::forward<Args>(args)...),
2000  details::get<details::ProgressBarOption::completed>(
2001  option::Completed{false}, std::forward<Args>(args)...),
2002  details::get<details::ProgressBarOption::show_percentage>(
2003  option::ShowPercentage{false}, std::forward<Args>(args)...),
2004  details::get<details::ProgressBarOption::show_elapsed_time>(
2005  option::ShowElapsedTime{false}, std::forward<Args>(args)...),
2006  details::get<details::ProgressBarOption::show_remaining_time>(
2007  option::ShowRemainingTime{false}, std::forward<Args>(args)...),
2008  details::get<details::ProgressBarOption::saved_start_time>(
2009  option::SavedStartTime{false}, std::forward<Args>(args)...),
2010  details::get<details::ProgressBarOption::foreground_color>(
2011  option::ForegroundColor{Color::unspecified},
2012  std::forward<Args>(args)...),
2013  details::get<details::ProgressBarOption::font_styles>(
2014  option::FontStyles{std::vector<FontStyle>{}},
2015  std::forward<Args>(args)...),
2016  details::get<details::ProgressBarOption::min_progress>(
2017  option::MinProgress{0}, std::forward<Args>(args)...),
2018  details::get<details::ProgressBarOption::max_progress>(
2019  option::MaxProgress{100}, std::forward<Args>(args)...),
2020  details::get<details::ProgressBarOption::progress_type>(
2021  option::ProgressType{ProgressType::incremental},
2022  std::forward<Args>(args)...),
2023  details::get<details::ProgressBarOption::stream>(
2024  option::Stream{std::cout}, std::forward<Args>(args)...)) {
2025 
2026  // if progress is incremental, start from min_progress
2027  // else start from max_progress
2028  const auto type = get_value<details::ProgressBarOption::progress_type>();
2029  if (type == ProgressType::incremental)
2030  progress_ = get_value<details::ProgressBarOption::min_progress>();
2031  else
2032  progress_ = get_value<details::ProgressBarOption::max_progress>();
2033  }
2034 
2035  template <typename T, details::ProgressBarOption id>
2036  void set_option(details::Setting<T, id> &&setting) {
2037  static_assert(
2038  !std::is_same<T, typename std::decay<decltype(details::get_value<id>(
2039  std::declval<Settings>()))>::type>::value,
2040  "Setting has wrong type!");
2041  std::lock_guard<std::mutex> lock(mutex_);
2042  get_value<id>() = std::move(setting).value;
2043  }
2044 
2045  template <typename T, details::ProgressBarOption id>
2046  void set_option(const details::Setting<T, id> &setting) {
2047  static_assert(
2048  !std::is_same<T, typename std::decay<decltype(details::get_value<id>(
2049  std::declval<Settings>()))>::type>::value,
2050  "Setting has wrong type!");
2051  std::lock_guard<std::mutex> lock(mutex_);
2052  get_value<id>() = setting.value;
2053  }
2054 
2055  void
2056  set_option(const details::Setting<
2057  std::string, details::ProgressBarOption::postfix_text> &setting) {
2058  std::lock_guard<std::mutex> lock(mutex_);
2059  get_value<details::ProgressBarOption::postfix_text>() = setting.value;
2060  if (setting.value.length() >
2061  get_value<details::ProgressBarOption::max_postfix_text_len>()) {
2062  get_value<details::ProgressBarOption::max_postfix_text_len>() =
2063  setting.value.length();
2064  }
2065  }
2066 
2067  void set_option(
2068  details::Setting<std::string, details::ProgressBarOption::postfix_text>
2069  &&setting) {
2070  std::lock_guard<std::mutex> lock(mutex_);
2071  get_value<details::ProgressBarOption::postfix_text>() =
2072  std::move(setting).value;
2073  auto &new_value = get_value<details::ProgressBarOption::postfix_text>();
2074  if (new_value.length() >
2075  get_value<details::ProgressBarOption::max_postfix_text_len>()) {
2076  get_value<details::ProgressBarOption::max_postfix_text_len>() =
2077  new_value.length();
2078  }
2079  }
2080 
2081  void set_progress(size_t new_progress) {
2082  {
2083  std::lock_guard<std::mutex> lock(mutex_);
2084  progress_ = new_progress;
2085  }
2086 
2087  save_start_time();
2088  print_progress();
2089  }
2090 
2091  void tick() {
2092  {
2093  std::lock_guard<std::mutex> lock{mutex_};
2094  const auto type = get_value<details::ProgressBarOption::progress_type>();
2095  if (type == ProgressType::incremental)
2096  progress_ += 1;
2097  else
2098  progress_ -= 1;
2099  }
2100  save_start_time();
2101  print_progress();
2102  }
2103 
2104  size_t current() {
2105  std::lock_guard<std::mutex> lock{mutex_};
2106  return (std::min)(
2107  progress_,
2108  size_t(get_value<details::ProgressBarOption::max_progress>()));
2109  }
2110 
2111  bool is_completed() const {
2112  return get_value<details::ProgressBarOption::completed>();
2113  }
2114 
2115  void mark_as_completed() {
2116  get_value<details::ProgressBarOption::completed>() = true;
2117  print_progress();
2118  }
2119 
2120 private:
2121  template <details::ProgressBarOption id>
2122  auto get_value()
2123  -> decltype((details::get_value<id>(std::declval<Settings &>()).value)) {
2124  return details::get_value<id>(settings_).value;
2125  }
2126 
2127  template <details::ProgressBarOption id>
2128  auto get_value() const -> decltype(
2129  (details::get_value<id>(std::declval<const Settings &>()).value)) {
2130  return details::get_value<id>(settings_).value;
2131  }
2132 
2133  size_t progress_{0};
2134  Settings settings_;
2135  std::chrono::nanoseconds elapsed_;
2136  std::chrono::time_point<std::chrono::high_resolution_clock> start_time_point_;
2137  std::mutex mutex_;
2138 
2139  template <typename Indicator, size_t count> friend class MultiProgress;
2140  template <typename Indicator> friend class DynamicProgress;
2141  std::atomic<bool> multi_progress_mode_{false};
2142 
2143  void save_start_time() {
2144  auto &show_elapsed_time =
2145  get_value<details::ProgressBarOption::show_elapsed_time>();
2146  auto &saved_start_time =
2147  get_value<details::ProgressBarOption::saved_start_time>();
2148  auto &show_remaining_time =
2149  get_value<details::ProgressBarOption::show_remaining_time>();
2150  if ((show_elapsed_time || show_remaining_time) && !saved_start_time) {
2151  start_time_point_ = std::chrono::high_resolution_clock::now();
2152  saved_start_time = true;
2153  }
2154  }
2155 
2156  std::pair<std::string, int> get_prefix_text() {
2157  std::stringstream os;
2158  os << get_value<details::ProgressBarOption::prefix_text>();
2159  const auto result = os.str();
2160  const auto result_size = unicode::display_width(result);
2161  return {result, result_size};
2162  }
2163 
2164  std::pair<std::string, int> get_postfix_text() {
2165  std::stringstream os;
2166  const auto max_progress =
2167  get_value<details::ProgressBarOption::max_progress>();
2168 
2169  if (get_value<details::ProgressBarOption::show_percentage>()) {
2170  os << " "
2171  << (std::min)(static_cast<size_t>(static_cast<float>(progress_) /
2172  max_progress * 100),
2173  size_t(100))
2174  << "%";
2175  }
2176 
2177  auto &saved_start_time =
2178  get_value<details::ProgressBarOption::saved_start_time>();
2179 
2180  if (get_value<details::ProgressBarOption::show_elapsed_time>()) {
2181  os << " [";
2182  if (saved_start_time)
2183  details::write_duration(os, elapsed_);
2184  else
2185  os << "00:00s";
2186  }
2187 
2188  if (get_value<details::ProgressBarOption::show_remaining_time>()) {
2189  if (get_value<details::ProgressBarOption::show_elapsed_time>())
2190  os << "<";
2191  else
2192  os << " [";
2193 
2194  if (saved_start_time) {
2195  auto eta = std::chrono::nanoseconds(
2196  progress_ > 0
2197  ? static_cast<long long>(std::ceil(float(elapsed_.count()) *
2198  max_progress / progress_))
2199  : 0);
2200  auto remaining = eta > elapsed_ ? (eta - elapsed_) : (elapsed_ - eta);
2201  details::write_duration(os, remaining);
2202  } else {
2203  os << "00:00s";
2204  }
2205 
2206  os << "]";
2207  } else {
2208  if (get_value<details::ProgressBarOption::show_elapsed_time>())
2209  os << "]";
2210  }
2211 
2212  os << " " << get_value<details::ProgressBarOption::postfix_text>();
2213 
2214  const auto result = os.str();
2215  const auto result_size = unicode::display_width(result);
2216  return {result, result_size};
2217  }
2218 
2219 public:
2220  void print_progress(bool from_multi_progress = false) {
2221  std::lock_guard<std::mutex> lock{mutex_};
2222 
2223  auto &os = get_value<details::ProgressBarOption::stream>();
2224 
2225  const auto type = get_value<details::ProgressBarOption::progress_type>();
2226  const auto min_progress =
2227  get_value<details::ProgressBarOption::min_progress>();
2228  const auto max_progress =
2229  get_value<details::ProgressBarOption::max_progress>();
2230  if (multi_progress_mode_ && !from_multi_progress) {
2231  if ((type == ProgressType::incremental && progress_ >= max_progress) ||
2232  (type == ProgressType::decremental && progress_ <= min_progress)) {
2233  get_value<details::ProgressBarOption::completed>() = true;
2234  }
2235  return;
2236  }
2237  auto now = std::chrono::high_resolution_clock::now();
2238  if (!get_value<details::ProgressBarOption::completed>())
2239  elapsed_ = std::chrono::duration_cast<std::chrono::nanoseconds>(
2240  now - start_time_point_);
2241 
2242  if (get_value<details::ProgressBarOption::foreground_color>() !=
2243  Color::unspecified)
2244  details::set_stream_color(
2245  os, get_value<details::ProgressBarOption::foreground_color>());
2246 
2247  for (auto &style : get_value<details::ProgressBarOption::font_styles>())
2248  details::set_font_style(os, style);
2249 
2250  const auto prefix_pair = get_prefix_text();
2251  const auto prefix_text = prefix_pair.first;
2252  const auto prefix_length = prefix_pair.second;
2253  os << "\r" << prefix_text;
2254 
2255  os << get_value<details::ProgressBarOption::start>();
2256 
2257  details::ProgressScaleWriter writer{
2258  os, get_value<details::ProgressBarOption::bar_width>(),
2259  get_value<details::ProgressBarOption::fill>(),
2260  get_value<details::ProgressBarOption::lead>(),
2261  get_value<details::ProgressBarOption::remainder>()};
2262  writer.write(double(progress_) / double(max_progress) * 100.0f);
2263 
2264  os << get_value<details::ProgressBarOption::end>();
2265 
2266  const auto postfix_pair = get_postfix_text();
2267  const auto postfix_text = postfix_pair.first;
2268  const auto postfix_length = postfix_pair.second;
2269  os << postfix_text;
2270 
2271  // Get length of prefix text and postfix text
2272  const auto start_length = get_value<details::ProgressBarOption::start>().size();
2273  const auto bar_width = get_value<details::ProgressBarOption::bar_width>();
2274  const auto end_length = get_value<details::ProgressBarOption::end>().size();
2275  const auto terminal_width = terminal_size().second;
2276  // prefix + bar_width + postfix should be <= terminal_width
2277  const int remaining = terminal_width - (prefix_length + start_length + bar_width + end_length + postfix_length);
2278  if (prefix_length == -1 || postfix_length == -1) {
2279  os << "\r";
2280  } else if (remaining > 0) {
2281  os << std::string(remaining, ' ') << "\r";
2282  } else if (remaining < 0) {
2283  // Do nothing. Maybe in the future truncate postfix with ...
2284  }
2285  os.flush();
2286 
2287  if ((type == ProgressType::incremental && progress_ >= max_progress) ||
2288  (type == ProgressType::decremental && progress_ <= min_progress)) {
2289  get_value<details::ProgressBarOption::completed>() = true;
2290  }
2291  if (get_value<details::ProgressBarOption::completed>() &&
2292  !from_multi_progress) // Don't std::endl if calling from MultiProgress
2293  os << termcolor::reset << std::endl;
2294  }
2295 };
2296 
2297 } // namespace indicators
2298 
2299 #endif
2300 
2301 
2302 #ifndef INDICATORS_BLOCK_PROGRESS_BAR
2303 #define INDICATORS_BLOCK_PROGRESS_BAR
2304 
2305 // #include <indicators/color.hpp>
2306 // #include <indicators/details/stream_helper.hpp>
2307 
2308 #include <algorithm>
2309 #include <atomic>
2310 #include <chrono>
2311 // #include <indicators/setting.hpp>
2312 // #include <indicators/terminal_size.hpp>
2313 #include <iomanip>
2314 #include <iostream>
2315 #include <sstream>
2316 #include <mutex>
2317 #include <string>
2318 #include <thread>
2319 #include <tuple>
2320 #include <utility>
2321 
2322 namespace indicators {
2323 
2324 class BlockProgressBar {
2325  using Settings = std::tuple<option::ForegroundColor, option::BarWidth, option::Start, option::End,
2326  option::PrefixText, option::PostfixText, option::ShowPercentage,
2327  option::ShowElapsedTime, option::ShowRemainingTime, option::Completed,
2328  option::SavedStartTime, option::MaxPostfixTextLen, option::FontStyles,
2329  option::MaxProgress, option::Stream>;
2330 
2331 public:
2332  template <typename... Args,
2333  typename std::enable_if<details::are_settings_from_tuple<
2334  Settings, typename std::decay<Args>::type...>::value,
2335  void *>::type = nullptr>
2336  explicit BlockProgressBar(Args &&... args)
2337  : settings_(details::get<details::ProgressBarOption::foreground_color>(
2338  option::ForegroundColor{Color::unspecified}, std::forward<Args>(args)...),
2339  details::get<details::ProgressBarOption::bar_width>(option::BarWidth{100},
2340  std::forward<Args>(args)...),
2341  details::get<details::ProgressBarOption::start>(option::Start{"["},
2342  std::forward<Args>(args)...),
2343  details::get<details::ProgressBarOption::end>(option::End{"]"},
2344  std::forward<Args>(args)...),
2345  details::get<details::ProgressBarOption::prefix_text>(
2346  option::PrefixText{""}, std::forward<Args>(args)...),
2347  details::get<details::ProgressBarOption::postfix_text>(
2348  option::PostfixText{""}, std::forward<Args>(args)...),
2349  details::get<details::ProgressBarOption::show_percentage>(
2350  option::ShowPercentage{true}, std::forward<Args>(args)...),
2351  details::get<details::ProgressBarOption::show_elapsed_time>(
2352  option::ShowElapsedTime{false}, std::forward<Args>(args)...),
2353  details::get<details::ProgressBarOption::show_remaining_time>(
2354  option::ShowRemainingTime{false}, std::forward<Args>(args)...),
2355  details::get<details::ProgressBarOption::completed>(option::Completed{false},
2356  std::forward<Args>(args)...),
2357  details::get<details::ProgressBarOption::saved_start_time>(
2358  option::SavedStartTime{false}, std::forward<Args>(args)...),
2359  details::get<details::ProgressBarOption::max_postfix_text_len>(
2360  option::MaxPostfixTextLen{0}, std::forward<Args>(args)...),
2361  details::get<details::ProgressBarOption::font_styles>(
2362  option::FontStyles{std::vector<FontStyle>{}}, std::forward<Args>(args)...),
2363  details::get<details::ProgressBarOption::max_progress>(
2364  option::MaxProgress{100}, std::forward<Args>(args)...),
2365  details::get<details::ProgressBarOption::stream>(option::Stream{std::cout},
2366  std::forward<Args>(args)...)) {}
2367 
2368  template <typename T, details::ProgressBarOption id>
2369  void set_option(details::Setting<T, id> &&setting) {
2370  static_assert(!std::is_same<T, typename std::decay<decltype(details::get_value<id>(
2371  std::declval<Settings>()))>::type>::value,
2372  "Setting has wrong type!");
2373  std::lock_guard<std::mutex> lock(mutex_);
2374  get_value<id>() = std::move(setting).value;
2375  }
2376 
2377  template <typename T, details::ProgressBarOption id>
2378  void set_option(const details::Setting<T, id> &setting) {
2379  static_assert(!std::is_same<T, typename std::decay<decltype(details::get_value<id>(
2380  std::declval<Settings>()))>::type>::value,
2381  "Setting has wrong type!");
2382  std::lock_guard<std::mutex> lock(mutex_);
2383  get_value<id>() = setting.value;
2384  }
2385 
2386  void set_option(
2387  const details::Setting<std::string, details::ProgressBarOption::postfix_text> &setting) {
2388  std::lock_guard<std::mutex> lock(mutex_);
2389  get_value<details::ProgressBarOption::postfix_text>() = setting.value;
2390  if (setting.value.length() > get_value<details::ProgressBarOption::max_postfix_text_len>()) {
2391  get_value<details::ProgressBarOption::max_postfix_text_len>() = setting.value.length();
2392  }
2393  }
2394 
2395  void
2396  set_option(details::Setting<std::string, details::ProgressBarOption::postfix_text> &&setting) {
2397  std::lock_guard<std::mutex> lock(mutex_);
2398  get_value<details::ProgressBarOption::postfix_text>() = std::move(setting).value;
2399  auto &new_value = get_value<details::ProgressBarOption::postfix_text>();
2400  if (new_value.length() > get_value<details::ProgressBarOption::max_postfix_text_len>()) {
2401  get_value<details::ProgressBarOption::max_postfix_text_len>() = new_value.length();
2402  }
2403  }
2404 
2405  void set_progress(float value) {
2406  {
2407  std::lock_guard<std::mutex> lock{mutex_};
2408  progress_ = value;
2409  }
2410  save_start_time();
2411  print_progress();
2412  }
2413 
2414  void tick() {
2415  {
2416  std::lock_guard<std::mutex> lock{mutex_};
2417  progress_ += 1;
2418  }
2419  save_start_time();
2420  print_progress();
2421  }
2422 
2423  size_t current() {
2424  std::lock_guard<std::mutex> lock{mutex_};
2425  return (std::min)(static_cast<size_t>(progress_),
2426  size_t(get_value<details::ProgressBarOption::max_progress>()));
2427  }
2428 
2429  bool is_completed() const { return get_value<details::ProgressBarOption::completed>(); }
2430 
2431  void mark_as_completed() {
2432  get_value<details::ProgressBarOption::completed>() = true;
2433  print_progress();
2434  }
2435 
2436 private:
2437  template <details::ProgressBarOption id>
2438  auto get_value() -> decltype((details::get_value<id>(std::declval<Settings &>()).value)) {
2439  return details::get_value<id>(settings_).value;
2440  }
2441 
2442  template <details::ProgressBarOption id>
2443  auto get_value() const
2444  -> decltype((details::get_value<id>(std::declval<const Settings &>()).value)) {
2445  return details::get_value<id>(settings_).value;
2446  }
2447 
2448  Settings settings_;
2449  float progress_{0.0};
2450  std::chrono::time_point<std::chrono::high_resolution_clock> start_time_point_;
2451  std::mutex mutex_;
2452 
2453  template <typename Indicator, size_t count> friend class MultiProgress;
2454  template <typename Indicator> friend class DynamicProgress;
2455  std::atomic<bool> multi_progress_mode_{false};
2456 
2457  void save_start_time() {
2458  auto &show_elapsed_time = get_value<details::ProgressBarOption::show_elapsed_time>();
2459  auto &saved_start_time = get_value<details::ProgressBarOption::saved_start_time>();
2460  auto &show_remaining_time = get_value<details::ProgressBarOption::show_remaining_time>();
2461  if ((show_elapsed_time || show_remaining_time) && !saved_start_time) {
2462  start_time_point_ = std::chrono::high_resolution_clock::now();
2463  saved_start_time = true;
2464  }
2465  }
2466 
2467  std::pair<std::string, int> get_prefix_text() {
2468  std::stringstream os;
2469  os << get_value<details::ProgressBarOption::prefix_text>();
2470  const auto result = os.str();
2471  const auto result_size = unicode::display_width(result);
2472  return {result, result_size};
2473  }
2474 
2475  std::pair<std::string, int> get_postfix_text() {
2476  std::stringstream os;
2477  const auto max_progress = get_value<details::ProgressBarOption::max_progress>();
2478  auto now = std::chrono::high_resolution_clock::now();
2479  auto elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(now - start_time_point_);
2480 
2481  if (get_value<details::ProgressBarOption::show_percentage>()) {
2482  os << " " << (std::min)(static_cast<size_t>(progress_ / max_progress * 100.0), size_t(100))
2483  << "%";
2484  }
2485 
2486  auto &saved_start_time = get_value<details::ProgressBarOption::saved_start_time>();
2487 
2488  if (get_value<details::ProgressBarOption::show_elapsed_time>()) {
2489  os << " [";
2490  if (saved_start_time)
2491  details::write_duration(os, elapsed);
2492  else
2493  os << "00:00s";
2494  }
2495 
2496  if (get_value<details::ProgressBarOption::show_remaining_time>()) {
2497  if (get_value<details::ProgressBarOption::show_elapsed_time>())
2498  os << "<";
2499  else
2500  os << " [";
2501 
2502  if (saved_start_time) {
2503  auto eta = std::chrono::nanoseconds(
2504  progress_ > 0
2505  ? static_cast<long long>(std::ceil(float(elapsed.count()) *
2506  max_progress / progress_))
2507  : 0);
2508  auto remaining = eta > elapsed ? (eta - elapsed) : (elapsed - eta);
2509  details::write_duration(os, remaining);
2510  } else {
2511  os << "00:00s";
2512  }
2513 
2514  os << "]";
2515  } else {
2516  if (get_value<details::ProgressBarOption::show_elapsed_time>())
2517  os << "]";
2518  }
2519 
2520  os << " " << get_value<details::ProgressBarOption::postfix_text>();
2521 
2522  const auto result = os.str();
2523  const auto result_size = unicode::display_width(result);
2524  return {result, result_size};
2525  }
2526 
2527 public:
2528  void print_progress(bool from_multi_progress = false) {
2529  std::lock_guard<std::mutex> lock{mutex_};
2530 
2531  auto &os = get_value<details::ProgressBarOption::stream>();
2532 
2533  const auto max_progress = get_value<details::ProgressBarOption::max_progress>();
2534  if (multi_progress_mode_ && !from_multi_progress) {
2535  if (progress_ > max_progress) {
2536  get_value<details::ProgressBarOption::completed>() = true;
2537  }
2538  return;
2539  }
2540 
2541  if (get_value<details::ProgressBarOption::foreground_color>() != Color::unspecified)
2542  details::set_stream_color(os, get_value<details::ProgressBarOption::foreground_color>());
2543 
2544  for (auto &style : get_value<details::ProgressBarOption::font_styles>())
2545  details::set_font_style(os, style);
2546 
2547  const auto prefix_pair = get_prefix_text();
2548  const auto prefix_text = prefix_pair.first;
2549  const auto prefix_length = prefix_pair.second;
2550  os << "\r" << prefix_text;
2551 
2552  os << get_value<details::ProgressBarOption::start>();
2553 
2554  details::BlockProgressScaleWriter writer{os,
2555  get_value<details::ProgressBarOption::bar_width>()};
2556  writer.write(progress_ / max_progress * 100);
2557 
2558  os << get_value<details::ProgressBarOption::end>();
2559 
2560  const auto postfix_pair = get_postfix_text();
2561  const auto postfix_text = postfix_pair.first;
2562  const auto postfix_length = postfix_pair.second;
2563  os << postfix_text;
2564 
2565  // Get length of prefix text and postfix text
2566  const auto start_length = get_value<details::ProgressBarOption::start>().size();
2567  const auto bar_width = get_value<details::ProgressBarOption::bar_width>();
2568  const auto end_length = get_value<details::ProgressBarOption::end>().size();
2569  const auto terminal_width = terminal_size().second;
2570  // prefix + bar_width + postfix should be <= terminal_width
2571  const int remaining = terminal_width - (prefix_length + start_length + bar_width + end_length + postfix_length);
2572  if (prefix_length == -1 || postfix_length == -1) {
2573  os << "\r";
2574  } else if (remaining > 0) {
2575  os << std::string(remaining, ' ') << "\r";
2576  } else if (remaining < 0) {
2577  // Do nothing. Maybe in the future truncate postfix with ...
2578  }
2579  os.flush();
2580 
2581  if (progress_ > max_progress) {
2582  get_value<details::ProgressBarOption::completed>() = true;
2583  }
2584  if (get_value<details::ProgressBarOption::completed>() &&
2585  !from_multi_progress) // Don't std::endl if calling from MultiProgress
2586  os << termcolor::reset << std::endl;
2587  }
2588 };
2589 
2590 } // namespace indicators
2591 
2592 #endif
2593 
2594 
2595 #ifndef INDICATORS_INDETERMINATE_PROGRESS_BAR
2596 #define INDICATORS_INDETERMINATE_PROGRESS_BAR
2597 
2598 // #include <indicators/details/stream_helper.hpp>
2599 
2600 #include <algorithm>
2601 #include <atomic>
2602 #include <chrono>
2603 #include <cmath>
2604 // #include <indicators/color.hpp>
2605 // #include <indicators/setting.hpp>
2606 // #include <indicators/terminal_size.hpp>
2607 #include <iomanip>
2608 #include <iostream>
2609 #include <mutex>
2610 #include <string>
2611 #include <thread>
2612 #include <tuple>
2613 #include <type_traits>
2614 #include <sstream>
2615 #include <utility>
2616 
2617 namespace indicators {
2618 
2619 class IndeterminateProgressBar {
2620  using Settings =
2621  std::tuple<option::BarWidth, option::PrefixText, option::PostfixText, option::Start,
2622  option::End, option::Fill, option::Lead, option::MaxPostfixTextLen,
2623  option::Completed, option::ForegroundColor, option::FontStyles, option::Stream>;
2624 
2625  enum class Direction { forward, backward };
2626 
2627  Direction direction_{Direction::forward};
2628 
2629 public:
2630  template <typename... Args,
2631  typename std::enable_if<details::are_settings_from_tuple<
2632  Settings, typename std::decay<Args>::type...>::value,
2633  void *>::type = nullptr>
2634  explicit IndeterminateProgressBar(Args &&... args)
2635  : settings_(details::get<details::ProgressBarOption::bar_width>(option::BarWidth{100},
2636  std::forward<Args>(args)...),
2637  details::get<details::ProgressBarOption::prefix_text>(
2638  option::PrefixText{}, std::forward<Args>(args)...),
2639  details::get<details::ProgressBarOption::postfix_text>(
2640  option::PostfixText{}, std::forward<Args>(args)...),
2641  details::get<details::ProgressBarOption::start>(option::Start{"["},
2642  std::forward<Args>(args)...),
2643  details::get<details::ProgressBarOption::end>(option::End{"]"},
2644  std::forward<Args>(args)...),
2645  details::get<details::ProgressBarOption::fill>(option::Fill{"."},
2646  std::forward<Args>(args)...),
2647  details::get<details::ProgressBarOption::lead>(option::Lead{"<==>"},
2648  std::forward<Args>(args)...),
2649  details::get<details::ProgressBarOption::max_postfix_text_len>(
2650  option::MaxPostfixTextLen{0}, std::forward<Args>(args)...),
2651  details::get<details::ProgressBarOption::completed>(option::Completed{false},
2652  std::forward<Args>(args)...),
2653  details::get<details::ProgressBarOption::foreground_color>(
2654  option::ForegroundColor{Color::unspecified}, std::forward<Args>(args)...),
2655  details::get<details::ProgressBarOption::font_styles>(
2656  option::FontStyles{std::vector<FontStyle>{}}, std::forward<Args>(args)...),
2657  details::get<details::ProgressBarOption::stream>(option::Stream{std::cout},
2658  std::forward<Args>(args)...)) {
2659  // starts with [<==>...........]
2660  // progress_ = 0
2661 
2662  // ends with [...........<==>]
2663  // ^^^^^^^^^^^^^^^^^ bar_width
2664  // ^^^^^^^^^^^^ (bar_width - len(lead))
2665  // progress_ = bar_width - len(lead)
2666  progress_ = 0;
2667  max_progress_ = get_value<details::ProgressBarOption::bar_width>() -
2668  get_value<details::ProgressBarOption::lead>().size() +
2669  get_value<details::ProgressBarOption::start>().size() +
2670  get_value<details::ProgressBarOption::end>().size();
2671  }
2672 
2673  template <typename T, details::ProgressBarOption id>
2674  void set_option(details::Setting<T, id> &&setting) {
2675  static_assert(!std::is_same<T, typename std::decay<decltype(details::get_value<id>(
2676  std::declval<Settings>()))>::type>::value,
2677  "Setting has wrong type!");
2678  std::lock_guard<std::mutex> lock(mutex_);
2679  get_value<id>() = std::move(setting).value;
2680  }
2681 
2682  template <typename T, details::ProgressBarOption id>
2683  void set_option(const details::Setting<T, id> &setting) {
2684  static_assert(!std::is_same<T, typename std::decay<decltype(details::get_value<id>(
2685  std::declval<Settings>()))>::type>::value,
2686  "Setting has wrong type!");
2687  std::lock_guard<std::mutex> lock(mutex_);
2688  get_value<id>() = setting.value;
2689  }
2690 
2691  void set_option(
2692  const details::Setting<std::string, details::ProgressBarOption::postfix_text> &setting) {
2693  std::lock_guard<std::mutex> lock(mutex_);
2694  get_value<details::ProgressBarOption::postfix_text>() = setting.value;
2695  if (setting.value.length() > get_value<details::ProgressBarOption::max_postfix_text_len>()) {
2696  get_value<details::ProgressBarOption::max_postfix_text_len>() = setting.value.length();
2697  }
2698  }
2699 
2700  void
2701  set_option(details::Setting<std::string, details::ProgressBarOption::postfix_text> &&setting) {
2702  std::lock_guard<std::mutex> lock(mutex_);
2703  get_value<details::ProgressBarOption::postfix_text>() = std::move(setting).value;
2704  auto &new_value = get_value<details::ProgressBarOption::postfix_text>();
2705  if (new_value.length() > get_value<details::ProgressBarOption::max_postfix_text_len>()) {
2706  get_value<details::ProgressBarOption::max_postfix_text_len>() = new_value.length();
2707  }
2708  }
2709 
2710  void tick() {
2711  {
2712  std::lock_guard<std::mutex> lock{mutex_};
2713  if (get_value<details::ProgressBarOption::completed>())
2714  return;
2715 
2716  progress_ += (direction_ == Direction::forward) ? 1 : -1;
2717  if (direction_ == Direction::forward && progress_ == max_progress_) {
2718  // time to go back
2719  direction_ = Direction::backward;
2720  } else if (direction_ == Direction::backward && progress_ == 0) {
2721  direction_ = Direction::forward;
2722  }
2723  }
2724  print_progress();
2725  }
2726 
2727  bool is_completed() { return get_value<details::ProgressBarOption::completed>(); }
2728 
2729  void mark_as_completed() {
2730  get_value<details::ProgressBarOption::completed>() = true;
2731  print_progress();
2732  }
2733 
2734 private:
2735  template <details::ProgressBarOption id>
2736  auto get_value() -> decltype((details::get_value<id>(std::declval<Settings &>()).value)) {
2737  return details::get_value<id>(settings_).value;
2738  }
2739 
2740  template <details::ProgressBarOption id>
2741  auto get_value() const
2742  -> decltype((details::get_value<id>(std::declval<const Settings &>()).value)) {
2743  return details::get_value<id>(settings_).value;
2744  }
2745 
2746  size_t progress_{0};
2747  size_t max_progress_;
2748  Settings settings_;
2749  std::chrono::nanoseconds elapsed_;
2750  std::mutex mutex_;
2751 
2752  template <typename Indicator, size_t count> friend class MultiProgress;
2753  template <typename Indicator> friend class DynamicProgress;
2754  std::atomic<bool> multi_progress_mode_{false};
2755 
2756  std::pair<std::string, int> get_prefix_text() {
2757  std::stringstream os;
2758  os << get_value<details::ProgressBarOption::prefix_text>();
2759  const auto result = os.str();
2760  const auto result_size = unicode::display_width(result);
2761  return {result, result_size};
2762  }
2763 
2764  std::pair<std::string, int> get_postfix_text() {
2765  std::stringstream os;
2766  os << " " << get_value<details::ProgressBarOption::postfix_text>();
2767 
2768  const auto result = os.str();
2769  const auto result_size = unicode::display_width(result);
2770  return {result, result_size};
2771  }
2772 
2773 public:
2774  void print_progress(bool from_multi_progress = false) {
2775  std::lock_guard<std::mutex> lock{mutex_};
2776 
2777  auto &os = get_value<details::ProgressBarOption::stream>();
2778 
2779  if (multi_progress_mode_ && !from_multi_progress) {
2780  return;
2781  }
2782  if (get_value<details::ProgressBarOption::foreground_color>() != Color::unspecified)
2783  details::set_stream_color(os, get_value<details::ProgressBarOption::foreground_color>());
2784 
2785  for (auto &style : get_value<details::ProgressBarOption::font_styles>())
2786  details::set_font_style(os, style);
2787 
2788  const auto prefix_pair = get_prefix_text();
2789  const auto prefix_text = prefix_pair.first;
2790  const auto prefix_length = prefix_pair.second;
2791  os << "\r" << prefix_text;
2792 
2793  os << get_value<details::ProgressBarOption::start>();
2794 
2795  details::IndeterminateProgressScaleWriter writer{
2796  os, get_value<details::ProgressBarOption::bar_width>(),
2797  get_value<details::ProgressBarOption::fill>(),
2798  get_value<details::ProgressBarOption::lead>()};
2799  writer.write(progress_);
2800 
2801  os << get_value<details::ProgressBarOption::end>();
2802 
2803  const auto postfix_pair = get_postfix_text();
2804  const auto postfix_text = postfix_pair.first;
2805  const auto postfix_length = postfix_pair.second;
2806  os << postfix_text;
2807 
2808  // Get length of prefix text and postfix text
2809  const auto start_length = get_value<details::ProgressBarOption::start>().size();
2810  const auto bar_width = get_value<details::ProgressBarOption::bar_width>();
2811  const auto end_length = get_value<details::ProgressBarOption::end>().size();
2812  const auto terminal_width = terminal_size().second;
2813  // prefix + bar_width + postfix should be <= terminal_width
2814  const int remaining = terminal_width - (prefix_length + start_length + bar_width + end_length + postfix_length);
2815  if (prefix_length == -1 || postfix_length == -1) {
2816  os << "\r";
2817  } else if (remaining > 0) {
2818  os << std::string(remaining, ' ') << "\r";
2819  } else if (remaining < 0) {
2820  // Do nothing. Maybe in the future truncate postfix with ...
2821  }
2822  os.flush();
2823 
2824  if (get_value<details::ProgressBarOption::completed>() &&
2825  !from_multi_progress) // Don't std::endl if calling from MultiProgress
2826  os << termcolor::reset << std::endl;
2827  }
2828 };
2829 
2830 } // namespace indicators
2831 
2832 #endif
2833 
2834 
2835 #ifndef INDICATORS_MULTI_PROGRESS
2836 #define INDICATORS_MULTI_PROGRESS
2837 #include <atomic>
2838 #include <functional>
2839 #include <iostream>
2840 #include <mutex>
2841 #include <vector>
2842 
2843 // #include <indicators/color.hpp>
2844 // #include <indicators/cursor_movement.hpp>
2845 // #include <indicators/details/stream_helper.hpp>
2846 
2847 namespace indicators {
2848 
2849 template <typename Indicator, size_t count> class MultiProgress {
2850 public:
2851  template <typename... Indicators,
2852  typename = typename std::enable_if<(sizeof...(Indicators) == count)>::type>
2853  explicit MultiProgress(Indicators &... bars) {
2854  bars_ = {bars...};
2855  for (auto &bar : bars_) {
2856  bar.get().multi_progress_mode_ = true;
2857  }
2858  }
2859 
2860  template <size_t index>
2861  typename std::enable_if<(index >= 0 && index < count), void>::type set_progress(size_t value) {
2862  if (!bars_[index].get().is_completed())
2863  bars_[index].get().set_progress(value);
2864  print_progress();
2865  }
2866 
2867  template <size_t index>
2868  typename std::enable_if<(index >= 0 && index < count), void>::type set_progress(float value) {
2869  if (!bars_[index].get().is_completed())
2870  bars_[index].get().set_progress(value);
2871  print_progress();
2872  }
2873 
2874  template <size_t index>
2875  typename std::enable_if<(index >= 0 && index < count), void>::type tick() {
2876  if (!bars_[index].get().is_completed())
2877  bars_[index].get().tick();
2878  print_progress();
2879  }
2880 
2881  template <size_t index>
2882  typename std::enable_if<(index >= 0 && index < count), bool>::type is_completed() const {
2883  return bars_[index].get().is_completed();
2884  }
2885 
2886 private:
2887  std::atomic<bool> started_{false};
2888  std::mutex mutex_;
2889  std::vector<std::reference_wrapper<Indicator>> bars_;
2890 
2891  bool _all_completed() {
2892  bool result{true};
2893  for (size_t i = 0; i < count; ++i)
2894  result &= bars_[i].get().is_completed();
2895  return result;
2896  }
2897 
2898 public:
2899  void print_progress() {
2900  std::lock_guard<std::mutex> lock{mutex_};
2901  if (started_)
2902  move_up(count);
2903  for (auto &bar : bars_) {
2904  bar.get().print_progress(true);
2905  std::cout << "\n";
2906  }
2907  std::cout << termcolor::reset;
2908  if (!started_)
2909  started_ = true;
2910  }
2911 };
2912 
2913 } // namespace indicators
2914 
2915 #endif
2916 
2917 
2918 #ifndef INDICATORS_DYNAMIC_PROGRESS
2919 #define INDICATORS_DYNAMIC_PROGRESS
2920 
2921 #include <atomic>
2922 #include <functional>
2923 // #include <indicators/color.hpp>
2924 // #include <indicators/setting.hpp>
2925 // #include <indicators/cursor_control.hpp>
2926 // #include <indicators/cursor_movement.hpp>
2927 // #include <indicators/details/stream_helper.hpp>
2928 #include <iostream>
2929 #include <mutex>
2930 #include <vector>
2931 
2932 namespace indicators {
2933 
2934 template <typename Indicator> class DynamicProgress {
2935  using Settings = std::tuple<option::HideBarWhenComplete>;
2936 
2937 public:
2938  template <typename... Indicators> explicit DynamicProgress(Indicators &... bars) {
2939  bars_ = {bars...};
2940  for (auto &bar : bars_) {
2941  bar.get().multi_progress_mode_ = true;
2942  ++total_count_;
2943  ++incomplete_count_;
2944  }
2945  }
2946 
2947  Indicator &operator[](size_t index) {
2948  print_progress();
2949  std::lock_guard<std::mutex> lock{mutex_};
2950  return bars_[index].get();
2951  }
2952 
2953  size_t push_back(Indicator &bar) {
2954  std::lock_guard<std::mutex> lock{mutex_};
2955  bar.multi_progress_mode_ = true;
2956  bars_.push_back(bar);
2957  return bars_.size() - 1;
2958  }
2959 
2960  template <typename T, details::ProgressBarOption id>
2961  void set_option(details::Setting<T, id> &&setting) {
2962  static_assert(!std::is_same<T, typename std::decay<decltype(details::get_value<id>(
2963  std::declval<Settings>()))>::type>::value,
2964  "Setting has wrong type!");
2965  std::lock_guard<std::mutex> lock(mutex_);
2966  get_value<id>() = std::move(setting).value;
2967  }
2968 
2969  template <typename T, details::ProgressBarOption id>
2970  void set_option(const details::Setting<T, id> &setting) {
2971  static_assert(!std::is_same<T, typename std::decay<decltype(details::get_value<id>(
2972  std::declval<Settings>()))>::type>::value,
2973  "Setting has wrong type!");
2974  std::lock_guard<std::mutex> lock(mutex_);
2975  get_value<id>() = setting.value;
2976  }
2977 
2978 private:
2979  Settings settings_;
2980  std::atomic<bool> started_{false};
2981  std::mutex mutex_;
2982  std::vector<std::reference_wrapper<Indicator>> bars_;
2983  std::atomic<size_t> total_count_{0};
2984  std::atomic<size_t> incomplete_count_{0};
2985 
2986  template <details::ProgressBarOption id>
2987  auto get_value() -> decltype((details::get_value<id>(std::declval<Settings &>()).value)) {
2988  return details::get_value<id>(settings_).value;
2989  }
2990 
2991  template <details::ProgressBarOption id>
2992  auto get_value() const
2993  -> decltype((details::get_value<id>(std::declval<const Settings &>()).value)) {
2994  return details::get_value<id>(settings_).value;
2995  }
2996 
2997 public:
2998  void print_progress() {
2999  std::lock_guard<std::mutex> lock{mutex_};
3000  auto &hide_bar_when_complete = get_value<details::ProgressBarOption::hide_bar_when_complete>();
3001  if (hide_bar_when_complete) {
3002  // Hide completed bars
3003  if (started_) {
3004  for (size_t i = 0; i < incomplete_count_; ++i) {
3005  move_up(1);
3006  erase_line();
3007  std::cout << std::flush;
3008  }
3009  }
3010  incomplete_count_ = 0;
3011  for (auto &bar : bars_) {
3012  if (!bar.get().is_completed()) {
3013  bar.get().print_progress(true);
3014  std::cout << "\n";
3015  ++incomplete_count_;
3016  }
3017  }
3018  if (!started_)
3019  started_ = true;
3020  } else {
3021  // Don't hide any bars
3022  if (started_)
3023  move_up(static_cast<int>(total_count_));
3024  for (auto &bar : bars_) {
3025  bar.get().print_progress(true);
3026  std::cout << "\n";
3027  }
3028  if (!started_)
3029  started_ = true;
3030  }
3031  total_count_ = bars_.size();
3032  std::cout << termcolor::reset;
3033  }
3034 };
3035 
3036 } // namespace indicators
3037 
3038 #endif
3039 
3040 
3041 #ifndef INDICATORS_PROGRESS_SPINNER
3042 #define INDICATORS_PROGRESS_SPINNER
3043 
3044 // #include <indicators/details/stream_helper.hpp>
3045 
3046 #include <algorithm>
3047 #include <atomic>
3048 #include <chrono>
3049 #include <cmath>
3050 // #include <indicators/color.hpp>
3051 // #include <indicators/setting.hpp>
3052 #include <iomanip>
3053 #include <iostream>
3054 #include <mutex>
3055 #include <string>
3056 #include <thread>
3057 #include <tuple>
3058 #include <vector>
3059 
3060 namespace indicators {
3061 
3062 class ProgressSpinner {
3063  using Settings =
3064  std::tuple<option::ForegroundColor, option::PrefixText, option::PostfixText,
3065  option::ShowPercentage, option::ShowElapsedTime, option::ShowRemainingTime,
3066  option::ShowSpinner, option::SavedStartTime, option::Completed,
3067  option::MaxPostfixTextLen, option::SpinnerStates, option::FontStyles,
3068  option::MaxProgress, option::Stream>;
3069 
3070 public:
3071  template <typename... Args,
3072  typename std::enable_if<details::are_settings_from_tuple<
3073  Settings, typename std::decay<Args>::type...>::value,
3074  void *>::type = nullptr>
3075  explicit ProgressSpinner(Args &&... args)
3076  : settings_(
3077  details::get<details::ProgressBarOption::foreground_color>(
3078  option::ForegroundColor{Color::unspecified}, std::forward<Args>(args)...),
3079  details::get<details::ProgressBarOption::prefix_text>(option::PrefixText{},
3080  std::forward<Args>(args)...),
3081  details::get<details::ProgressBarOption::postfix_text>(option::PostfixText{},
3082  std::forward<Args>(args)...),
3083  details::get<details::ProgressBarOption::show_percentage>(option::ShowPercentage{true},
3084  std::forward<Args>(args)...),
3085  details::get<details::ProgressBarOption::show_elapsed_time>(
3086  option::ShowElapsedTime{false}, std::forward<Args>(args)...),
3087  details::get<details::ProgressBarOption::show_remaining_time>(
3088  option::ShowRemainingTime{false}, std::forward<Args>(args)...),
3089  details::get<details::ProgressBarOption::spinner_show>(option::ShowSpinner{true},
3090  std::forward<Args>(args)...),
3091  details::get<details::ProgressBarOption::saved_start_time>(
3092  option::SavedStartTime{false}, std::forward<Args>(args)...),
3093  details::get<details::ProgressBarOption::completed>(option::Completed{false},
3094  std::forward<Args>(args)...),
3095  details::get<details::ProgressBarOption::max_postfix_text_len>(
3096  option::MaxPostfixTextLen{0}, std::forward<Args>(args)...),
3097  details::get<details::ProgressBarOption::spinner_states>(
3098  option::SpinnerStates{
3099  std::vector<std::string>{"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"}},
3100  std::forward<Args>(args)...),
3101  details::get<details::ProgressBarOption::font_styles>(
3102  option::FontStyles{std::vector<FontStyle>{}}, std::forward<Args>(args)...),
3103  details::get<details::ProgressBarOption::max_progress>(option::MaxProgress{100},
3104  std::forward<Args>(args)...),
3105  details::get<details::ProgressBarOption::stream>(option::Stream{std::cout},
3106  std::forward<Args>(args)...)) {}
3107 
3108  template <typename T, details::ProgressBarOption id>
3109  void set_option(details::Setting<T, id> &&setting) {
3110  static_assert(!std::is_same<T, typename std::decay<decltype(details::get_value<id>(
3111  std::declval<Settings>()))>::type>::value,
3112  "Setting has wrong type!");
3113  std::lock_guard<std::mutex> lock(mutex_);
3114  get_value<id>() = std::move(setting).value;
3115  }
3116 
3117  template <typename T, details::ProgressBarOption id>
3118  void set_option(const details::Setting<T, id> &setting) {
3119  static_assert(!std::is_same<T, typename std::decay<decltype(details::get_value<id>(
3120  std::declval<Settings>()))>::type>::value,
3121  "Setting has wrong type!");
3122  std::lock_guard<std::mutex> lock(mutex_);
3123  get_value<id>() = setting.value;
3124  }
3125 
3126  void set_option(
3127  const details::Setting<std::string, details::ProgressBarOption::postfix_text> &setting) {
3128  std::lock_guard<std::mutex> lock(mutex_);
3129  get_value<details::ProgressBarOption::postfix_text>() = setting.value;
3130  if (setting.value.length() > get_value<details::ProgressBarOption::max_postfix_text_len>()) {
3131  get_value<details::ProgressBarOption::max_postfix_text_len>() = setting.value.length();
3132  }
3133  }
3134 
3135  void
3136  set_option(details::Setting<std::string, details::ProgressBarOption::postfix_text> &&setting) {
3137  std::lock_guard<std::mutex> lock(mutex_);
3138  get_value<details::ProgressBarOption::postfix_text>() = std::move(setting).value;
3139  auto &new_value = get_value<details::ProgressBarOption::postfix_text>();
3140  if (new_value.length() > get_value<details::ProgressBarOption::max_postfix_text_len>()) {
3141  get_value<details::ProgressBarOption::max_postfix_text_len>() = new_value.length();
3142  }
3143  }
3144 
3145  void set_progress(size_t value) {
3146  {
3147  std::lock_guard<std::mutex> lock{mutex_};
3148  progress_ = value;
3149  }
3150  save_start_time();
3151  print_progress();
3152  }
3153 
3154  void tick() {
3155  {
3156  std::lock_guard<std::mutex> lock{mutex_};
3157  progress_ += 1;
3158  }
3159  save_start_time();
3160  print_progress();
3161  }
3162 
3163  size_t current() {
3164  std::lock_guard<std::mutex> lock{mutex_};
3165  return (std::min)(progress_, size_t(get_value<details::ProgressBarOption::max_progress>()));
3166  }
3167 
3168  bool is_completed() const { return get_value<details::ProgressBarOption::completed>(); }
3169 
3170  void mark_as_completed() {
3171  get_value<details::ProgressBarOption::completed>() = true;
3172  print_progress();
3173  }
3174 
3175 private:
3176  Settings settings_;
3177  size_t progress_{0};
3178  size_t index_{0};
3179  std::chrono::time_point<std::chrono::high_resolution_clock> start_time_point_;
3180  std::mutex mutex_;
3181 
3182  template <details::ProgressBarOption id>
3183  auto get_value() -> decltype((details::get_value<id>(std::declval<Settings &>()).value)) {
3184  return details::get_value<id>(settings_).value;
3185  }
3186 
3187  template <details::ProgressBarOption id>
3188  auto get_value() const
3189  -> decltype((details::get_value<id>(std::declval<const Settings &>()).value)) {
3190  return details::get_value<id>(settings_).value;
3191  }
3192 
3193  void save_start_time() {
3194  auto &show_elapsed_time = get_value<details::ProgressBarOption::show_elapsed_time>();
3195  auto &show_remaining_time = get_value<details::ProgressBarOption::show_remaining_time>();
3196  auto &saved_start_time = get_value<details::ProgressBarOption::saved_start_time>();
3197  if ((show_elapsed_time || show_remaining_time) && !saved_start_time) {
3198  start_time_point_ = std::chrono::high_resolution_clock::now();
3199  saved_start_time = true;
3200  }
3201  }
3202 
3203 public:
3204  void print_progress() {
3205  std::lock_guard<std::mutex> lock{mutex_};
3206 
3207  auto &os = get_value<details::ProgressBarOption::stream>();
3208 
3209  const auto max_progress = get_value<details::ProgressBarOption::max_progress>();
3210  auto now = std::chrono::high_resolution_clock::now();
3211  auto elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(now - start_time_point_);
3212 
3213  if (get_value<details::ProgressBarOption::foreground_color>() != Color::unspecified)
3214  details::set_stream_color(os, get_value<details::ProgressBarOption::foreground_color>());
3215 
3216  for (auto &style : get_value<details::ProgressBarOption::font_styles>())
3217  details::set_font_style(os, style);
3218 
3219  os << get_value<details::ProgressBarOption::prefix_text>();
3220  if (get_value<details::ProgressBarOption::spinner_show>())
3221  os << get_value<details::ProgressBarOption::spinner_states>()
3222  [index_ % get_value<details::ProgressBarOption::spinner_states>().size()];
3223  if (get_value<details::ProgressBarOption::show_percentage>()) {
3224  os << " " << std::size_t(progress_ / double(max_progress) * 100) << "%";
3225  }
3226 
3227  if (get_value<details::ProgressBarOption::show_elapsed_time>()) {
3228  os << " [";
3229  details::write_duration(os, elapsed);
3230  }
3231 
3232  if (get_value<details::ProgressBarOption::show_remaining_time>()) {
3233  if (get_value<details::ProgressBarOption::show_elapsed_time>())
3234  os << "<";
3235  else
3236  os << " [";
3237  auto eta = std::chrono::nanoseconds(
3238  progress_ > 0
3239  ? static_cast<long long>(std::ceil(float(elapsed.count()) *
3240  max_progress / progress_))
3241  : 0);
3242  auto remaining = eta > elapsed ? (eta - elapsed) : (elapsed - eta);
3243  details::write_duration(os, remaining);
3244  os << "]";
3245  } else {
3246  if (get_value<details::ProgressBarOption::show_elapsed_time>())
3247  os << "]";
3248  }
3249 
3250  if (get_value<details::ProgressBarOption::max_postfix_text_len>() == 0)
3251  get_value<details::ProgressBarOption::max_postfix_text_len>() = 10;
3252  os << " " << get_value<details::ProgressBarOption::postfix_text>()
3253  << std::string(get_value<details::ProgressBarOption::max_postfix_text_len>(), ' ') << "\r";
3254  os.flush();
3255  index_ += 1;
3256  if (progress_ > max_progress) {
3257  get_value<details::ProgressBarOption::completed>() = true;
3258  }
3259  if (get_value<details::ProgressBarOption::completed>())
3260  os << termcolor::reset << std::endl;
3261  }
3262 };
3263 
3264 } // namespace indicators
3265 
3266 #endif