progress_bar_none_overload_3000 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +20 -0
- data/README.md +250 -0
- data/lib/cockpit3000.rb +1 -0
- data/lib/progressbarnone.rb +1 -0
- data/lib/progress/360/237/246/253bar/360/237/246/253none/ansi/360/237/246/253.rb +426 -0
- data/lib/progress/360/237/246/253bar/360/237/246/253none/bar/360/237/246/253.rb +234 -0
- data/lib/progress/360/237/246/253bar/360/237/246/253none/download_thread_state/360/237/246/253.rb +249 -0
- data/lib/progress/360/237/246/253bar/360/237/246/253none/enumerable_extension/360/237/246/253.rb +115 -0
- data/lib/progress/360/237/246/253bar/360/237/246/253none/frames/360/237/246/253.rb +224 -0
- data/lib/progress/360/237/246/253bar/360/237/246/253none/gantt/360/237/246/253.rb +356 -0
- data/lib/progress/360/237/246/253bar/360/237/246/253none/graphics/360/237/246/253.rb +315 -0
- data/lib/progress/360/237/246/253bar/360/237/246/253none/metrics/360/237/246/253.rb +150 -0
- data/lib/progress/360/237/246/253bar/360/237/246/253none/multi_bar/360/237/246/253.rb +379 -0
- data/lib/progress/360/237/246/253bar/360/237/246/253none/progressbar_compat/360/237/246/253.rb +132 -0
- data/lib/progress/360/237/246/253bar/360/237/246/253none/renderer/360/237/246/253.rb +473 -0
- data/lib/progress/360/237/246/253bar/360/237/246/253none/sparkline/360/237/246/253.rb +158 -0
- data/lib/progress/360/237/246/253bar/360/237/246/253none/version/360/237/246/253.rb +5 -0
- data/lib/progress/360/237/246/253bar/360/237/246/253none.rb +108 -0
- metadata +139 -0
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ProgressBarNone
|
|
4
|
+
# ANSI escape codes for colors, cursor control, and styling
|
|
5
|
+
module ANSI
|
|
6
|
+
# Escape sequence prefix
|
|
7
|
+
ESC = "\e["
|
|
8
|
+
|
|
9
|
+
# Cursor control
|
|
10
|
+
HIDE_CURSOR = "#{ESC}?25l"
|
|
11
|
+
SHOW_CURSOR = "#{ESC}?25h"
|
|
12
|
+
SAVE_CURSOR = "\e7"
|
|
13
|
+
RESTORE_CURSOR = "\e8"
|
|
14
|
+
CLEAR_LINE = "#{ESC}2K"
|
|
15
|
+
CLEAR_TO_END = "#{ESC}0K"
|
|
16
|
+
|
|
17
|
+
# Text styles
|
|
18
|
+
RESET = "#{ESC}0m"
|
|
19
|
+
BOLD = "#{ESC}1m"
|
|
20
|
+
DIM = "#{ESC}2m"
|
|
21
|
+
ITALIC = "#{ESC}3m"
|
|
22
|
+
UNDERLINE = "#{ESC}4m"
|
|
23
|
+
BLINK = "#{ESC}5m"
|
|
24
|
+
REVERSE = "#{ESC}7m"
|
|
25
|
+
|
|
26
|
+
# Standard colors (foreground)
|
|
27
|
+
BLACK = "#{ESC}30m"
|
|
28
|
+
RED = "#{ESC}31m"
|
|
29
|
+
GREEN = "#{ESC}32m"
|
|
30
|
+
YELLOW = "#{ESC}33m"
|
|
31
|
+
BLUE = "#{ESC}34m"
|
|
32
|
+
MAGENTA = "#{ESC}35m"
|
|
33
|
+
CYAN = "#{ESC}36m"
|
|
34
|
+
WHITE = "#{ESC}37m"
|
|
35
|
+
|
|
36
|
+
# Bright colors
|
|
37
|
+
BRIGHT_BLACK = "#{ESC}90m"
|
|
38
|
+
BRIGHT_RED = "#{ESC}91m"
|
|
39
|
+
BRIGHT_GREEN = "#{ESC}92m"
|
|
40
|
+
BRIGHT_YELLOW = "#{ESC}93m"
|
|
41
|
+
BRIGHT_BLUE = "#{ESC}94m"
|
|
42
|
+
BRIGHT_MAGENTA = "#{ESC}95m"
|
|
43
|
+
BRIGHT_CYAN = "#{ESC}96m"
|
|
44
|
+
BRIGHT_WHITE = "#{ESC}97m"
|
|
45
|
+
|
|
46
|
+
# Background colors
|
|
47
|
+
BG_BLACK = "#{ESC}40m"
|
|
48
|
+
BG_RED = "#{ESC}41m"
|
|
49
|
+
BG_GREEN = "#{ESC}42m"
|
|
50
|
+
BG_YELLOW = "#{ESC}43m"
|
|
51
|
+
BG_BLUE = "#{ESC}44m"
|
|
52
|
+
BG_MAGENTA = "#{ESC}45m"
|
|
53
|
+
BG_CYAN = "#{ESC}46m"
|
|
54
|
+
BG_WHITE = "#{ESC}47m"
|
|
55
|
+
|
|
56
|
+
# Crystal color palette - beautiful gradients (moved to module level)
|
|
57
|
+
CRYSTAL_PALETTE = {
|
|
58
|
+
# Cyan to purple crystal gradient
|
|
59
|
+
crystal: [
|
|
60
|
+
[80, 220, 255], # Bright cyan
|
|
61
|
+
[100, 200, 255], # Light blue
|
|
62
|
+
[130, 180, 255], # Sky blue
|
|
63
|
+
[160, 160, 255], # Periwinkle
|
|
64
|
+
[190, 140, 255], # Light purple
|
|
65
|
+
[220, 120, 255], # Bright purple
|
|
66
|
+
[255, 100, 220], # Pink
|
|
67
|
+
],
|
|
68
|
+
# Fire gradient
|
|
69
|
+
fire: [
|
|
70
|
+
[255, 80, 0], # Orange
|
|
71
|
+
[255, 120, 0], # Light orange
|
|
72
|
+
[255, 160, 0], # Yellow-orange
|
|
73
|
+
[255, 200, 0], # Yellow
|
|
74
|
+
[255, 220, 100], # Light yellow
|
|
75
|
+
],
|
|
76
|
+
# Ocean gradient
|
|
77
|
+
ocean: [
|
|
78
|
+
[0, 80, 120], # Deep blue
|
|
79
|
+
[0, 120, 160], # Ocean blue
|
|
80
|
+
[0, 160, 200], # Bright blue
|
|
81
|
+
[0, 200, 220], # Turquoise
|
|
82
|
+
[100, 220, 220], # Aqua
|
|
83
|
+
],
|
|
84
|
+
# Forest gradient
|
|
85
|
+
forest: [
|
|
86
|
+
[0, 80, 40], # Deep green
|
|
87
|
+
[0, 120, 60], # Forest
|
|
88
|
+
[40, 160, 80], # Green
|
|
89
|
+
[80, 200, 100], # Bright green
|
|
90
|
+
[160, 220, 120], # Light green
|
|
91
|
+
],
|
|
92
|
+
# Sunset gradient
|
|
93
|
+
sunset: [
|
|
94
|
+
[100, 0, 120], # Deep purple
|
|
95
|
+
[160, 0, 100], # Purple
|
|
96
|
+
[200, 40, 80], # Magenta
|
|
97
|
+
[255, 80, 60], # Red-orange
|
|
98
|
+
[255, 140, 40], # Orange
|
|
99
|
+
[255, 200, 80], # Yellow
|
|
100
|
+
],
|
|
101
|
+
# Rainbow
|
|
102
|
+
rainbow: [
|
|
103
|
+
[255, 0, 0], # Red
|
|
104
|
+
[255, 127, 0], # Orange
|
|
105
|
+
[255, 255, 0], # Yellow
|
|
106
|
+
[0, 255, 0], # Green
|
|
107
|
+
[0, 0, 255], # Blue
|
|
108
|
+
[75, 0, 130], # Indigo
|
|
109
|
+
[148, 0, 211], # Violet
|
|
110
|
+
],
|
|
111
|
+
# Monochrome
|
|
112
|
+
mono: [
|
|
113
|
+
[60, 60, 60],
|
|
114
|
+
[100, 100, 100],
|
|
115
|
+
[140, 140, 140],
|
|
116
|
+
[180, 180, 180],
|
|
117
|
+
[220, 220, 220],
|
|
118
|
+
],
|
|
119
|
+
# Extended palettes
|
|
120
|
+
# Neon cyberpunk
|
|
121
|
+
neon: [
|
|
122
|
+
[255, 0, 102], # Hot pink
|
|
123
|
+
[255, 0, 255], # Magenta
|
|
124
|
+
[0, 255, 255], # Cyan
|
|
125
|
+
[0, 255, 128], # Neon green
|
|
126
|
+
[255, 255, 0], # Electric yellow
|
|
127
|
+
[255, 0, 102], # Back to hot pink (loop)
|
|
128
|
+
],
|
|
129
|
+
# Synthwave/Outrun
|
|
130
|
+
synthwave: [
|
|
131
|
+
[15, 5, 40], # Deep purple night
|
|
132
|
+
[139, 0, 139], # Dark magenta
|
|
133
|
+
[255, 0, 100], # Hot pink
|
|
134
|
+
[255, 110, 199], # Pink
|
|
135
|
+
[0, 255, 255], # Cyan glow
|
|
136
|
+
[255, 255, 100], # Pale yellow sun
|
|
137
|
+
],
|
|
138
|
+
# Vaporwave aesthetic
|
|
139
|
+
vaporwave: [
|
|
140
|
+
[255, 113, 206], # Pink
|
|
141
|
+
[185, 103, 255], # Purple
|
|
142
|
+
[1, 205, 254], # Cyan
|
|
143
|
+
[5, 255, 161], # Teal
|
|
144
|
+
[255, 251, 150], # Yellow
|
|
145
|
+
[255, 113, 206], # Back to pink
|
|
146
|
+
],
|
|
147
|
+
# Acid/Psychedelic
|
|
148
|
+
acid: [
|
|
149
|
+
[0, 255, 0], # Nuclear green
|
|
150
|
+
[255, 255, 0], # Bright yellow
|
|
151
|
+
[255, 0, 255], # Magenta
|
|
152
|
+
[0, 255, 255], # Cyan
|
|
153
|
+
[255, 128, 0], # Orange
|
|
154
|
+
[128, 255, 0], # Lime
|
|
155
|
+
],
|
|
156
|
+
# Plasma/Electric
|
|
157
|
+
plasma: [
|
|
158
|
+
[128, 0, 255], # Electric purple
|
|
159
|
+
[255, 0, 128], # Electric pink
|
|
160
|
+
[255, 0, 255], # Magenta
|
|
161
|
+
[0, 128, 255], # Electric blue
|
|
162
|
+
[0, 255, 255], # Cyan
|
|
163
|
+
[128, 0, 255], # Back to purple
|
|
164
|
+
],
|
|
165
|
+
# Matrix green
|
|
166
|
+
matrix: [
|
|
167
|
+
[0, 40, 0], # Dark green
|
|
168
|
+
[0, 80, 0], # Forest green
|
|
169
|
+
[0, 140, 0], # Green
|
|
170
|
+
[0, 200, 0], # Bright green
|
|
171
|
+
[0, 255, 0], # Neon green
|
|
172
|
+
[180, 255, 180], # White-green glow
|
|
173
|
+
],
|
|
174
|
+
# Lava/Magma
|
|
175
|
+
lava: [
|
|
176
|
+
[80, 0, 0], # Dark red
|
|
177
|
+
[180, 0, 0], # Red
|
|
178
|
+
[255, 60, 0], # Red-orange
|
|
179
|
+
[255, 120, 0], # Orange
|
|
180
|
+
[255, 200, 0], # Yellow-orange
|
|
181
|
+
[255, 255, 100], # Hot yellow
|
|
182
|
+
],
|
|
183
|
+
# Ice/Frozen
|
|
184
|
+
ice: [
|
|
185
|
+
[200, 240, 255], # Pale blue
|
|
186
|
+
[150, 220, 255], # Light blue
|
|
187
|
+
[100, 200, 255], # Sky blue
|
|
188
|
+
[50, 180, 255], # Blue
|
|
189
|
+
[0, 160, 255], # Deep blue
|
|
190
|
+
[255, 255, 255], # White sparkle
|
|
191
|
+
],
|
|
192
|
+
# Galaxy/Cosmic
|
|
193
|
+
galaxy: [
|
|
194
|
+
[10, 0, 30], # Deep space
|
|
195
|
+
[60, 0, 100], # Purple nebula
|
|
196
|
+
[150, 50, 200], # Violet
|
|
197
|
+
[200, 100, 255], # Light purple
|
|
198
|
+
[255, 200, 255], # Pink star
|
|
199
|
+
[255, 255, 255], # White star
|
|
200
|
+
],
|
|
201
|
+
# Toxic/Radioactive
|
|
202
|
+
toxic: [
|
|
203
|
+
[0, 0, 0], # Black
|
|
204
|
+
[0, 80, 0], # Dark green
|
|
205
|
+
[0, 180, 0], # Green
|
|
206
|
+
[180, 255, 0], # Yellow-green
|
|
207
|
+
[255, 255, 0], # Warning yellow
|
|
208
|
+
[0, 255, 0], # Neon green glow
|
|
209
|
+
],
|
|
210
|
+
# Hacker/Terminal
|
|
211
|
+
hacker: [
|
|
212
|
+
[0, 20, 0], # Almost black
|
|
213
|
+
[0, 60, 0], # Very dark green
|
|
214
|
+
[0, 100, 0], # Dark green
|
|
215
|
+
[0, 150, 10], # Green
|
|
216
|
+
[20, 200, 20], # Bright green
|
|
217
|
+
[100, 255, 100], # Glow green
|
|
218
|
+
],
|
|
219
|
+
}.freeze
|
|
220
|
+
|
|
221
|
+
class << self
|
|
222
|
+
# Move cursor up n lines
|
|
223
|
+
def up(n = 1)
|
|
224
|
+
"#{ESC}#{n}A"
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
# Move cursor down n lines
|
|
228
|
+
def down(n = 1)
|
|
229
|
+
"#{ESC}#{n}B"
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
# Move cursor forward n columns
|
|
233
|
+
def forward(n = 1)
|
|
234
|
+
"#{ESC}#{n}C"
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
# Move cursor backward n columns
|
|
238
|
+
def backward(n = 1)
|
|
239
|
+
"#{ESC}#{n}D"
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
# Move cursor to column n
|
|
243
|
+
def column(n)
|
|
244
|
+
"#{ESC}#{n}G"
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
# Move cursor to specific position
|
|
248
|
+
def position(row, col)
|
|
249
|
+
"#{ESC}#{row};#{col}H"
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
# 256-color foreground
|
|
253
|
+
def fg256(color)
|
|
254
|
+
"#{ESC}38;5;#{color}m"
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
# 256-color background
|
|
258
|
+
def bg256(color)
|
|
259
|
+
"#{ESC}48;5;#{color}m"
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
# True color (24-bit) foreground
|
|
263
|
+
def rgb(r, g, b)
|
|
264
|
+
"#{ESC}38;2;#{r};#{g};#{b}m"
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
# True color (24-bit) background
|
|
268
|
+
def bg_rgb(r, g, b)
|
|
269
|
+
"#{ESC}48;2;#{r};#{g};#{b}m"
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
# Get color from palette based on progress (0.0 to 1.0)
|
|
273
|
+
def palette_color(palette_name, progress)
|
|
274
|
+
palette = CRYSTAL_PALETTE[palette_name] || CRYSTAL_PALETTE[:crystal]
|
|
275
|
+
return rgb(*palette.first) if progress <= 0
|
|
276
|
+
return rgb(*palette.last) if progress >= 1
|
|
277
|
+
|
|
278
|
+
# Interpolate between colors
|
|
279
|
+
scaled = progress * (palette.length - 1)
|
|
280
|
+
index = scaled.floor
|
|
281
|
+
fraction = scaled - index
|
|
282
|
+
|
|
283
|
+
c1 = palette[index]
|
|
284
|
+
c2 = palette[[index + 1, palette.length - 1].min]
|
|
285
|
+
|
|
286
|
+
r = (c1[0] + (c2[0] - c1[0]) * fraction).round
|
|
287
|
+
g = (c1[1] + (c2[1] - c1[1]) * fraction).round
|
|
288
|
+
b = (c1[2] + (c2[2] - c1[2]) * fraction).round
|
|
289
|
+
|
|
290
|
+
rgb(r, g, b)
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
# Create a shimmer effect (slight brightness variation)
|
|
294
|
+
def shimmer(r, g, b, phase)
|
|
295
|
+
shimmer_amount = (Math.sin(phase) * 30).round
|
|
296
|
+
r = [[r + shimmer_amount, 0].max, 255].min
|
|
297
|
+
g = [[g + shimmer_amount, 0].max, 255].min
|
|
298
|
+
b = [[b + shimmer_amount, 0].max, 255].min
|
|
299
|
+
rgb(r, g, b)
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
# Rainbow color from hue (0.0 to 1.0)
|
|
303
|
+
def hue_to_rgb(hue, saturation = 1.0, lightness = 0.5)
|
|
304
|
+
hue = hue % 1.0
|
|
305
|
+
c = (1 - (2 * lightness - 1).abs) * saturation
|
|
306
|
+
x = c * (1 - ((hue * 6) % 2 - 1).abs)
|
|
307
|
+
m = lightness - c / 2
|
|
308
|
+
|
|
309
|
+
r, g, b = case (hue * 6).floor
|
|
310
|
+
when 0 then [c, x, 0]
|
|
311
|
+
when 1 then [x, c, 0]
|
|
312
|
+
when 2 then [0, c, x]
|
|
313
|
+
when 3 then [0, x, c]
|
|
314
|
+
when 4 then [x, 0, c]
|
|
315
|
+
else [c, 0, x]
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
rgb(((r + m) * 255).round, ((g + m) * 255).round, ((b + m) * 255).round)
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
# Animated rainbow color based on position and time
|
|
322
|
+
def rainbow_cycle(position, time, speed = 1.0)
|
|
323
|
+
hue = (position + time * speed) % 1.0
|
|
324
|
+
hue_to_rgb(hue, 1.0, 0.5)
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
# Neon glow effect - returns [bg_color, fg_color] for glow effect
|
|
328
|
+
def neon_glow(r, g, b, intensity = 1.0)
|
|
329
|
+
# Dim background glow
|
|
330
|
+
glow_r = (r * 0.3 * intensity).round
|
|
331
|
+
glow_g = (g * 0.3 * intensity).round
|
|
332
|
+
glow_b = (b * 0.3 * intensity).round
|
|
333
|
+
# Bright foreground
|
|
334
|
+
fg = rgb([[r + 50, 255].min, 0].max, [[g + 50, 255].min, 0].max, [[b + 50, 255].min, 0].max)
|
|
335
|
+
bg = bg_rgb(glow_r, glow_g, glow_b)
|
|
336
|
+
[bg, fg]
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
# Pulsing brightness effect
|
|
340
|
+
def pulse(r, g, b, time, min_brightness = 0.5, max_brightness = 1.0)
|
|
341
|
+
brightness = min_brightness + (max_brightness - min_brightness) * (0.5 + 0.5 * Math.sin(time * Math::PI * 2))
|
|
342
|
+
rgb((r * brightness).round.clamp(0, 255),
|
|
343
|
+
(g * brightness).round.clamp(0, 255),
|
|
344
|
+
(b * brightness).round.clamp(0, 255))
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
# Fire flicker effect
|
|
348
|
+
def fire_flicker(base_r, base_g, base_b, time)
|
|
349
|
+
flicker = rand(-20..20) + (Math.sin(time * 10) * 15).round
|
|
350
|
+
rgb((base_r + flicker).clamp(0, 255),
|
|
351
|
+
(base_g + flicker / 2).clamp(0, 255),
|
|
352
|
+
(base_b).clamp(0, 255))
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
# Glitch effect - occasionally scramble color
|
|
356
|
+
def glitch(r, g, b, probability = 0.1)
|
|
357
|
+
if rand < probability
|
|
358
|
+
# Random color shift
|
|
359
|
+
shift = rand(-100..100)
|
|
360
|
+
rgb((r + shift).clamp(0, 255), (g + shift).clamp(0, 255), (b + shift).clamp(0, 255))
|
|
361
|
+
else
|
|
362
|
+
rgb(r, g, b)
|
|
363
|
+
end
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
# Strip ANSI codes from string
|
|
367
|
+
def strip(str)
|
|
368
|
+
str.gsub(/\e\[[0-9;]*[a-zA-Z]/, "")
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
# Visible length of string (excluding ANSI codes)
|
|
372
|
+
def visible_length(str)
|
|
373
|
+
strip(str).length
|
|
374
|
+
end
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
# Extended spinner styles for maximum pizzazz
|
|
378
|
+
SPINNERS = {
|
|
379
|
+
braille: ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"],
|
|
380
|
+
dots: ["⣾", "⣽", "⣻", "⢿", "⡿", "⣟", "⣯", "⣷"],
|
|
381
|
+
moon: ["🌑", "🌒", "🌓", "🌔", "🌕", "🌖", "🌗", "🌘"],
|
|
382
|
+
clock: ["🕐", "🕑", "🕒", "🕓", "🕔", "🕕", "🕖", "🕗", "🕘", "🕙", "🕚", "🕛"],
|
|
383
|
+
earth: ["🌍", "🌎", "🌏"],
|
|
384
|
+
bounce: ["⠁", "⠂", "⠄", "⠂"],
|
|
385
|
+
arc: ["◜", "◠", "◝", "◞", "◡", "◟"],
|
|
386
|
+
square: ["◰", "◳", "◲", "◱"],
|
|
387
|
+
arrows: ["←", "↖", "↑", "↗", "→", "↘", "↓", "↙"],
|
|
388
|
+
box: ["▖", "▘", "▝", "▗"],
|
|
389
|
+
triangle: ["◢", "◣", "◤", "◥"],
|
|
390
|
+
binary: ["0", "1"],
|
|
391
|
+
hearts: ["💖", "💗", "💓", "💗"],
|
|
392
|
+
fire: ["🔥", "🔥", "🔥", "🔥", "🔥", "🔥", "🔥", "🔥", "✨", "✨"],
|
|
393
|
+
sparkle: ["✨", "💫", "⭐", "🌟", "💫", "✨"],
|
|
394
|
+
nyan: ["🐱", "🐱", "🐱", "🌈"],
|
|
395
|
+
snake: ["⠁", "⠉", "⠋", "⠛", "⠟", "⠿", "⡿", "⣿", "⣶", "⣤", "⣀"],
|
|
396
|
+
grow: ["▁", "▂", "▃", "▄", "▅", "▆", "▇", "█", "▇", "▆", "▅", "▄", "▃", "▂"],
|
|
397
|
+
wave: ["▁", "▂", "▃", "▄", "▅", "▆", "▇", "█", "▇", "▆", "▅", "▄", "▃", "▂", "▁"],
|
|
398
|
+
toggle: ["⊶", "⊷"],
|
|
399
|
+
balloon: [".", "o", "O", "@", "*", " "],
|
|
400
|
+
noise: ["▓", "▒", "░", "▒"],
|
|
401
|
+
dna: ["╔", "╗", "╝", "╚"],
|
|
402
|
+
weather: ["🌤️", "⛅", "🌥️", "☁️", "🌧️", "⛈️", "🌩️", "🌨️"],
|
|
403
|
+
rocket: ["🚀", "🚀", "💨", "✨"],
|
|
404
|
+
skull: ["💀", "☠️"],
|
|
405
|
+
eyes: ["👁️", "👀", "👁️", "👀"],
|
|
406
|
+
explosion: ["💥", "✨", "🔥", "💫"],
|
|
407
|
+
}.freeze
|
|
408
|
+
|
|
409
|
+
# Celebration effects
|
|
410
|
+
CELEBRATIONS = {
|
|
411
|
+
firework: [".", "*", "✦", "✸", "✹", "✺", "✹", "✸", "✦", "*", "."],
|
|
412
|
+
confetti: ["🎊", "🎉", "✨", "🌟", "💫", "⭐"],
|
|
413
|
+
party: ["🎈", "🎁", "🎂", "🍰", "🎊", "🎉"],
|
|
414
|
+
success: ["✓", "✔", "✔️", "☑️", "✅"],
|
|
415
|
+
}.freeze
|
|
416
|
+
|
|
417
|
+
# Box drawing characters for frames
|
|
418
|
+
FRAMES = {
|
|
419
|
+
single: { tl: "┌", tr: "┐", bl: "└", br: "┘", h: "─", v: "│" },
|
|
420
|
+
double: { tl: "╔", tr: "╗", bl: "╚", br: "╝", h: "═", v: "║" },
|
|
421
|
+
rounded: { tl: "╭", tr: "╮", bl: "╰", br: "╯", h: "─", v: "│" },
|
|
422
|
+
bold: { tl: "┏", tr: "┓", bl: "┗", br: "┛", h: "━", v: "┃" },
|
|
423
|
+
ascii: { tl: "+", tr: "+", bl: "+", br: "+", h: "-", v: "|" },
|
|
424
|
+
}.freeze
|
|
425
|
+
end
|
|
426
|
+
end
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ProgressBarNone
|
|
4
|
+
# The main progress bar class
|
|
5
|
+
class Bar
|
|
6
|
+
attr_reader :total, :current, :metrics, :title
|
|
7
|
+
|
|
8
|
+
# Initialize a new progress bar
|
|
9
|
+
# @param total [Integer] Total number of items
|
|
10
|
+
# @param title [String, nil] Optional title for the progress bar
|
|
11
|
+
# @param style [Symbol] Visual style (:crystal, :blocks, :dots, :arrows, :ascii, :fire, :nyan, :matrix, etc.)
|
|
12
|
+
# @param palette [Symbol] Color palette (:crystal, :fire, :ocean, :neon, :synthwave, :vaporwave, :acid, etc.)
|
|
13
|
+
# @param width [Integer] Width of the progress bar
|
|
14
|
+
# @param output [IO] Output stream (default: $stderr)
|
|
15
|
+
# @param spinner [Symbol] Spinner style (:braille, :moon, :clock, :earth, :fire, :nyan, etc.)
|
|
16
|
+
# @param rainbow_mode [Boolean] Enable rainbow color cycling animation
|
|
17
|
+
# @param celebration [Symbol] Celebration effect on completion (:confetti, :firework, :party, :success)
|
|
18
|
+
# @param glow [Boolean] Enable neon glow effect on the progress bar edge
|
|
19
|
+
# @param fps [Integer] Frames per second for animation (default: 15)
|
|
20
|
+
def initialize(total:, title: nil, style: :crystal, palette: :crystal, width: 40, output: $stderr,
|
|
21
|
+
spinner: :braille, rainbow_mode: false, celebration: :confetti, glow: false, fps: 15)
|
|
22
|
+
@total = total
|
|
23
|
+
@current = 0
|
|
24
|
+
@title = title
|
|
25
|
+
@output = output
|
|
26
|
+
@started_at = nil
|
|
27
|
+
@last_render_at = nil
|
|
28
|
+
@render_interval = 1.0 / fps
|
|
29
|
+
@metrics = Metrics.new
|
|
30
|
+
@renderer = Renderer.new(
|
|
31
|
+
style: style,
|
|
32
|
+
width: width,
|
|
33
|
+
palette: palette,
|
|
34
|
+
spinner: spinner,
|
|
35
|
+
rainbow_mode: rainbow_mode,
|
|
36
|
+
celebration_mode: celebration,
|
|
37
|
+
glow: glow
|
|
38
|
+
)
|
|
39
|
+
@lines_rendered = 0
|
|
40
|
+
@mutex = Mutex.new
|
|
41
|
+
@finished = false
|
|
42
|
+
@rate_samples = []
|
|
43
|
+
@last_increment_at = nil
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Start the progress bar
|
|
47
|
+
def start
|
|
48
|
+
@started_at = Time.now
|
|
49
|
+
@last_render_at = Time.now
|
|
50
|
+
@output.print ANSI::HIDE_CURSOR
|
|
51
|
+
render
|
|
52
|
+
self
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Increment progress by a given amount
|
|
56
|
+
# @param amount [Integer] Amount to increment by
|
|
57
|
+
# @param metrics [Hash, nil] Optional metrics hash to record
|
|
58
|
+
def increment(amount = 1, metrics: nil)
|
|
59
|
+
@mutex.synchronize do
|
|
60
|
+
@current += amount
|
|
61
|
+
@current = [@current, @total].min
|
|
62
|
+
|
|
63
|
+
# Track rate
|
|
64
|
+
now = Time.now
|
|
65
|
+
if @last_increment_at
|
|
66
|
+
interval = now - @last_increment_at
|
|
67
|
+
if interval > 0
|
|
68
|
+
@rate_samples << amount / interval
|
|
69
|
+
@rate_samples.shift if @rate_samples.length > 10
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
@last_increment_at = now
|
|
73
|
+
|
|
74
|
+
# Record metrics if provided
|
|
75
|
+
@metrics.record(metrics) if metrics
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
maybe_render
|
|
79
|
+
self
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Set progress to a specific value
|
|
83
|
+
# @param value [Integer] The value to set
|
|
84
|
+
# @param metrics [Hash, nil] Optional metrics hash
|
|
85
|
+
def set(value, metrics: nil)
|
|
86
|
+
@mutex.synchronize do
|
|
87
|
+
@current = [[value, 0].max, @total].min
|
|
88
|
+
@metrics.record(metrics) if metrics
|
|
89
|
+
end
|
|
90
|
+
maybe_render
|
|
91
|
+
self
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Update progress and report metrics
|
|
95
|
+
# @param metrics [Hash] Metrics hash with numeric values
|
|
96
|
+
def report(metrics)
|
|
97
|
+
@metrics.record(metrics)
|
|
98
|
+
maybe_render
|
|
99
|
+
self
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Mark the progress as finished
|
|
103
|
+
def finish
|
|
104
|
+
@mutex.synchronize do
|
|
105
|
+
@current = @total
|
|
106
|
+
@finished = true
|
|
107
|
+
end
|
|
108
|
+
render(force: true)
|
|
109
|
+
@output.puts
|
|
110
|
+
@output.print ANSI::SHOW_CURSOR
|
|
111
|
+
self
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Clear the progress bar display
|
|
115
|
+
def clear
|
|
116
|
+
@mutex.synchronize do
|
|
117
|
+
clear_rendered_lines
|
|
118
|
+
end
|
|
119
|
+
@output.print ANSI::SHOW_CURSOR
|
|
120
|
+
self
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Get current progress as a float (0.0 to 1.0)
|
|
124
|
+
def progress
|
|
125
|
+
return 0.0 if @total.zero?
|
|
126
|
+
@current.to_f / @total
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Get elapsed time in seconds
|
|
130
|
+
def elapsed
|
|
131
|
+
return 0 unless @started_at
|
|
132
|
+
Time.now - @started_at
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Get estimated time remaining
|
|
136
|
+
def eta
|
|
137
|
+
return Float::INFINITY if @current.zero?
|
|
138
|
+
return 0 if @current >= @total
|
|
139
|
+
|
|
140
|
+
elapsed_time = elapsed
|
|
141
|
+
return Float::INFINITY if elapsed_time.zero?
|
|
142
|
+
|
|
143
|
+
rate = @current / elapsed_time
|
|
144
|
+
remaining = @total - @current
|
|
145
|
+
remaining / rate
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Get current rate (items per second)
|
|
149
|
+
def rate
|
|
150
|
+
return 0.0 if @rate_samples.empty?
|
|
151
|
+
@rate_samples.sum / @rate_samples.length
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# Iterate with progress tracking
|
|
155
|
+
# @param enumerable [Enumerable] The collection to iterate
|
|
156
|
+
# @yield [item] Block to execute for each item
|
|
157
|
+
def self.each(enumerable, **options, &block)
|
|
158
|
+
items = enumerable.to_a
|
|
159
|
+
bar = new(total: items.length, **options)
|
|
160
|
+
bar.start
|
|
161
|
+
|
|
162
|
+
begin
|
|
163
|
+
items.each do |item|
|
|
164
|
+
result = yield(item)
|
|
165
|
+
# If block returns a hash with :metrics key, record it
|
|
166
|
+
if result.is_a?(Hash) && result.key?(:metrics)
|
|
167
|
+
bar.increment(metrics: result[:metrics])
|
|
168
|
+
else
|
|
169
|
+
bar.increment
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
ensure
|
|
173
|
+
bar.finish
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
private
|
|
178
|
+
|
|
179
|
+
def maybe_render
|
|
180
|
+
render
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def render(force: false)
|
|
184
|
+
@mutex.synchronize do
|
|
185
|
+
now = Time.now
|
|
186
|
+
return if !force && @last_render_at && (now - @last_render_at) < @render_interval
|
|
187
|
+
|
|
188
|
+
clear_rendered_lines
|
|
189
|
+
|
|
190
|
+
state = build_state
|
|
191
|
+
lines = @renderer.render(state)
|
|
192
|
+
|
|
193
|
+
# Add title if present
|
|
194
|
+
if @title && !@title.empty?
|
|
195
|
+
title_line = "#{ANSI::BOLD}#{ANSI.palette_color(@renderer.palette, 0.5)}#{@title}#{ANSI::RESET}"
|
|
196
|
+
lines.unshift(title_line)
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# Output lines
|
|
200
|
+
lines.each_with_index do |line, i|
|
|
201
|
+
@output.print "#{ANSI::CLEAR_LINE}#{line}"
|
|
202
|
+
@output.print "\n" if i < lines.length - 1
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
@lines_rendered = lines.length
|
|
206
|
+
@last_render_at = now
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def clear_rendered_lines
|
|
211
|
+
return if @lines_rendered.zero?
|
|
212
|
+
|
|
213
|
+
# Move up and clear each line
|
|
214
|
+
(@lines_rendered - 1).times do
|
|
215
|
+
@output.print ANSI.up(1)
|
|
216
|
+
@output.print ANSI::CLEAR_LINE
|
|
217
|
+
end
|
|
218
|
+
@output.print "\r#{ANSI::CLEAR_LINE}"
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def build_state
|
|
222
|
+
{
|
|
223
|
+
progress: progress,
|
|
224
|
+
current: @current,
|
|
225
|
+
total: @total,
|
|
226
|
+
elapsed: elapsed,
|
|
227
|
+
eta: eta,
|
|
228
|
+
rate: rate,
|
|
229
|
+
metrics: @metrics,
|
|
230
|
+
finished: @finished,
|
|
231
|
+
}
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
end
|