fatty 0.99.0 → 0.99.3
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 +4 -4
- data/CHANGELOG.org +11 -29
- data/README.md +2207 -18
- data/README.org +2066 -104
- data/exe/fatty +236 -93
- data/help/help.md +233 -0
- data/lib/fatty/action.rb +3 -7
- data/lib/fatty/actionable.rb +2 -0
- data/lib/fatty/alert.rb +65 -39
- data/lib/fatty/ansi/renderer.rb +26 -6
- data/lib/fatty/ansi.rb +1 -0
- data/lib/fatty/api/alert.rb +15 -0
- data/lib/fatty/api/choose.rb +145 -0
- data/lib/fatty/api/environment.rb +12 -0
- data/lib/fatty/api/keytest.rb +11 -0
- data/lib/fatty/api/menu.rb +104 -0
- data/lib/fatty/api/output.rb +55 -0
- data/lib/fatty/api/progress.rb +24 -0
- data/lib/fatty/api/prompt.rb +77 -0
- data/lib/fatty/api/status.rb +55 -0
- data/lib/fatty/api.rb +38 -0
- data/lib/fatty/callback_environment.rb +74 -0
- data/lib/fatty/colors/color.rb +366 -232
- data/lib/fatty/colors/pairs.rb +2 -0
- data/lib/fatty/command.rb +78 -0
- data/lib/fatty/config.rb +227 -39
- data/lib/fatty/config_files/config.yml +4 -12
- data/lib/fatty/config_files/keydefs.yml +13 -23
- data/lib/fatty/config_files/themes/capuchin_monk.yml +140 -0
- data/lib/fatty/config_files/themes/catppuccin_latte.yml +140 -0
- data/lib/fatty/config_files/themes/catppuccin_mocha.yml +140 -0
- data/lib/fatty/config_files/themes/cyberpunk.yml +141 -0
- data/lib/fatty/config_files/themes/dracula.yml +140 -0
- data/lib/fatty/config_files/themes/everforest_dark.yml +140 -0
- data/lib/fatty/config_files/themes/gruvbox_dark.yml +140 -0
- data/lib/fatty/config_files/themes/gruvbox_light.yml +140 -0
- data/lib/fatty/config_files/themes/mono.yml +119 -47
- data/lib/fatty/config_files/themes/monokai.yml +140 -0
- data/lib/fatty/config_files/themes/nordic.yml +1 -0
- data/lib/fatty/config_files/themes/onedark.yml +140 -0
- data/lib/fatty/config_files/themes/solarized_dark.yml +1 -0
- data/lib/fatty/config_files/themes/solarized_light.yml +140 -0
- data/lib/fatty/config_files/themes/terminal.yml +67 -0
- data/lib/fatty/config_files/themes/tokyo_night.yml +140 -0
- data/lib/fatty/config_files/themes/wordperfect.yml +80 -9
- data/lib/fatty/core_ext/hash.rb +19 -0
- data/lib/fatty/core_ext/string.rb +19 -12
- data/lib/fatty/core_ext.rb +1 -0
- data/lib/fatty/curses/context.rb +86 -84
- data/lib/fatty/curses/event_source.rb +128 -40
- data/lib/fatty/curses/key_decoder.rb +77 -11
- data/lib/fatty/env.rb +21 -20
- data/lib/fatty/help.rb +1 -29
- data/lib/fatty/history/entry.rb +2 -0
- data/lib/fatty/history.rb +17 -14
- data/lib/fatty/input_buffer.rb +71 -47
- data/lib/fatty/input_field.rb +216 -149
- data/lib/fatty/key_event.rb +67 -66
- data/lib/fatty/key_map.rb +54 -16
- data/lib/fatty/keymaps/emacs.rb +40 -6
- data/lib/fatty/log_formats/json.rb +2 -0
- data/lib/fatty/log_formats/text.rb +2 -0
- data/lib/fatty/logger.rb +7 -2
- data/lib/fatty/markdown/ansi_renderer.rb +75 -6
- data/lib/fatty/markdown/render.rb +2 -3
- data/lib/fatty/mouse_event.rb +142 -2
- data/lib/fatty/output_buffer.rb +2 -0
- data/lib/fatty/pager.rb +158 -47
- data/lib/fatty/progress.rb +417 -0
- data/lib/fatty/renderer/curses.rb +340 -184
- data/lib/fatty/renderer/truecolor.rb +266 -163
- data/lib/fatty/renderer.rb +115 -97
- data/lib/fatty/screen.rb +2 -0
- data/lib/fatty/session/alert_session.rb +39 -21
- data/lib/fatty/session/isearch_session.rb +92 -38
- data/lib/fatty/session/keytest_session.rb +105 -85
- data/lib/fatty/session/modal_session.rb +38 -1
- data/lib/fatty/session/output_session.rb +472 -21
- data/lib/fatty/session/popup_session.rb +251 -134
- data/lib/fatty/session/prompt_session.rb +68 -26
- data/lib/fatty/session/search_session.rb +79 -31
- data/lib/fatty/session/shell_session.rb +383 -368
- data/lib/fatty/session/status_session.rb +167 -0
- data/lib/fatty/session.rb +95 -95
- data/lib/fatty/terminal/popup_owner.rb +14 -11
- data/lib/fatty/terminal.rb +515 -813
- data/lib/fatty/themes/loader.rb +4 -2
- data/lib/fatty/themes/manager.rb +4 -0
- data/lib/fatty/themes/registry.rb +2 -0
- data/lib/fatty/themes/resolver.rb +175 -162
- data/lib/fatty/version.rb +1 -1
- data/lib/fatty/viewport.rb +8 -1
- data/lib/fatty.rb +35 -7
- metadata +42 -40
- data/.envrc +0 -2
- data/.simplecov +0 -23
- data/.yardopts +0 -4
- data/CHANGELOG.md +0 -34
- data/Rakefile +0 -15
- data/TODO.org +0 -163
- data/examples/markdown/native-markdown.md +0 -370
- data/examples/markdown/ox-gfm-markdown.md +0 -373
- data/examples/markdown/ox-gfm-markdown.org +0 -376
- data/fatty.gemspec +0 -42
- data/lib/fatty/accept_env.rb +0 -32
- data/lib/fatty/config_files/help.md +0 -120
- data/lib/fatty/config_files/help.org +0 -124
- data/lib/fatty/config_files/themes/wordperfect_light.yml +0 -77
- data/lib/fatty/menu_env.rb +0 -22
- data/lib/fatty/session/input_session.rb +0 -99
- data/lib/fatty/sessions.rb +0 -14
- data/lib/fatty/terminal/progress.rb +0 -374
- data/lib/fatty/view/alert_view.rb +0 -14
- data/lib/fatty/view/cursor_view.rb +0 -18
- data/lib/fatty/view/input_view.rb +0 -9
- data/lib/fatty/view/output_view.rb +0 -9
- data/lib/fatty/view/status_view.rb +0 -14
- data/lib/fatty/view.rb +0 -33
- data/lib/fatty/views.rb +0 -9
- data/sig/fatty.rbs +0 -4
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Fatty
|
|
4
|
+
class Progress
|
|
5
|
+
PARTIAL_BLOCKS = ["", "▏", "▎", "▍", "▌", "▋", "▊", "▉"].freeze
|
|
6
|
+
FULL_BLOCK = "█"
|
|
7
|
+
EMPTY_BAR = "."
|
|
8
|
+
|
|
9
|
+
SHADE_EMPTY = "░"
|
|
10
|
+
SHADE_HALF = "▒"
|
|
11
|
+
SHADE_FULL = "▓"
|
|
12
|
+
|
|
13
|
+
BRAILLE_STEPS = ["⠀", "⣀", "⣄", "⣆", "⣇", "⣧", "⣷", "⣿"].freeze
|
|
14
|
+
|
|
15
|
+
STYLES = %i[
|
|
16
|
+
count
|
|
17
|
+
percent
|
|
18
|
+
count_percent
|
|
19
|
+
trail
|
|
20
|
+
bar
|
|
21
|
+
unicode_bar
|
|
22
|
+
braille_bar
|
|
23
|
+
spinner
|
|
24
|
+
].freeze
|
|
25
|
+
|
|
26
|
+
DEFAULT_LABEL = "Progress"
|
|
27
|
+
DEFAULT_ROLE = :info
|
|
28
|
+
DEFAULT_STYLE = :percent
|
|
29
|
+
DEFAULT_WIDTH = 40
|
|
30
|
+
|
|
31
|
+
attr_reader :terminal, :label, :total, :current, :style, :role, :width
|
|
32
|
+
|
|
33
|
+
# The width parameter's purpose varies by style:
|
|
34
|
+
#
|
|
35
|
+
# | Style | Width Purpose |
|
|
36
|
+
# |----------------+---------------------------------------------------|
|
|
37
|
+
# | :trail | width = max visible width of the trail portion |
|
|
38
|
+
# | :bar | width = max bar width |
|
|
39
|
+
# | :unicode_bar | width = max bar width |
|
|
40
|
+
# | :braille_bar | width = max bar width |
|
|
41
|
+
# | :spinner | width ignored, unless later used for suffix/trail |
|
|
42
|
+
# | :count | width ignored |
|
|
43
|
+
# | :percent | width ignored |
|
|
44
|
+
# | :count_percent | width ignored |
|
|
45
|
+
def initialize(
|
|
46
|
+
terminal:,
|
|
47
|
+
label: DEFAULT_LABEL,
|
|
48
|
+
total: nil,
|
|
49
|
+
style: DEFAULT_STYLE,
|
|
50
|
+
role: DEFAULT_ROLE,
|
|
51
|
+
width: DEFAULT_WIDTH
|
|
52
|
+
)
|
|
53
|
+
@terminal = terminal
|
|
54
|
+
@label = normalize_label(label)
|
|
55
|
+
@total = normalize_total(total)
|
|
56
|
+
@style = normalize_style(style)
|
|
57
|
+
@role = normalize_role(role)
|
|
58
|
+
@width = normalize_width(width)
|
|
59
|
+
@trail = []
|
|
60
|
+
@current = 0
|
|
61
|
+
@spinner_index = 0
|
|
62
|
+
validate_total_requirement!
|
|
63
|
+
refresh
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def update(current: nil, indicator: nil, render: false)
|
|
67
|
+
@current = normalize_current(current) unless current.nil?
|
|
68
|
+
if style == :spinner
|
|
69
|
+
advance_spinner
|
|
70
|
+
else
|
|
71
|
+
append_indicator(indicator)
|
|
72
|
+
end
|
|
73
|
+
refresh(render:)
|
|
74
|
+
self
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def finish(message = nil, clear: false, role: @role, render: false)
|
|
78
|
+
if clear
|
|
79
|
+
clear_status
|
|
80
|
+
else
|
|
81
|
+
text =
|
|
82
|
+
if message && !message.empty?
|
|
83
|
+
render_text(suffix: message)
|
|
84
|
+
else
|
|
85
|
+
render_text
|
|
86
|
+
end
|
|
87
|
+
show_status(text, role: role)
|
|
88
|
+
end
|
|
89
|
+
terminal.render_frame if render
|
|
90
|
+
self
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def clear
|
|
94
|
+
clear_status
|
|
95
|
+
self
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
private
|
|
99
|
+
|
|
100
|
+
# simplecov:disable
|
|
101
|
+
|
|
102
|
+
def normalize_label(value)
|
|
103
|
+
text = value.to_s.strip
|
|
104
|
+
text.empty? ? DEFAULT_LABEL : text
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def normalize_total(value)
|
|
108
|
+
return if value.nil?
|
|
109
|
+
|
|
110
|
+
Integer(value, exception: false)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def normalize_style(value)
|
|
114
|
+
candidate = value&.to_sym || DEFAULT_STYLE
|
|
115
|
+
return candidate if STYLES.include?(candidate)
|
|
116
|
+
|
|
117
|
+
raise ArgumentError, "unknown progress style: #{value.inspect}"
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def normalize_role(value)
|
|
121
|
+
text = value.to_s.strip
|
|
122
|
+
return DEFAULT_ROLE if text.empty?
|
|
123
|
+
|
|
124
|
+
candidate = text.downcase.to_sym
|
|
125
|
+
return candidate if %i[good info warn error].include?(candidate)
|
|
126
|
+
|
|
127
|
+
raise ArgumentError, "progress role must be :good, :info, :warn, or :error"
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def normalize_width(value)
|
|
131
|
+
candidate = Integer(value, exception: false)
|
|
132
|
+
candidate&.positive? ? candidate : DEFAULT_WIDTH
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def normalize_current(value)
|
|
136
|
+
candidate = Integer(value, exception: false)
|
|
137
|
+
return candidate if candidate
|
|
138
|
+
|
|
139
|
+
raise ArgumentError, "progress current must be an integer: #{value.inspect}"
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def show_status(text, role:)
|
|
143
|
+
terminal.apply_command(Command.session(:status, :show, text: text, role: role))
|
|
144
|
+
nil
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def clear_status
|
|
148
|
+
terminal.apply_command(Command.session(:status, :clear))
|
|
149
|
+
nil
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def append_indicator(indicator)
|
|
153
|
+
return if indicator.nil?
|
|
154
|
+
|
|
155
|
+
item = normalize_indicator(indicator)
|
|
156
|
+
return if renderable_indicator_text(item).empty?
|
|
157
|
+
|
|
158
|
+
@trail << item
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def refresh(render: false)
|
|
162
|
+
terminal.without_cursor_restore do
|
|
163
|
+
terminal.apply_command(
|
|
164
|
+
Command.session(
|
|
165
|
+
:status,
|
|
166
|
+
:show,
|
|
167
|
+
text: render_text,
|
|
168
|
+
role: role,
|
|
169
|
+
)
|
|
170
|
+
)
|
|
171
|
+
terminal.render_frame if render
|
|
172
|
+
end
|
|
173
|
+
nil
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def render_text(suffix: nil)
|
|
177
|
+
case style
|
|
178
|
+
when :count
|
|
179
|
+
base = total ? "#{label} [#{current}/#{total}]" : "#{label} [#{current}]"
|
|
180
|
+
suffix_text(base, suffix)
|
|
181
|
+
when :percent
|
|
182
|
+
base = total && total > 0 ? "#{label} #{percent}%" : label.to_s
|
|
183
|
+
suffix_text(base, suffix)
|
|
184
|
+
when :count_percent
|
|
185
|
+
base =
|
|
186
|
+
if total && total > 0
|
|
187
|
+
"#{label} [#{current}/#{total}] #{percent}%"
|
|
188
|
+
else
|
|
189
|
+
"#{label} [#{current}]"
|
|
190
|
+
end
|
|
191
|
+
suffix_text(base, suffix)
|
|
192
|
+
when :trail
|
|
193
|
+
render_trail_text(suffix:)
|
|
194
|
+
when :bar
|
|
195
|
+
render_bar_text(suffix:, mode: :solid)
|
|
196
|
+
when :unicode_bar
|
|
197
|
+
render_bar_text(suffix:, mode: :unicode)
|
|
198
|
+
when :braille_bar
|
|
199
|
+
render_bar_text(suffix:, mode: :braille)
|
|
200
|
+
when :spinner
|
|
201
|
+
render_spinner_text(suffix:)
|
|
202
|
+
else
|
|
203
|
+
raise ArgumentError, "unknown progress style: #{style.inspect}"
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def percent
|
|
208
|
+
((current.to_f / total.to_f) * 100).round
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
def suffix_text(base, suffix)
|
|
212
|
+
extra = suffix.to_s
|
|
213
|
+
return base if extra.empty?
|
|
214
|
+
|
|
215
|
+
"#{base} #{extra}"
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def render_trail_text(suffix: nil)
|
|
219
|
+
base =
|
|
220
|
+
if total && total > 0
|
|
221
|
+
"#{label} [#{current}/#{total}] #{percent}%"
|
|
222
|
+
else
|
|
223
|
+
"#{label} [#{current}]"
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
trailer = suffix.to_s.empty? ? "" : " #{suffix}"
|
|
227
|
+
return "#{base}#{trailer}" if @trail.empty?
|
|
228
|
+
|
|
229
|
+
[base, " ", *@trail, trailer]
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
def visible_length(value)
|
|
233
|
+
if value.is_a?(Hash) && value.key?(:text)
|
|
234
|
+
Fatty::Ansi.visible_length(value[:text].to_s)
|
|
235
|
+
else
|
|
236
|
+
Fatty::Ansi.visible_length(value.to_s)
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
def normalize_indicator(indicator)
|
|
241
|
+
if indicator.is_a?(Hash) && indicator.key?(:text)
|
|
242
|
+
indicator.merge(text: renderable_indicator_text(indicator))
|
|
243
|
+
else
|
|
244
|
+
renderable_indicator_text(indicator)
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
def renderable_indicator_text(item)
|
|
249
|
+
text =
|
|
250
|
+
if item.is_a?(Hash) && item.key?(:text)
|
|
251
|
+
item[:text].to_s
|
|
252
|
+
else
|
|
253
|
+
item.to_s
|
|
254
|
+
end
|
|
255
|
+
text.gsub(/\s+/, " ").strip
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
def render_bar_text(suffix: nil, mode: :solid)
|
|
259
|
+
base = label.to_s
|
|
260
|
+
info = progress_info_text
|
|
261
|
+
extra = suffix.to_s
|
|
262
|
+
trailer = extra.empty? ? "" : " #{extra}"
|
|
263
|
+
|
|
264
|
+
bar_width = bar_width_for(base, info, trailer)
|
|
265
|
+
bar =
|
|
266
|
+
case mode
|
|
267
|
+
when :unicode
|
|
268
|
+
unicode_bar(bar_width)
|
|
269
|
+
when :braille
|
|
270
|
+
braille_bar(bar_width)
|
|
271
|
+
else
|
|
272
|
+
solid_bar(bar_width)
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
pieces = [base]
|
|
276
|
+
pieces << "[#{bar}]" unless bar.empty?
|
|
277
|
+
pieces << info unless info.empty?
|
|
278
|
+
|
|
279
|
+
text = pieces.join(" ")
|
|
280
|
+
text = "#{text}#{trailer}" unless trailer.empty?
|
|
281
|
+
text
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
def render_spinner_text(suffix: nil)
|
|
285
|
+
frame = spinner_frames[@spinner_index % spinner_frames.length]
|
|
286
|
+
base =
|
|
287
|
+
if total && total > 0
|
|
288
|
+
"#{label} #{frame} #{percent}%"
|
|
289
|
+
else
|
|
290
|
+
"#{label} #{frame}"
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
suffix_text(base, suffix)
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
def progress_info_text
|
|
297
|
+
if total && total > 0
|
|
298
|
+
"#{percent}% [#{current}/#{total}]"
|
|
299
|
+
else
|
|
300
|
+
"[#{current}]"
|
|
301
|
+
end
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
def bar_width_for(base, info, trailer)
|
|
305
|
+
cols =
|
|
306
|
+
if terminal.screen
|
|
307
|
+
terminal.screen.cols.to_i
|
|
308
|
+
else
|
|
309
|
+
80
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
reserved = visible_length(base)
|
|
313
|
+
reserved += 1 + visible_length(info) unless info.empty?
|
|
314
|
+
reserved += visible_length(trailer) unless trailer.empty?
|
|
315
|
+
|
|
316
|
+
# Space for:
|
|
317
|
+
# " ["
|
|
318
|
+
# "]"
|
|
319
|
+
# around the bar
|
|
320
|
+
available = cols - reserved - 4
|
|
321
|
+
available = 0 if available < 0
|
|
322
|
+
[available, @width].min
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
def solid_bar(width)
|
|
326
|
+
return "" if width <= 0
|
|
327
|
+
|
|
328
|
+
ratio = progress_ratio
|
|
329
|
+
filled = (ratio * width).round
|
|
330
|
+
filled = 0 if filled < 0
|
|
331
|
+
filled = width if filled > width
|
|
332
|
+
|
|
333
|
+
empty = width - filled
|
|
334
|
+
(FULL_BLOCK * filled) + (EMPTY_BAR * empty)
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
def unicode_bar(width)
|
|
338
|
+
return "" if width <= 0
|
|
339
|
+
|
|
340
|
+
raw = progress_ratio * width
|
|
341
|
+
full = raw.floor
|
|
342
|
+
|
|
343
|
+
# Show a transition block whenever the bar is in progress but not complete,
|
|
344
|
+
# provided there is space for it.
|
|
345
|
+
half =
|
|
346
|
+
if progress_ratio.positive? && progress_ratio < 1.0 && full < width
|
|
347
|
+
1
|
|
348
|
+
else
|
|
349
|
+
0
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
bar = +""
|
|
353
|
+
bar << (SHADE_FULL * full)
|
|
354
|
+
bar << SHADE_HALF if half == 1
|
|
355
|
+
|
|
356
|
+
remaining = width - Fatty::Ansi.visible_length(bar)
|
|
357
|
+
remaining = 0 if remaining < 0
|
|
358
|
+
bar << (SHADE_EMPTY * remaining)
|
|
359
|
+
bar
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
def braille_bar(width)
|
|
363
|
+
return "" if width <= 0
|
|
364
|
+
|
|
365
|
+
raw = progress_ratio * width
|
|
366
|
+
full = raw.floor
|
|
367
|
+
remainder = raw - full
|
|
368
|
+
|
|
369
|
+
partial_idx = (remainder * (BRAILLE_STEPS.length - 1)).round
|
|
370
|
+
partial_idx = 0 if partial_idx < 0
|
|
371
|
+
partial_idx = BRAILLE_STEPS.length - 1 if partial_idx >= BRAILLE_STEPS.length
|
|
372
|
+
|
|
373
|
+
bar = +""
|
|
374
|
+
bar << (BRAILLE_STEPS[-1] * full)
|
|
375
|
+
|
|
376
|
+
if progress_ratio.positive? && progress_ratio < 1.0 && full < width
|
|
377
|
+
partial =
|
|
378
|
+
if partial_idx.zero?
|
|
379
|
+
BRAILLE_STEPS[1]
|
|
380
|
+
else
|
|
381
|
+
BRAILLE_STEPS[partial_idx]
|
|
382
|
+
end
|
|
383
|
+
bar << partial
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
remaining = width - Fatty::Ansi.visible_length(bar)
|
|
387
|
+
remaining = 0 if remaining < 0
|
|
388
|
+
bar << (BRAILLE_STEPS[0] * remaining)
|
|
389
|
+
bar
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
def progress_ratio
|
|
393
|
+
return 0.0 unless total && total > 0
|
|
394
|
+
|
|
395
|
+
ratio = current.to_f / total.to_f
|
|
396
|
+
ratio = 0.0 if ratio < 0.0
|
|
397
|
+
ratio = 1.0 if ratio > 1.0
|
|
398
|
+
ratio
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
def validate_total_requirement!
|
|
402
|
+
return if style == :spinner && total.nil?
|
|
403
|
+
return if total&.positive?
|
|
404
|
+
|
|
405
|
+
raise ArgumentError,
|
|
406
|
+
"progress style #{style.inspect} requires a positive integer total:"
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
def advance_spinner
|
|
410
|
+
@spinner_index = (@spinner_index + 1) % spinner_frames.length
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
def spinner_frames
|
|
414
|
+
BRAILLE_STEPS[1..]
|
|
415
|
+
end
|
|
416
|
+
end
|
|
417
|
+
end
|