1
2 #ifndef INDICATORS_STREAM_HELPER
3 #define INDICATORS_STREAM_HELPER
4
5 #include <indicators/display_width.hpp>
6 #include <indicators/setting.hpp>
7 #include <indicators/termcolor.hpp>
8
9 #include <algorithm>
10 #include <chrono>
11 #include <iomanip>
12 #include <ostream>
13 #include <string>
14 #include <vector>
15
16 #include <cassert>
17 #include <cmath>
18
19 namespace indicators {
20 namespace details {
21
set_stream_color(std::ostream & os,Color color)22 inline void set_stream_color(std::ostream &os, Color color) {
23 switch (color) {
24 case Color::grey:
25 os << termcolor::grey;
26 break;
27 case Color::red:
28 os << termcolor::red;
29 break;
30 case Color::green:
31 os << termcolor::green;
32 break;
33 case Color::yellow:
34 os << termcolor::yellow;
35 break;
36 case Color::blue:
37 os << termcolor::blue;
38 break;
39 case Color::magenta:
40 os << termcolor::magenta;
41 break;
42 case Color::cyan:
43 os << termcolor::cyan;
44 break;
45 case Color::white:
46 os << termcolor::white;
47 break;
48 default:
49 assert(false);
50 }
51 }
52
set_font_style(std::ostream & os,FontStyle style)53 inline void set_font_style(std::ostream &os, FontStyle style) {
54 switch (style) {
55 case FontStyle::bold:
56 os << termcolor::bold;
57 break;
58 case FontStyle::dark:
59 os << termcolor::dark;
60 break;
61 case FontStyle::italic:
62 os << termcolor::italic;
63 break;
64 case FontStyle::underline:
65 os << termcolor::underline;
66 break;
67 case FontStyle::blink:
68 os << termcolor::blink;
69 break;
70 case FontStyle::reverse:
71 os << termcolor::reverse;
72 break;
73 case FontStyle::concealed:
74 os << termcolor::concealed;
75 break;
76 case FontStyle::crossed:
77 os << termcolor::crossed;
78 break;
79 default:
80 break;
81 }
82 }
83
write_duration(std::ostream & os,std::chrono::nanoseconds ns)84 inline std::ostream &write_duration(std::ostream &os, std::chrono::nanoseconds ns) {
85 using namespace std;
86 using namespace std::chrono;
87 using days = duration<int, ratio<86400>>;
88 char fill = os.fill();
89 os.fill('0');
90 auto d = duration_cast<days>(ns);
91 ns -= d;
92 auto h = duration_cast<hours>(ns);
93 ns -= h;
94 auto m = duration_cast<minutes>(ns);
95 ns -= m;
96 auto s = duration_cast<seconds>(ns);
97 if (d.count() > 0)
98 os << setw(2) << d.count() << "d:";
99 if (h.count() > 0)
100 os << setw(2) << h.count() << "h:";
101 os << setw(2) << m.count() << "m:" << setw(2) << s.count() << 's';
102 os.fill(fill);
103 return os;
104 }
105
106 class BlockProgressScaleWriter {
107 public:
BlockProgressScaleWriter(std::ostream & os,size_t bar_width)108 BlockProgressScaleWriter(std::ostream &os, size_t bar_width) : os(os), bar_width(bar_width) {}
109
write(float progress)110 std::ostream &write(float progress) {
111 std::string fill_text{"█"};
112 std::vector<std::string> lead_characters{" ", "▏", "▎", "▍", "▌", "▋", "▊", "▉"};
113 auto value = std::min(1.0f, std::max(0.0f, progress / 100.0f));
114 auto whole_width = std::floor(value * bar_width);
115 auto remainder_width = fmod((value * bar_width), 1.0f);
116 auto part_width = std::floor(remainder_width * lead_characters.size());
117 std::string lead_text = lead_characters[size_t(part_width)];
118 if ((bar_width - whole_width - 1) < 0)
119 lead_text = "";
120 for (size_t i = 0; i < whole_width; ++i)
121 os << fill_text;
122 os << lead_text;
123 for (size_t i = 0; i < (bar_width - whole_width - 1); ++i)
124 os << " ";
125 return os;
126 }
127
128 private:
129 std::ostream &os;
130 size_t bar_width = 0;
131 };
132
133 class ProgressScaleWriter {
134 public:
ProgressScaleWriter(std::ostream & os,size_t bar_width,const std::string & fill,const std::string & lead,const std::string & remainder)135 ProgressScaleWriter(std::ostream &os, size_t bar_width, const std::string &fill,
136 const std::string &lead, const std::string &remainder)
137 : os(os), bar_width(bar_width), fill(fill), lead(lead), remainder(remainder) {}
138
write(float progress)139 std::ostream &write(float progress) {
140 auto pos = static_cast<size_t>(progress * bar_width / 100.0);
141 for (size_t i = 0, current_display_width = 0; i < bar_width;) {
142 std::string next;
143
144 if (i < pos) {
145 next = fill;
146 current_display_width = unicode::display_width(fill);
147 } else if (i == pos) {
148 next = lead;
149 current_display_width = unicode::display_width(lead);
150 } else {
151 next = remainder;
152 current_display_width = unicode::display_width(remainder);
153 }
154
155 i += current_display_width;
156
157 if (i > bar_width) {
158 // `next` is larger than the allowed bar width
159 // fill with empty space instead
160 os << std::string((bar_width - (i - current_display_width)), ' ');
161 break;
162 }
163
164 os << next;
165 }
166 return os;
167 }
168
169 private:
170 std::ostream &os;
171 size_t bar_width = 0;
172 std::string fill;
173 std::string lead;
174 std::string remainder;
175 };
176
177 class IndeterminateProgressScaleWriter {
178 public:
IndeterminateProgressScaleWriter(std::ostream & os,size_t bar_width,const std::string & fill,const std::string & lead)179 IndeterminateProgressScaleWriter(std::ostream &os, size_t bar_width, const std::string &fill,
180 const std::string &lead)
181 : os(os), bar_width(bar_width), fill(fill), lead(lead) {}
182
write(size_t progress)183 std::ostream &write(size_t progress) {
184 for (size_t i = 0; i < bar_width;) {
185 std::string next;
186 size_t current_display_width = 0;
187
188 if (i < progress) {
189 next = fill;
190 current_display_width = unicode::display_width(fill);
191 } else if (i == progress) {
192 next = lead;
193 current_display_width = unicode::display_width(lead);
194 } else {
195 next = fill;
196 current_display_width = unicode::display_width(fill);
197 }
198
199 i += current_display_width;
200
201 if (i > bar_width) {
202 // `next` is larger than the allowed bar width
203 // fill with empty space instead
204 os << std::string((bar_width - (i - current_display_width)), ' ');
205 break;
206 }
207
208 os << next;
209 }
210 return os;
211 }
212
213 private:
214 std::ostream &os;
215 size_t bar_width = 0;
216 std::string fill;
217 std::string lead;
218 };
219
220 } // namespace details
221 } // namespace indicators
222
223 #endif