ruby-progress 1.3.2 → 1.3.4
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/.rubocop_todo.yml +20 -14
- data/CHANGELOG.md +62 -96
- data/Gemfile +2 -0
- data/Gemfile.lock +7 -1
- data/demo_screencast.rb +130 -122
- data/lib/ruby-progress/cli/fill_options.rb +8 -2
- data/lib/ruby-progress/cli/ripple_cli.rb +6 -1
- data/lib/ruby-progress/cli/ripple_options.rb +4 -0
- data/lib/ruby-progress/cli/twirl_options.rb +4 -0
- data/lib/ruby-progress/cli/twirl_runner.rb +5 -3
- data/lib/ruby-progress/cli/worm_cli.rb +2 -1
- data/lib/ruby-progress/cli/worm_options.rb +4 -0
- data/lib/ruby-progress/cli/worm_runner.rb +9 -4
- data/lib/ruby-progress/fill_cli.rb +4 -2
- data/lib/ruby-progress/output_capture.rb +169 -37
- data/lib/ruby-progress/version.rb +1 -1
- data/lib/ruby-progress/worm.rb +8 -61
- data/screencast +2497 -26
- data/screencast.svg +1 -0
- metadata +30 -1
data/demo_screencast.rb
CHANGED
|
@@ -40,6 +40,7 @@ class ProgressDemo
|
|
|
40
40
|
|
|
41
41
|
def run
|
|
42
42
|
clear_screen
|
|
43
|
+
|
|
43
44
|
# show_title
|
|
44
45
|
|
|
45
46
|
# Introduction
|
|
@@ -70,17 +71,17 @@ class ProgressDemo
|
|
|
70
71
|
|
|
71
72
|
# Ripple - basic expanding circle animation
|
|
72
73
|
show_demo_header('Ripple', 'Expanding circle animation for tasks with unknown duration')
|
|
73
|
-
run_command("#{ruby_cmd} ripple --command 'sleep
|
|
74
|
+
run_command("#{ruby_cmd} ripple --command 'sleep 2' --success 'Download complete!' --checkmark PROCESSING")
|
|
74
75
|
pause_between_demos
|
|
75
76
|
|
|
76
77
|
# Worm - progress bar animation
|
|
77
78
|
show_demo_header('Worm', 'Animated progress bar for visual feedback')
|
|
78
|
-
run_command("#{ruby_cmd} worm --length
|
|
79
|
+
run_command("#{ruby_cmd} worm --length 4 --command 'sleep 5' --success 'Processing finished!' --checkmark --message 'Loading'")
|
|
79
80
|
pause_between_demos
|
|
80
81
|
|
|
81
82
|
# Twirl - spinning indicator
|
|
82
83
|
show_demo_header('Twirl', 'Classic spinning indicator for quick tasks')
|
|
83
|
-
run_command("#{ruby_cmd} twirl --command 'sleep
|
|
84
|
+
run_command("#{ruby_cmd} twirl --command 'sleep 2' --success 'Task completed!' --checkmark")
|
|
84
85
|
pause_between_demos
|
|
85
86
|
end
|
|
86
87
|
|
|
@@ -91,17 +92,17 @@ class ProgressDemo
|
|
|
91
92
|
show_demo_header('Ripple Styles', 'Different visual patterns')
|
|
92
93
|
show_command_info('Default ripple style')
|
|
93
94
|
run_command("#{ruby_cmd} ripple --command 'sleep 3' --success 'Default style' 'Rippling Progress Default Style'")
|
|
94
|
-
pause_between_demos(2)
|
|
95
|
-
|
|
96
|
-
show_command_info('Pulse style')
|
|
97
|
-
run_command("#{ruby_cmd} ripple --style pulse --command 'sleep 3' --success 'Pulse style' 'Rippling Progress'")
|
|
98
95
|
pause_between_demos
|
|
99
96
|
|
|
97
|
+
# show_command_info('Pulse style')
|
|
98
|
+
# run_command("#{ruby_cmd} ripple --style pulse --command 'sleep 3' --success 'Pulse style' 'Rippling Progress'")
|
|
99
|
+
# pause_between_demos
|
|
100
|
+
|
|
100
101
|
# Worm styles
|
|
101
102
|
show_demo_header('Worm Styles', 'Various progress bar animations')
|
|
102
103
|
show_command_info('Classic worm style')
|
|
103
104
|
run_command("#{ruby_cmd} worm --length 10 --style classic --command 'sleep 4' --success 'Classic worm' --message 'Classic'")
|
|
104
|
-
pause_between_demos
|
|
105
|
+
pause_between_demos
|
|
105
106
|
|
|
106
107
|
show_command_info('Blocks worm style')
|
|
107
108
|
run_command("#{ruby_cmd} worm --length 10 --style blocks --command 'sleep 4' --success 'Block worm' --message 'Blocks'")
|
|
@@ -111,14 +112,14 @@ class ProgressDemo
|
|
|
111
112
|
show_demo_header('Twirl Styles', 'Different spinning patterns')
|
|
112
113
|
show_command_info('Classic spinner')
|
|
113
114
|
run_command("#{ruby_cmd} twirl --style classic --command 'sleep 3' --success 'Classic spin' --message 'Loading'")
|
|
114
|
-
pause_between_demos
|
|
115
|
+
pause_between_demos
|
|
115
116
|
|
|
116
117
|
show_command_info('Dots spinner')
|
|
117
118
|
run_command("#{ruby_cmd} twirl --style dots --command 'sleep 3' --success 'Dotty!'")
|
|
118
|
-
pause_between_demos
|
|
119
|
+
pause_between_demos
|
|
119
120
|
|
|
120
121
|
show_command_info('Arrow spinner')
|
|
121
|
-
run_command("#{ruby_cmd} twirl --style arrow --command 'sleep
|
|
122
|
+
run_command("#{ruby_cmd} twirl --style arrow --command 'sleep 2' --success 'Arrow spin' --message 'Loading'")
|
|
122
123
|
pause_between_demos
|
|
123
124
|
end
|
|
124
125
|
|
|
@@ -128,159 +129,165 @@ class ProgressDemo
|
|
|
128
129
|
# Error handling
|
|
129
130
|
show_demo_header('Error Handling', 'Graceful failure with custom messages')
|
|
130
131
|
show_command_info('Simulating a failed task')
|
|
131
|
-
run_command("#{ruby_cmd} worm --length 10 --command 'sleep
|
|
132
|
+
run_command("#{ruby_cmd} worm --length 10 --command 'sleep 3 && exit 1' --error 'Error message!' --checkmark")
|
|
132
133
|
pause_between_demos
|
|
133
134
|
|
|
134
135
|
# Custom colors (if supported)
|
|
135
136
|
show_demo_header('Success Messages', 'Custom completion messages')
|
|
136
137
|
show_command_info('Custom success message with checkmark')
|
|
137
138
|
run_command("#{ruby_cmd} ripple --command 'sleep 3' --success 'Data synchronized successfully' --checkmark --message 'Syncing data...'")
|
|
138
|
-
pause_between_demos(2)
|
|
139
|
-
|
|
140
|
-
show_command_info('Different success icon')
|
|
141
|
-
run_command("#{ruby_cmd} twirl --command 'sleep 3' --success 'Backup completed' --success-icon '✓' --checkmark")
|
|
142
139
|
pause_between_demos
|
|
143
140
|
|
|
141
|
+
# show_command_info('Different success icon')
|
|
142
|
+
# run_command("#{ruby_cmd} twirl --command 'sleep 3' --success 'Backup completed' --success-icon '✓' --checkmark")
|
|
143
|
+
# pause_between_demos
|
|
144
|
+
|
|
144
145
|
# No completion message
|
|
145
146
|
show_demo_header('Silent Completion', 'Progress without completion messages')
|
|
146
147
|
show_command_info('Silent completion (no message)')
|
|
147
|
-
run_command("#{ruby_cmd} worm --length 10 --command 'sleep
|
|
148
|
+
run_command("#{ruby_cmd} worm --length 10 --command 'sleep 2'")
|
|
148
149
|
pause_between_demos
|
|
149
150
|
end
|
|
150
151
|
|
|
151
152
|
def demo_new_features
|
|
152
|
-
show_section_header('New in v1.2.0 - Enhanced Features')
|
|
153
|
+
# show_section_header('New in v1.2.0 - Enhanced Features')
|
|
153
154
|
|
|
154
155
|
# Universal --ends flag
|
|
155
156
|
show_demo_header('Universal --ends Flag', 'Add decorative start/end characters')
|
|
156
157
|
show_command_info("Ripple with square brackets: --ends '[]'")
|
|
157
|
-
run_command("#{ruby_cmd} ripple --ends '[]' --command 'sleep
|
|
158
|
-
pause_between_demos
|
|
158
|
+
run_command("#{ruby_cmd} ripple --ends '[]' --command 'sleep 3' --success 'Framed ripple!' 'With a frame'")
|
|
159
|
+
pause_between_demos
|
|
159
160
|
|
|
160
|
-
show_command_info("Worm with angle brackets: --ends '<<>>'")
|
|
161
|
-
run_command("#{ruby_cmd} worm --length 10 --ends '<<>>' --command 'sleep 4' --success 'Angled worm!'")
|
|
162
|
-
pause_between_demos
|
|
161
|
+
# show_command_info("Worm with angle brackets: --ends '<<>>'")
|
|
162
|
+
# run_command("#{ruby_cmd} worm --length 10 --ends '<<>>' --command 'sleep 4' --success 'Angled worm!'")
|
|
163
|
+
# pause_between_demos
|
|
163
164
|
|
|
164
|
-
show_command_info("Twirl with emoji decoration: --ends '🎯🎪'")
|
|
165
|
-
run_command("#{ruby_cmd} twirl --ends '🎯🎪' --command 'sleep 3' --success 'Emoji decorated!'")
|
|
166
|
-
pause_between_demos
|
|
165
|
+
# show_command_info("Twirl with emoji decoration: --ends '🎯🎪'")
|
|
166
|
+
# run_command("#{ruby_cmd} twirl --ends '🎯🎪' --command 'sleep 3' --success 'Emoji decorated!'")
|
|
167
|
+
# pause_between_demos
|
|
167
168
|
|
|
168
169
|
# Worm direction control
|
|
169
170
|
show_demo_header('Worm Direction Control', 'Forward-only vs bidirectional movement')
|
|
170
171
|
show_command_info('Bidirectional worm (default back-and-forth)')
|
|
171
|
-
run_command("#{ruby_cmd} worm --length 10 --direction bidirectional --command 'sleep
|
|
172
|
-
pause_between_demos
|
|
172
|
+
run_command("#{ruby_cmd} worm --length 10 --direction bidirectional --command 'sleep 3' --speed fast --success 'Both ways'")
|
|
173
|
+
pause_between_demos
|
|
173
174
|
|
|
174
175
|
show_command_info('Forward-only worm (resets at end)')
|
|
175
|
-
run_command("#{ruby_cmd} worm --length
|
|
176
|
+
run_command("#{ruby_cmd} worm --length 5 --direction forward --command 'sleep 4' --speed fast --success 'Forward only!'")
|
|
176
177
|
pause_between_demos
|
|
177
178
|
|
|
178
179
|
# Custom worm styles
|
|
179
|
-
show_demo_header('Custom Worm Styles', 'User-defined 3-character patterns')
|
|
180
|
-
show_command_info('ASCII custom style: --style custom=_-=')
|
|
181
|
-
run_command("#{ruby_cmd} worm --length 10 --style custom=_-= --command 'sleep 4' --success 'Custom ASCII!'")
|
|
182
|
-
pause_between_demos
|
|
180
|
+
# show_demo_header('Custom Worm Styles', 'User-defined 3-character patterns')
|
|
181
|
+
# show_command_info('ASCII custom style: --style custom=_-=')
|
|
182
|
+
# run_command("#{ruby_cmd} worm --length 10 --style custom=_-= --command 'sleep 4' --success 'Custom ASCII!'")
|
|
183
|
+
# pause_between_demos
|
|
183
184
|
|
|
184
185
|
show_command_info('Unicode custom style: --style custom=▫▪■')
|
|
185
|
-
run_command("#{ruby_cmd} worm --length 10 --style custom=▫▪■ --command 'sleep
|
|
186
|
-
pause_between_demos
|
|
186
|
+
run_command("#{ruby_cmd} worm --length 10 --style custom=▫▪■ --command 'sleep 3' --speed fast --success 'Custom Unicode!'")
|
|
187
|
+
pause_between_demos
|
|
187
188
|
|
|
188
189
|
show_command_info('Emoji custom style: --style custom=🟦🟨🟥')
|
|
189
|
-
run_command("#{ruby_cmd} worm --length 10 --style custom=🟦🟨🟥 --command 'sleep
|
|
190
|
+
run_command("#{ruby_cmd} worm --length 10 --style custom=🟦🟨🟥 --command 'sleep 3' --speed fast --success 'Custom emoji!'")
|
|
190
191
|
pause_between_demos
|
|
191
192
|
|
|
192
193
|
# Combining features
|
|
193
|
-
show_demo_header('Feature Combinations', 'Mixing multiple options together')
|
|
194
|
-
show_command_info('Custom style + direction + ends: the full package!')
|
|
195
|
-
# Split the long command string to avoid RuboCop line-length issues while preserving behavior
|
|
196
|
-
part1 = "#{ruby_cmd} worm --length 10 --style custom=.🟡* --direction forward "
|
|
197
|
-
part2 = "--ends '【】' --command 'sleep 5' --success 'Ultimate combo!' --checkmark"
|
|
198
|
-
run_command(part1 + part2)
|
|
199
|
-
pause_between_demos
|
|
194
|
+
# show_demo_header('Feature Combinations', 'Mixing multiple options together')
|
|
195
|
+
# show_command_info('Custom style + direction + ends: the full package!')
|
|
196
|
+
# # Split the long command string to avoid RuboCop line-length issues while preserving behavior
|
|
197
|
+
# part1 = "#{ruby_cmd} worm --length 10 --style custom=.🟡* --direction forward "
|
|
198
|
+
# part2 = "--ends '【】' --command 'sleep 5' --success 'Ultimate combo!' --checkmark"
|
|
199
|
+
# run_command(part1 + part2)
|
|
200
|
+
# pause_between_demos
|
|
200
201
|
|
|
201
202
|
# v1.3.x additions: output capture and job queue demo snippets
|
|
202
|
-
show_section_header('New in v1.3.x - Output Capture & Job Queue')
|
|
203
|
-
|
|
204
|
-
show_demo_header('Fill --command (output capture)', 'Run a command and reserve terminal rows for output while preserving animation')
|
|
203
|
+
# show_section_header('New in v1.3.x - Output Capture & Job Queue')
|
|
204
|
+
show_demo_header('Worm --command (output capture)', 'Run a command and reserve terminal rows for output while preserving animation')
|
|
205
205
|
show_command_info('Capture command stdout/stderr into reserved rows:')
|
|
206
|
-
|
|
207
|
-
|
|
206
|
+
# ensure a trailing space so flags aren't squashed onto the command string
|
|
207
|
+
part_a = %(#{ruby_cmd} worm --style blocks --length 10 --speed fast --command "ruby -e 'for i in 1..3 do; puts \\"line:\#{i}\\"; sleep 1; end'" )
|
|
208
|
+
part_b = "--stdout --success 'Captured!' --checkmark"
|
|
208
209
|
run_command(part_a + part_b)
|
|
209
210
|
pause_between_demos
|
|
210
211
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
puts "#{@colors[:command]}$ prg job send --daemon-name demo --percent 42#{@colors[:reset]}"
|
|
216
|
-
puts
|
|
217
|
-
show_command_info('Or enqueue a shell command:')
|
|
218
|
-
|
|
219
|
-
# For the demo we run the worker in the foreground so you can see the
|
|
220
|
-
# live animation and completion message inline. Daemon mode (started with
|
|
221
|
-
# `--daemon` or `--daemon-as`) detaches to the background and processes
|
|
222
|
-
# jobs via the file-based queue; `prg job send` targets a background
|
|
223
|
-
# daemon and prints the job result JSON, but won't show the daemon's
|
|
224
|
-
# animation in the foreground.
|
|
225
|
-
show_command_info('Start a named fill daemon that processes percent/action jobs')
|
|
226
|
-
# Start the fill daemon in non-detaching background mode so animation remains visible
|
|
227
|
-
run_command("#{ruby_cmd} fill --daemon-as demo --no-detach --output-lines 3 --output-position top --success 'Captured!' --checkmark")
|
|
228
|
-
pause_between_demos(1)
|
|
229
|
-
|
|
230
|
-
show_command_info('We will enqueue several percent actions via a small shell script')
|
|
231
|
-
demo_script = <<~BASH
|
|
232
|
-
#!/usr/bin/env bash
|
|
233
|
-
set -eu
|
|
234
|
-
echo "Sending percent updates to demo daemon (atomic mktemp+mv writes)"
|
|
235
|
-
|
|
236
|
-
job_dir="/tmp/ruby-progress/demo.jobs"
|
|
237
|
-
mkdir -p "$job_dir"
|
|
238
|
-
|
|
239
|
-
enqueue_percent() {
|
|
240
|
-
percent=$1
|
|
241
|
-
# Build JSON payload
|
|
242
|
-
id=$(uuidgen 2>/dev/null || echo "job-$(date +%s%N)")
|
|
243
|
-
tmp=$(mktemp "$job_dir/${id}.json.tmp.XXXXXX")
|
|
244
|
-
printf '%s\n' '{"id":"'"${id}"'","action":"percent","value":'"${percent}"'}' > "$tmp"
|
|
245
|
-
mv "$tmp" "$job_dir/${id}.json"
|
|
246
|
-
|
|
247
|
-
# Wait for the daemon to process the job (poll for .processing.result)
|
|
248
|
-
result_path="$job_dir/${id}.json.processing.result"
|
|
249
|
-
start=$(date +%s)
|
|
250
|
-
timeout=10
|
|
251
|
-
while [ ! -f "$result_path" ]; do
|
|
252
|
-
sleep 0.1
|
|
253
|
-
now=$(date +%s)
|
|
254
|
-
if [ $((now - start)) -gt $timeout ]; then
|
|
255
|
-
echo "Timed out waiting for result for job ${id}" >&2
|
|
256
|
-
return 2
|
|
257
|
-
fi
|
|
258
|
-
done
|
|
259
|
-
cat "$result_path"
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
enqueue_percent 10
|
|
263
|
-
sleep 1
|
|
264
|
-
enqueue_percent 40
|
|
265
|
-
sleep 1
|
|
266
|
-
enqueue_percent 70
|
|
267
|
-
sleep 1
|
|
268
|
-
enqueue_percent 100
|
|
269
|
-
|
|
270
|
-
# After updates, stop the daemon cleanly (call local bin/prg to avoid global conflicts)
|
|
271
|
-
#{ruby_cmd} fill --stop-id demo --stop-success 'Demo daemon stopped'
|
|
272
|
-
BASH
|
|
273
|
-
|
|
274
|
-
# Show the simulated script contents
|
|
275
|
-
puts "#{@colors[:command]}$ cat demo_percent_updates.sh#{@colors[:reset]}"
|
|
276
|
-
puts demo_script
|
|
277
|
-
|
|
278
|
-
# Write and execute the script (run in a subshell so output doesn't interleave too badly)
|
|
279
|
-
script_path = File.join(Dir.tmpdir, "demo_percent_updates_#{Time.now.to_i}.sh")
|
|
280
|
-
File.write(script_path, demo_script)
|
|
281
|
-
File.chmod(0o755, script_path)
|
|
282
|
-
run_command("bash #{Shellwords.escape(script_path)}")
|
|
212
|
+
show_command_info('Capture command stdout/stderr and display live:')
|
|
213
|
+
part_a = %(#{ruby_cmd} worm --style blocks --length 10 --speed fast --command "ruby -e 'for i in 1..5 do; puts \\"line:\#{i}\\"; sleep 0.5; end'" )
|
|
214
|
+
part_b = "--output-lines 3 --output-position top --stdout-live --success 'Captured live!' --checkmark"
|
|
215
|
+
run_command(part_a + part_b)
|
|
283
216
|
pause_between_demos
|
|
217
|
+
|
|
218
|
+
# show_demo_header('prg job send (enqueue a job)', 'Send a job to a running daemon using the file-based job queue')
|
|
219
|
+
# show_command_info('Example: create a job payload and atomically enqueue it for the daemon')
|
|
220
|
+
# show_command_info('Use the bundled helper to enqueue control/action jobs:')
|
|
221
|
+
# puts "#{@colors[:command]}$ prg job send --daemon-name demo --advance#{@colors[:reset]}"
|
|
222
|
+
# puts "#{@colors[:command]}$ prg job send --daemon-name demo --percent 42#{@colors[:reset]}"
|
|
223
|
+
# puts
|
|
224
|
+
# show_command_info('Or enqueue a shell command:')
|
|
225
|
+
|
|
226
|
+
# # For the demo we run the worker in the foreground so you can see the
|
|
227
|
+
# # live animation and completion message inline. Daemon mode (started with
|
|
228
|
+
# # `--daemon` or `--daemon-as`) detaches to the background and processes
|
|
229
|
+
# # jobs via the file-based queue; `prg job send` targets a background
|
|
230
|
+
# # daemon and prints the job result JSON, but won't show the daemon's
|
|
231
|
+
# # animation in the foreground.
|
|
232
|
+
# show_command_info('Start a named fill daemon that processes percent/action jobs')
|
|
233
|
+
# # Start the fill daemon in non-detaching background mode so animation remains visible
|
|
234
|
+
# run_command("#{ruby_cmd} fill --daemon-as demo --no-detach --output-lines 3 --output-position top --success 'Captured!' --checkmark")
|
|
235
|
+
# pause_between_demos(1)
|
|
236
|
+
|
|
237
|
+
# show_command_info('We will enqueue several percent actions via a small shell script')
|
|
238
|
+
# demo_script = <<~BASH
|
|
239
|
+
# #!/usr/bin/env bash
|
|
240
|
+
# set -eu
|
|
241
|
+
# echo "Sending percent updates to demo daemon (atomic mktemp+mv writes)"
|
|
242
|
+
|
|
243
|
+
# job_dir="/tmp/ruby-progress/demo.jobs"
|
|
244
|
+
# mkdir -p "$job_dir"
|
|
245
|
+
|
|
246
|
+
# enqueue_percent() {
|
|
247
|
+
# percent=$1
|
|
248
|
+
# # Build JSON payload
|
|
249
|
+
# id=$(uuidgen 2>/dev/null || echo "job-$(date +%s%N)")
|
|
250
|
+
# tmp=$(mktemp "$job_dir/${id}.json.tmp.XXXXXX")
|
|
251
|
+
# printf '%s\n' '{"id":"'"${id}"'","action":"percent","value":'"${percent}"'}' > "$tmp"
|
|
252
|
+
# mv "$tmp" "$job_dir/${id}.json"
|
|
253
|
+
|
|
254
|
+
# # Wait for the daemon to process the job (poll for .processing.result)
|
|
255
|
+
# result_path="$job_dir/${id}.json.processing.result"
|
|
256
|
+
# start=$(date +%s)
|
|
257
|
+
# timeout=10
|
|
258
|
+
# while [ ! -f "$result_path" ]; do
|
|
259
|
+
# sleep 0.1
|
|
260
|
+
# now=$(date +%s)
|
|
261
|
+
# if [ $((now - start)) -gt $timeout ]; then
|
|
262
|
+
# echo "Timed out waiting for result for job ${id}" >&2
|
|
263
|
+
# return 2
|
|
264
|
+
# fi
|
|
265
|
+
# done
|
|
266
|
+
# cat "$result_path"
|
|
267
|
+
# }
|
|
268
|
+
|
|
269
|
+
# enqueue_percent 10
|
|
270
|
+
# sleep 1
|
|
271
|
+
# enqueue_percent 40
|
|
272
|
+
# sleep 1
|
|
273
|
+
# enqueue_percent 70
|
|
274
|
+
# sleep 1
|
|
275
|
+
# enqueue_percent 100
|
|
276
|
+
|
|
277
|
+
# # After updates, stop the daemon cleanly (call local bin/prg to avoid global conflicts)
|
|
278
|
+
# #{ruby_cmd} fill --stop-id demo --stop-success 'Demo daemon stopped'
|
|
279
|
+
# BASH
|
|
280
|
+
|
|
281
|
+
# # Show the simulated script contents
|
|
282
|
+
# puts "#{@colors[:command]}$ cat demo_percent_updates.sh#{@colors[:reset]}"
|
|
283
|
+
# puts demo_script
|
|
284
|
+
|
|
285
|
+
# # Write and execute the script (run in a subshell so output doesn't interleave too badly)
|
|
286
|
+
# script_path = File.join(Dir.tmpdir, "demo_percent_updates_#{Time.now.to_i}.sh")
|
|
287
|
+
# File.write(script_path, demo_script)
|
|
288
|
+
# File.chmod(0o755, script_path)
|
|
289
|
+
# run_command("bash #{Shellwords.escape(script_path)}")
|
|
290
|
+
# pause_between_demos
|
|
284
291
|
end
|
|
285
292
|
|
|
286
293
|
def show_finale
|
|
@@ -310,6 +317,7 @@ class ProgressDemo
|
|
|
310
317
|
|
|
311
318
|
def clear_screen
|
|
312
319
|
system('clear') || system('cls')
|
|
320
|
+
system('tput cup 15 0')
|
|
313
321
|
end
|
|
314
322
|
|
|
315
323
|
def show_title
|
|
@@ -357,7 +365,7 @@ class ProgressDemo
|
|
|
357
365
|
# - flags (tokens starting with '-') use @colors[:flag]
|
|
358
366
|
# - values use @colors[:value]
|
|
359
367
|
# The function prints one character at a time to simulate typing.
|
|
360
|
-
def type_command(line, speed: 0.
|
|
368
|
+
def type_command(line, speed: 0.02)
|
|
361
369
|
tokens = line.scan(/'[^']*'|"[^"]*"|\S+/)
|
|
362
370
|
pos = 0
|
|
363
371
|
|
|
@@ -412,7 +420,7 @@ class ProgressDemo
|
|
|
412
420
|
# sleep(seconds)
|
|
413
421
|
end
|
|
414
422
|
|
|
415
|
-
def pause_between_demos(seconds =
|
|
423
|
+
def pause_between_demos(seconds = 1)
|
|
416
424
|
# puts "#{@colors[:dim]}[Pausing #{seconds}s between demos...]#{@colors[:reset]}"
|
|
417
425
|
sleep(seconds)
|
|
418
426
|
end
|
|
@@ -5,7 +5,9 @@ require 'optparse'
|
|
|
5
5
|
module RubyProgress
|
|
6
6
|
module FillCLI
|
|
7
7
|
# Option parsing extracted to reduce module length in FillCLI
|
|
8
|
+
# rubocop:disable Metrics/AbcSize, Metrics/BlockLength
|
|
8
9
|
module Options
|
|
10
|
+
# rubocop :disable Metrics/MethodLength
|
|
9
11
|
def self.parse_cli_options
|
|
10
12
|
options = {
|
|
11
13
|
style: :blocks,
|
|
@@ -28,7 +30,6 @@ module RubyProgress
|
|
|
28
30
|
report: false
|
|
29
31
|
}
|
|
30
32
|
|
|
31
|
-
# rubocop:disable Metrics/BlockLength
|
|
32
33
|
begin
|
|
33
34
|
OptionParser.new do |opts|
|
|
34
35
|
opts.banner = 'Usage: prg fill [options]'
|
|
@@ -61,6 +62,10 @@ module RubyProgress
|
|
|
61
62
|
options[:output_lines] = n
|
|
62
63
|
end
|
|
63
64
|
|
|
65
|
+
opts.on('--stdout-live', 'Stream captured output to STDOUT as it arrives (non-blocking)') do
|
|
66
|
+
options[:stdout_live] = true
|
|
67
|
+
end
|
|
68
|
+
|
|
64
69
|
opts.separator ''
|
|
65
70
|
opts.separator 'Progress Control:'
|
|
66
71
|
|
|
@@ -198,7 +203,6 @@ module RubyProgress
|
|
|
198
203
|
options[:help] = true
|
|
199
204
|
end
|
|
200
205
|
end.parse!
|
|
201
|
-
# rubocop:enable Metrics/BlockLength
|
|
202
206
|
rescue OptionParser::InvalidOption => e
|
|
203
207
|
warn "Invalid option: #{e.args.first}"
|
|
204
208
|
warn ''
|
|
@@ -208,6 +212,7 @@ module RubyProgress
|
|
|
208
212
|
end
|
|
209
213
|
options
|
|
210
214
|
end
|
|
215
|
+
# rubocop :enable Metrics/MethodLength
|
|
211
216
|
|
|
212
217
|
def self.help_text
|
|
213
218
|
opts = OptionParser.new
|
|
@@ -261,5 +266,6 @@ module RubyProgress
|
|
|
261
266
|
opts.to_s
|
|
262
267
|
end
|
|
263
268
|
end
|
|
269
|
+
# rubocop:enable Metrics/AbcSize, Metrics/BlockLength
|
|
264
270
|
end
|
|
265
271
|
end
|
|
@@ -71,7 +71,12 @@ module RippleCLI
|
|
|
71
71
|
if $stdout.tty?
|
|
72
72
|
# Interactive TTY: use PTY-based capture so the animation can run while the
|
|
73
73
|
# command executes. We only print captured stdout if options[:output] == :stdout.
|
|
74
|
-
oc = RubyProgress::OutputCapture.new(
|
|
74
|
+
oc = RubyProgress::OutputCapture.new(
|
|
75
|
+
command: options[:command],
|
|
76
|
+
lines: options[:output_lines] || 3,
|
|
77
|
+
position: options[:output_position] || :above,
|
|
78
|
+
stream: options[:output] == :stdout || options[:stdout_live]
|
|
79
|
+
)
|
|
75
80
|
oc.start
|
|
76
81
|
|
|
77
82
|
# Create rippler. Attach output capture only when the user requested
|
|
@@ -91,6 +91,10 @@ module RippleCLI
|
|
|
91
91
|
options[:output] = :stdout
|
|
92
92
|
end
|
|
93
93
|
|
|
94
|
+
opts.on('--stdout-live', 'Stream captured output to STDOUT as it arrives (non-blocking)') do
|
|
95
|
+
options[:stdout_live] = true
|
|
96
|
+
end
|
|
97
|
+
|
|
94
98
|
opts.on('--quiet', 'Suppress all output') do
|
|
95
99
|
options[:output] = :quiet
|
|
96
100
|
end
|
|
@@ -23,11 +23,12 @@ module TwirlRunner
|
|
|
23
23
|
RubyProgress::Utils.hide_cursor
|
|
24
24
|
spinner_thread = Thread.new { loop { spinner.animate } }
|
|
25
25
|
|
|
26
|
-
if $stdout.tty? && options[:stdout]
|
|
26
|
+
if $stdout.tty? && (options[:stdout] || options[:stdout_live])
|
|
27
27
|
oc = RubyProgress::OutputCapture.new(
|
|
28
28
|
command: options[:command],
|
|
29
29
|
lines: options[:output_lines] || 3,
|
|
30
|
-
position: options[:output_position] || :above
|
|
30
|
+
position: options[:output_position] || :above,
|
|
31
|
+
stream: options[:stdout] || options[:stdout_live]
|
|
31
32
|
)
|
|
32
33
|
oc.start
|
|
33
34
|
|
|
@@ -110,7 +111,8 @@ module TwirlRunner
|
|
|
110
111
|
oc = RubyProgress::OutputCapture.new(
|
|
111
112
|
command: job['command'],
|
|
112
113
|
lines: options[:output_lines] || 3,
|
|
113
|
-
position: options[:output_position] || :above
|
|
114
|
+
position: options[:output_position] || :above,
|
|
115
|
+
stream: options[:stdout] || options[:stdout_live]
|
|
114
116
|
)
|
|
115
117
|
oc.start
|
|
116
118
|
|
|
@@ -57,11 +57,12 @@ module WormRunner
|
|
|
57
57
|
stdout_content = nil
|
|
58
58
|
|
|
59
59
|
begin
|
|
60
|
-
stdout_content = if $stdout.tty? && @output_stdout
|
|
60
|
+
stdout_content = if $stdout.tty? && (@output_stdout || @output_live)
|
|
61
61
|
oc = RubyProgress::OutputCapture.new(
|
|
62
62
|
command: @command,
|
|
63
63
|
lines: @output_lines || 3,
|
|
64
|
-
position: @output_position || :above
|
|
64
|
+
position: @output_position || :above,
|
|
65
|
+
stream: @output_live || false
|
|
65
66
|
)
|
|
66
67
|
oc.start
|
|
67
68
|
@output_capture = oc
|
|
@@ -233,8 +234,12 @@ module WormRunner
|
|
|
233
234
|
$stderr.print "\r\e[2K"
|
|
234
235
|
|
|
235
236
|
if (frame_count % 10).zero?
|
|
236
|
-
|
|
237
|
-
|
|
237
|
+
# Use ANSI save/restore to clear the previous line without moving the
|
|
238
|
+
# global cursor position. This prevents the animation from erasing
|
|
239
|
+
# reserved output lines that we draw elsewhere.
|
|
240
|
+
$stderr.print "\e7" # save
|
|
241
|
+
$stderr.print "\e[1A\e[2K\r"
|
|
242
|
+
$stderr.print "\e8" # restore
|
|
238
243
|
end
|
|
239
244
|
|
|
240
245
|
$stderr.print "#{message_part}#{generate_dots(position, direction)}"
|
|
@@ -136,7 +136,8 @@ module RubyProgress
|
|
|
136
136
|
command: job['command'],
|
|
137
137
|
lines: options[:output_lines] || 3,
|
|
138
138
|
position: options[:output_position] || :above,
|
|
139
|
-
log_path: log_path
|
|
139
|
+
log_path: log_path,
|
|
140
|
+
stream: options[:stdout_live]
|
|
140
141
|
)
|
|
141
142
|
oc.start
|
|
142
143
|
|
|
@@ -298,7 +299,8 @@ module RubyProgress
|
|
|
298
299
|
command: options[:command],
|
|
299
300
|
lines: options[:output_lines] || 3,
|
|
300
301
|
position: options[:output_position] || :above,
|
|
301
|
-
log_path: nil
|
|
302
|
+
log_path: nil,
|
|
303
|
+
stream: options[:stdout] || options[:stdout_live]
|
|
302
304
|
)
|
|
303
305
|
oc.start
|
|
304
306
|
|