ruby-progress 1.1.8 → 1.2.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 +4 -4
- data/CHANGELOG.md +67 -0
- data/Gemfile.lock +1 -1
- data/README.md +95 -19
- data/bin/prg +31 -7
- data/lib/ruby-progress/ripple.rb +4 -2
- data/lib/ruby-progress/utils.rb +16 -0
- data/lib/ruby-progress/version.rb +4 -4
- data/lib/ruby-progress/worm.rb +51 -8
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 35418d5ca6c2be425e6727b2480ce99da3baaa768991fc1a1e92bbcb15b54d37
|
|
4
|
+
data.tar.gz: 439632bfced82834cdd7157e33a84c187821436fa6ca3f1854627ab092c682bc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3def99d8f6d1bde28c3fc6a273fe0d8be65db3aabbd440a9bef8b165bd606e09872f8f216a73b186477cd4ef84f06bcfd728cd3a96eae23fdfc2114926827082
|
|
7
|
+
data.tar.gz: dda2ef12f24c66481e3280e23ba34932d7691edbdfa5ae503e3c1071a917158f126862df5b4b67ccb45b066523e0010b31298a4c6009dd296557cae190016367
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,73 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.2.0] - 2025-10-11
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **--ends flag for all commands**: New universal option to add start/end characters around animations
|
|
13
|
+
- Accepts even-length strings split in half for start and end characters
|
|
14
|
+
- Works across all three commands: ripple, worm, and twirl
|
|
15
|
+
- Examples: `--ends "[]"` → `[animation]`, `--ends "<<>>"` → `<<animation>>`
|
|
16
|
+
- Multi-byte character support for emojis: `--ends "🎯🎪"` → `🎯animation🎪`
|
|
17
|
+
- Graceful fallback for invalid input (odd-length strings)
|
|
18
|
+
|
|
19
|
+
- **Comprehensive test coverage for new features**: Added extensive test suites
|
|
20
|
+
- Direction control tests: Forward-only vs bidirectional animation behavior
|
|
21
|
+
- Custom style tests: ASCII, Unicode, emoji, and mixed character pattern validation
|
|
22
|
+
- CLI integration tests: End-to-end testing for all new command-line options
|
|
23
|
+
- Ends functionality tests: Multi-byte character handling, error cases, help documentation
|
|
24
|
+
- Total: 58 new test examples covering all edge cases
|
|
25
|
+
|
|
26
|
+
- **Worm direction control**: Fine-grained animation movement control
|
|
27
|
+
- `--direction forward` (or `-d f`): Animation moves only forward, resets at end
|
|
28
|
+
- `--direction bidirectional` (or `-d b`): Default back-and-forth movement
|
|
29
|
+
- Compatible with all worm styles including custom patterns
|
|
30
|
+
|
|
31
|
+
- **Worm custom styles**: User-defined 3-character animation patterns
|
|
32
|
+
- Format: `--style custom=abc` where `abc` defines baseline, midline, peak characters
|
|
33
|
+
- ASCII support: `--style custom=_-=` → `___-=___`
|
|
34
|
+
- Unicode support: `--style custom=▫▪■` → geometric patterns
|
|
35
|
+
- Emoji support: `--style custom=🟦🟨🟥` → colorful animations
|
|
36
|
+
- Mixed characters: `--style custom=.🟡*` → combined ASCII and emoji
|
|
37
|
+
- Proper multi-byte character counting for accurate 3-character validation
|
|
38
|
+
|
|
39
|
+
### Enhanced
|
|
40
|
+
|
|
41
|
+
- **Centralized utility functions**: Moved common functionality to `RubyProgress::Utils`
|
|
42
|
+
- `Utils.parse_ends()`: Universal start/end character parsing
|
|
43
|
+
- Eliminates code duplication across animation classes
|
|
44
|
+
- Consistent behavior and error handling
|
|
45
|
+
|
|
46
|
+
- **Documentation improvements**: Updated README with comprehensive examples
|
|
47
|
+
- New common options section highlighting universal flags
|
|
48
|
+
- Detailed --ends usage examples with various character patterns
|
|
49
|
+
- Enhanced help output for all commands
|
|
50
|
+
|
|
51
|
+
### Technical
|
|
52
|
+
|
|
53
|
+
- **Version management**: Bumped all component versions to reflect new features
|
|
54
|
+
- Main version: 1.1.9 → 1.2.0 (new feature addition)
|
|
55
|
+
- Worm version: 1.0.4 → 1.1.0 (direction control + custom styles)
|
|
56
|
+
- Ripple version: 1.0.5 → 1.1.0 (ends support)
|
|
57
|
+
- Twirl version: 1.0.1 → 1.1.0 (ends support)
|
|
58
|
+
|
|
59
|
+
## [1.1.9] - 2025-10-10
|
|
60
|
+
|
|
61
|
+
### Fixed
|
|
62
|
+
|
|
63
|
+
- **Worm animation line clearing**: Resolved issue where completion messages appeared alongside animation characters
|
|
64
|
+
- Fixed stream mismatch where animations used stderr but completion messages used stdout
|
|
65
|
+
- Implemented atomic operation combining line clearing and message output on stderr
|
|
66
|
+
- Ensured clean line clearing for all scenarios (success, error, no completion message)
|
|
67
|
+
- Updated tests to match new stderr-based completion message output
|
|
68
|
+
- Clean output format: animation disappears completely before completion message appears
|
|
69
|
+
|
|
70
|
+
### Technical
|
|
71
|
+
|
|
72
|
+
- **Stream consistency**: All worm animation output (including completion messages) now uses stderr consistently
|
|
73
|
+
- **Enhanced completion message display**: Single atomic stderr operation prevents race conditions between line clearing and message display
|
|
74
|
+
|
|
8
75
|
## [1.1.8] - 2025-10-10
|
|
9
76
|
|
|
10
77
|
### Added
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -29,6 +29,14 @@ prg twirl --message "Working..." --style dots --speed fast
|
|
|
29
29
|
prg worm --command "sleep 5" --success "Completed!" --error "Failed!" --checkmark
|
|
30
30
|
prg ripple "Building..." --command "make build" --success "Build complete!" --stdout
|
|
31
31
|
prg twirl --command "npm install" --message "Installing packages" --style arc
|
|
32
|
+
|
|
33
|
+
# With start/end character decoration using --ends
|
|
34
|
+
prg ripple "Loading data" --ends "[]" --style rainbow
|
|
35
|
+
prg worm --message "Processing" --ends "()" --style blocks
|
|
36
|
+
prg twirl --message "Building" --ends "<<>>" --style dots
|
|
37
|
+
|
|
38
|
+
# Complex --ends patterns with emojis
|
|
39
|
+
prg worm --message "Magic" --ends "🎯🎪" --style "custom=🟦🟨🟥"
|
|
32
40
|
```
|
|
33
41
|
|
|
34
42
|
### Global Options
|
|
@@ -38,7 +46,7 @@ prg twirl --command "npm install" --message "Installing packages" --style arc
|
|
|
38
46
|
- `prg --list-styles` - Show all available styles for all subcommands
|
|
39
47
|
- `prg <subcommand> --help` - Show specific subcommand help
|
|
40
48
|
|
|
41
|
-
### Common Options (available for
|
|
49
|
+
### Common Options (available for all subcommands)
|
|
42
50
|
|
|
43
51
|
- `--speed SPEED` - Animation speed (fast/medium/slow or f/m/s)
|
|
44
52
|
- `--message MESSAGE` - Message to display
|
|
@@ -47,6 +55,7 @@ prg twirl --command "npm install" --message "Installing packages" --style arc
|
|
|
47
55
|
- `--error MESSAGE` - Error message on failure
|
|
48
56
|
- `--checkmark` - Show checkmarks (✅ success, 🛑 failure)
|
|
49
57
|
- `--stdout` - Output command results to STDOUT
|
|
58
|
+
- `--ends CHARS` - Start/end characters (even number of chars, split in half)
|
|
50
59
|
|
|
51
60
|
### Daemon Mode (Background Progress)
|
|
52
61
|
|
|
@@ -304,25 +313,39 @@ Worm is a clean, Unicode-based progress indicator that creates a ripple effect u
|
|
|
304
313
|
|
|
305
314
|
```bash
|
|
306
315
|
# Run indefinitely without a command (like ripple)
|
|
307
|
-
|
|
316
|
+
prg worm --message "Loading..." --speed fast --style circles
|
|
308
317
|
|
|
309
318
|
# Run a command with progress animation
|
|
310
|
-
|
|
319
|
+
prg worm --command "sleep 5" --message "Installing" --success "Done!"
|
|
311
320
|
|
|
312
321
|
# Customize the animation
|
|
313
|
-
|
|
322
|
+
prg worm --command "make build" --speed fast --length 5 --style blocks
|
|
314
323
|
|
|
315
324
|
# With custom error handling
|
|
316
|
-
|
|
325
|
+
prg worm --command "risky_operation" --error "Operation failed" --style geometric
|
|
317
326
|
|
|
318
327
|
# With checkmarks for visual feedback
|
|
319
|
-
|
|
328
|
+
prg worm --command "npm install" --success "Installation complete!" --checkmark
|
|
329
|
+
|
|
330
|
+
# Control animation direction (forward-only or bidirectional)
|
|
331
|
+
prg worm --message "Processing" --direction forward --style circles
|
|
332
|
+
prg worm --command "sleep 3" --direction bidirectional --style blocks
|
|
333
|
+
|
|
334
|
+
# Create custom animations with 3-character patterns
|
|
335
|
+
prg worm --message "Custom style" --style "custom=_-=" --command "sleep 2"
|
|
336
|
+
prg worm --message "Emoji worm!" --style "custom=🟦🟨🟥" --success "Complete!"
|
|
337
|
+
prg worm --message "Mixed chars" --style "custom=.🟡*" --direction forward
|
|
338
|
+
|
|
339
|
+
# Add start/end characters around the animation
|
|
340
|
+
prg worm --message "Bracketed" --ends "[]" --style circles
|
|
341
|
+
prg worm --message "Parentheses" --ends "()" --style blocks --direction forward
|
|
342
|
+
prg worm --message "Emoji ends" --ends "🎯🎪" --style "custom=🟦🟨🟥"
|
|
320
343
|
|
|
321
344
|
# Capture and display command output
|
|
322
|
-
|
|
345
|
+
prg worm --command "git status" --message "Checking status" --stdout
|
|
323
346
|
|
|
324
347
|
# Combine checkmarks and stdout output
|
|
325
|
-
|
|
348
|
+
prg worm --command "echo 'Build output'" --success "Build complete!" --checkmark --stdout
|
|
326
349
|
```
|
|
327
350
|
|
|
328
351
|
#### Daemon mode (background indicator)
|
|
@@ -351,15 +374,25 @@ Note: You don’t need `&` when starting the daemon. The command detaches itself
|
|
|
351
374
|
|
|
352
375
|
#### Worm Command Line Options
|
|
353
376
|
|
|
354
|
-
| Option | Description
|
|
355
|
-
| ----------------------- |
|
|
356
|
-
| `-s, --speed SPEED` | Animation speed (1-10, fast/medium/slow, or f/m/s)
|
|
357
|
-
| `-l, --length LENGTH` | Number of dots to display
|
|
358
|
-
| `-m, --message MESSAGE` | Message to display before animation
|
|
359
|
-
| `--style STYLE` | Animation style (blocks/geometric
|
|
360
|
-
|
|
|
361
|
-
| `--
|
|
362
|
-
|
|
|
377
|
+
| Option | Description |
|
|
378
|
+
| ----------------------- | ---------------------------------------------------------- |
|
|
379
|
+
| `-s, --speed SPEED` | Animation speed (1-10, fast/medium/slow, or f/m/s) |
|
|
380
|
+
| `-l, --length LENGTH` | Number of dots to display |
|
|
381
|
+
| `-m, --message MESSAGE` | Message to display before animation |
|
|
382
|
+
| `--style STYLE` | Animation style (circles/blocks/geometric or custom=XXX) |
|
|
383
|
+
| `--direction DIR` | Animation direction (forward/bidirectional or f/b) |
|
|
384
|
+
| `--ends CHARS` | Start/end characters (even number of chars, split in half) |
|
|
385
|
+
| `-c, --command COMMAND` | Command to run (optional) |
|
|
386
|
+
| `--success TEXT` | Text to display on successful completion |
|
|
387
|
+
| `--error TEXT` | Text to display on error |
|
|
388
|
+
| `--checkmark` | Show checkmarks (✅ for success, 🛑 for failure) |
|
|
389
|
+
| `--stdout` | Output captured command result to STDOUT |
|
|
390
|
+
| `--daemon` | Run in background daemon mode |
|
|
391
|
+
| `--daemon-as NAME` | Run in daemon mode with custom name |
|
|
392
|
+
| `--stop` | Stop a running daemon |
|
|
393
|
+
| `--stop-id NAME` | Stop daemon by name (implies --stop) |
|
|
394
|
+
| `--status` | Check daemon status |
|
|
395
|
+
| `--status-id NAME` | Check daemon status by name |
|
|
363
396
|
|
|
364
397
|
### Worm Library Usage
|
|
365
398
|
|
|
@@ -371,7 +404,8 @@ worm = RubyProgress::Worm.new(
|
|
|
371
404
|
length: 4,
|
|
372
405
|
message: "Processing",
|
|
373
406
|
speed: 'fast',
|
|
374
|
-
style: 'circles'
|
|
407
|
+
style: 'circles',
|
|
408
|
+
direction: :bidirectional
|
|
375
409
|
)
|
|
376
410
|
|
|
377
411
|
result = worm.animate(
|
|
@@ -382,6 +416,15 @@ result = worm.animate(
|
|
|
382
416
|
some_long_running_task
|
|
383
417
|
end
|
|
384
418
|
|
|
419
|
+
# With custom style and forward direction
|
|
420
|
+
worm = RubyProgress::Worm.new(
|
|
421
|
+
message: "Custom animation",
|
|
422
|
+
style: 'custom=🔴🟡🟢',
|
|
423
|
+
direction: :forward
|
|
424
|
+
)
|
|
425
|
+
|
|
426
|
+
result = worm.animate { sleep 3 }
|
|
427
|
+
|
|
385
428
|
# Or run with a command
|
|
386
429
|
worm = RubyProgress::Worm.new(command: "bundle install")
|
|
387
430
|
worm.run_with_command
|
|
@@ -389,7 +432,7 @@ worm.run_with_command
|
|
|
389
432
|
|
|
390
433
|
### Animation Styles
|
|
391
434
|
|
|
392
|
-
Worm supports three built-in animation styles:
|
|
435
|
+
Worm supports three built-in animation styles plus custom patterns:
|
|
393
436
|
|
|
394
437
|
#### Circles
|
|
395
438
|
|
|
@@ -409,6 +452,39 @@ Worm supports three built-in animation styles:
|
|
|
409
452
|
- Midline: `▫` (small white square)
|
|
410
453
|
- Peak: `■` (large black square)
|
|
411
454
|
|
|
455
|
+
#### Custom Styles
|
|
456
|
+
|
|
457
|
+
Create your own animation patterns using the `custom=XXX` format, where `XXX` is a 3-character pattern representing baseline, midline, and peak states:
|
|
458
|
+
|
|
459
|
+
```bash
|
|
460
|
+
# ASCII characters
|
|
461
|
+
prg worm --style "custom=_-=" --message "Custom ASCII"
|
|
462
|
+
|
|
463
|
+
# Unicode characters
|
|
464
|
+
prg worm --style "custom=▫▪■" --message "Custom geometric"
|
|
465
|
+
|
|
466
|
+
# Emojis (supports multi-byte characters)
|
|
467
|
+
prg worm --style "custom=🟦🟨🟥" --message "Color progression"
|
|
468
|
+
|
|
469
|
+
# Mixed ASCII and emoji
|
|
470
|
+
prg worm --style "custom=.🟡*" --message "Mixed characters"
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
The custom format requires exactly 3 characters and supports:
|
|
474
|
+
- ASCII characters
|
|
475
|
+
- Unicode symbols and shapes
|
|
476
|
+
- Emojis (properly handled as single characters)
|
|
477
|
+
- Mixed combinations of the above
|
|
478
|
+
|
|
479
|
+
#### Direction Control
|
|
480
|
+
|
|
481
|
+
Control the animation movement pattern:
|
|
482
|
+
|
|
483
|
+
- `--direction forward` (or `-d f`): Animation moves only forward
|
|
484
|
+
- `--direction bidirectional` (or `-d b`): Animation moves back and forth (default)
|
|
485
|
+
|
|
486
|
+
This works with all animation styles including custom patterns.
|
|
487
|
+
|
|
412
488
|
---
|
|
413
489
|
|
|
414
490
|
## Requirements
|
data/bin/prg
CHANGED
|
@@ -68,11 +68,18 @@ module PrgCLI
|
|
|
68
68
|
--show-styles Show visual previews of all styles for all subcommands
|
|
69
69
|
--stop-all Stop all prg processes
|
|
70
70
|
|
|
71
|
+
COMMON OPTIONS (available for all subcommands):
|
|
72
|
+
--ends CHARS Start/end characters (even number split in half)
|
|
73
|
+
--speed SPEED Animation speed (fast/medium/slow)
|
|
74
|
+
--message TEXT Message to display with animation
|
|
75
|
+
--checkmark Show checkmarks for success/failure
|
|
76
|
+
--command CMD Execute command during animation
|
|
77
|
+
|
|
71
78
|
EXAMPLES:
|
|
72
|
-
prg ripple "Loading..." --style rainbow --speed fast
|
|
73
|
-
prg worm --message "Processing" --style blocks --checkmark
|
|
74
|
-
prg twirl --message "Spinning" --style dots --checkmark
|
|
75
|
-
prg ripple --command "sleep 3" --success "Done!" --checkmark
|
|
79
|
+
prg ripple "Loading..." --style rainbow --speed fast --ends "[]"
|
|
80
|
+
prg worm --message "Processing" --style blocks --checkmark --ends "()"
|
|
81
|
+
prg twirl --message "Spinning" --style dots --checkmark --ends "<<>>"
|
|
82
|
+
prg ripple --command "sleep 3" --success "Done!" --checkmark --ends "{}"
|
|
76
83
|
|
|
77
84
|
Run 'prg <subcommand> --help' for specific subcommand options.
|
|
78
85
|
HELP
|
|
@@ -304,6 +311,10 @@ module RippleCLI
|
|
|
304
311
|
options[:format] = f =~ /^f/i ? :forward_only : :bidirectional
|
|
305
312
|
end
|
|
306
313
|
|
|
314
|
+
opts.on('--ends CHARS', 'Start/end characters (even number of chars, split in half)') do |chars|
|
|
315
|
+
options[:ends] = chars
|
|
316
|
+
end
|
|
317
|
+
|
|
307
318
|
opts.separator ''
|
|
308
319
|
opts.separator 'Command Execution:'
|
|
309
320
|
|
|
@@ -611,10 +622,18 @@ module WormCLI
|
|
|
611
622
|
options[:length] = length
|
|
612
623
|
end
|
|
613
624
|
|
|
614
|
-
opts.on('--style STYLE', 'Animation style (circles/blocks/geometric
|
|
625
|
+
opts.on('--style STYLE', 'Animation style (circles/blocks/geometric, c/b/g, or custom=abc)') do |style|
|
|
615
626
|
options[:style] = style
|
|
616
627
|
end
|
|
617
628
|
|
|
629
|
+
opts.on('-d', '--direction DIRECTION', 'Animation direction (forward/bidirectional or f/b)') do |direction|
|
|
630
|
+
options[:direction] = direction =~ /^f/i ? :forward_only : :bidirectional
|
|
631
|
+
end
|
|
632
|
+
|
|
633
|
+
opts.on('--ends CHARS', 'Start/end characters (even number of chars, split in half)') do |chars|
|
|
634
|
+
options[:ends] = chars
|
|
635
|
+
end
|
|
636
|
+
|
|
618
637
|
opts.separator ''
|
|
619
638
|
opts.separator 'Command Execution:'
|
|
620
639
|
|
|
@@ -894,6 +913,10 @@ module TwirlCLI
|
|
|
894
913
|
options[:style] = style
|
|
895
914
|
end
|
|
896
915
|
|
|
916
|
+
opts.on('--ends CHARS', 'Start/end characters (even number of chars, split in half)') do |chars|
|
|
917
|
+
options[:ends] = chars
|
|
918
|
+
end
|
|
919
|
+
|
|
897
920
|
opts.separator ''
|
|
898
921
|
opts.separator 'Command Execution:'
|
|
899
922
|
|
|
@@ -1003,14 +1026,15 @@ class TwirlSpinner
|
|
|
1003
1026
|
@style = parse_style(options[:style] || 'dots')
|
|
1004
1027
|
@speed = parse_speed(options[:speed] || 'medium')
|
|
1005
1028
|
@frames = RubyProgress::INDICATORS[@style] || RubyProgress::INDICATORS[:dots]
|
|
1029
|
+
@start_chars, @end_chars = RubyProgress::Utils.parse_ends(options[:ends])
|
|
1006
1030
|
@index = 0
|
|
1007
1031
|
end
|
|
1008
1032
|
|
|
1009
1033
|
def animate
|
|
1010
1034
|
if @message && !@message.empty?
|
|
1011
|
-
$stderr.print "\r\e[2K#{@message} #{@frames[@index]}"
|
|
1035
|
+
$stderr.print "\r\e[2K#{@start_chars}#{@message} #{@frames[@index]}#{@end_chars}"
|
|
1012
1036
|
else
|
|
1013
|
-
$stderr.print "\r\e[2K#{@frames[@index]}"
|
|
1037
|
+
$stderr.print "\r\e[2K#{@start_chars}#{@frames[@index]}#{@end_chars}"
|
|
1014
1038
|
end
|
|
1015
1039
|
$stderr.flush
|
|
1016
1040
|
@index = (@index + 1) % @frames.length
|
data/lib/ruby-progress/ripple.rb
CHANGED
|
@@ -93,7 +93,8 @@ module RubyProgress
|
|
|
93
93
|
spinner_position: false,
|
|
94
94
|
caps: false,
|
|
95
95
|
inverse: false,
|
|
96
|
-
output: :error
|
|
96
|
+
output: :error,
|
|
97
|
+
ends: nil
|
|
97
98
|
}
|
|
98
99
|
@options = defaults.merge(options)
|
|
99
100
|
@string = string
|
|
@@ -104,6 +105,7 @@ module RubyProgress
|
|
|
104
105
|
@spinner_position = @options[:spinner_position]
|
|
105
106
|
@caps = @options[:caps]
|
|
106
107
|
@inverse = @options[:inverse]
|
|
108
|
+
@start_chars, @end_chars = RubyProgress::Utils.parse_ends(@options[:ends])
|
|
107
109
|
end
|
|
108
110
|
|
|
109
111
|
def printout
|
|
@@ -138,7 +140,7 @@ module RubyProgress
|
|
|
138
140
|
char = @rainbow ? char.rainbow(i) : char.extend(StringExtensions).light_white
|
|
139
141
|
post = letters.slice!(0, letters.length).join.extend(StringExtensions).dark_white
|
|
140
142
|
end
|
|
141
|
-
$stderr.print "\r\e[2K#{pre}#{char}#{post}"
|
|
143
|
+
$stderr.print "\r\e[2K#{@start_chars}#{pre}#{char}#{post}#{@end_chars}"
|
|
142
144
|
$stderr.flush
|
|
143
145
|
end
|
|
144
146
|
|
data/lib/ruby-progress/utils.rb
CHANGED
|
@@ -61,5 +61,21 @@ module RubyProgress
|
|
|
61
61
|
clear_line(output_stream) if output_stream != :warn # warn already includes clear in display_completion
|
|
62
62
|
display_completion(message, success: success, show_checkmark: show_checkmark, output_stream: output_stream)
|
|
63
63
|
end
|
|
64
|
+
|
|
65
|
+
# Parse start/end characters for animation wrapping
|
|
66
|
+
# @param ends_string [String] Even-length string to split in half for start/end chars
|
|
67
|
+
# @return [Array<String>] Array with [start_chars, end_chars]
|
|
68
|
+
def self.parse_ends(ends_string)
|
|
69
|
+
return ['', ''] unless ends_string && !ends_string.empty?
|
|
70
|
+
|
|
71
|
+
chars = ends_string.each_char.to_a
|
|
72
|
+
return ['', ''] if chars.length.odd? || chars.empty?
|
|
73
|
+
|
|
74
|
+
mid_point = chars.length / 2
|
|
75
|
+
start_chars = chars[0...mid_point].join
|
|
76
|
+
end_chars = chars[mid_point..-1].join
|
|
77
|
+
|
|
78
|
+
[start_chars, end_chars]
|
|
79
|
+
end
|
|
64
80
|
end
|
|
65
81
|
end
|
data/lib/ruby-progress/worm.rb
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require 'optparse'
|
|
4
4
|
require 'open3'
|
|
5
5
|
require 'json'
|
|
6
|
+
require_relative 'utils'
|
|
6
7
|
|
|
7
8
|
module RubyProgress
|
|
8
9
|
# Animated progress indicator with ripple effect using Unicode combining characters
|
|
@@ -63,6 +64,8 @@ module RubyProgress
|
|
|
63
64
|
@error_text = options[:error]
|
|
64
65
|
@show_checkmark = options[:checkmark] || false
|
|
65
66
|
@output_stdout = options[:stdout] || false
|
|
67
|
+
@direction_mode = options[:direction] || :bidirectional
|
|
68
|
+
@start_chars, @end_chars = RubyProgress::Utils.parse_ends(options[:ends])
|
|
66
69
|
@running = false
|
|
67
70
|
end
|
|
68
71
|
|
|
@@ -101,7 +104,8 @@ module RubyProgress
|
|
|
101
104
|
display_completion_message(@error_text || "Error: #{e.message}", false)
|
|
102
105
|
nil # Return nil instead of re-raising when used as a progress indicator
|
|
103
106
|
ensure
|
|
104
|
-
# Always
|
|
107
|
+
# Always clear animation line and restore cursor
|
|
108
|
+
$stderr.print "\r\e[2K"
|
|
105
109
|
RubyProgress::Utils.show_cursor
|
|
106
110
|
Signal.trap('INT', original_int_handler) if original_int_handler
|
|
107
111
|
end
|
|
@@ -224,7 +228,7 @@ module RubyProgress
|
|
|
224
228
|
@direction ||= 1
|
|
225
229
|
|
|
226
230
|
message_part = @message && !@message.empty? ? "#{@message} " : ''
|
|
227
|
-
$stderr.print "\r\e[2K#{message_part}#{generate_dots(@position, @direction)}"
|
|
231
|
+
$stderr.print "\r\e[2K#{@start_chars}#{message_part}#{generate_dots(@position, @direction)}#{@end_chars}"
|
|
228
232
|
$stderr.flush
|
|
229
233
|
|
|
230
234
|
sleep @speed
|
|
@@ -232,7 +236,11 @@ module RubyProgress
|
|
|
232
236
|
# Update position and direction
|
|
233
237
|
@position += @direction
|
|
234
238
|
if @position >= @length - 1
|
|
235
|
-
@
|
|
239
|
+
if @direction_mode == :forward_only
|
|
240
|
+
@position = 0
|
|
241
|
+
else
|
|
242
|
+
@direction = -1
|
|
243
|
+
end
|
|
236
244
|
elsif @position <= 0
|
|
237
245
|
@direction = 1
|
|
238
246
|
end
|
|
@@ -248,7 +256,8 @@ module RubyProgress
|
|
|
248
256
|
mark = success ? '✅ ' : '🛑 '
|
|
249
257
|
end
|
|
250
258
|
|
|
251
|
-
|
|
259
|
+
# Clear animation line and output completion message on stderr
|
|
260
|
+
$stderr.print "\r\e[2K#{mark}#{message}\n"
|
|
252
261
|
end
|
|
253
262
|
|
|
254
263
|
def parse_speed(speed_input)
|
|
@@ -282,7 +291,15 @@ module RubyProgress
|
|
|
282
291
|
def parse_style(style_input)
|
|
283
292
|
return RIPPLE_STYLES['circles'] unless style_input && !style_input.to_s.strip.empty?
|
|
284
293
|
|
|
285
|
-
|
|
294
|
+
style_str = style_input.to_s.strip
|
|
295
|
+
|
|
296
|
+
# Check for custom style format: custom=abc or custom_abc or customXabc
|
|
297
|
+
if style_str.match(/^custom[_=](.+)$/i)
|
|
298
|
+
custom_chars = Regexp.last_match(1)
|
|
299
|
+
return parse_custom_style(custom_chars)
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
style_lower = style_str.downcase
|
|
286
303
|
|
|
287
304
|
# First, try exact match
|
|
288
305
|
return RIPPLE_STYLES[style_lower] if RIPPLE_STYLES.key?(style_lower)
|
|
@@ -336,6 +353,24 @@ module RubyProgress
|
|
|
336
353
|
RIPPLE_STYLES['circles']
|
|
337
354
|
end
|
|
338
355
|
|
|
356
|
+
def parse_custom_style(custom_chars)
|
|
357
|
+
# Split into individual characters, properly handling multi-byte characters (emojis)
|
|
358
|
+
chars = custom_chars.each_char.to_a
|
|
359
|
+
|
|
360
|
+
# Ensure we have exactly 3 characters
|
|
361
|
+
if chars.length != 3
|
|
362
|
+
# Fallback to default if not exactly 3 characters
|
|
363
|
+
return RIPPLE_STYLES['circles']
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
# Create custom style hash with baseline, midline, peak
|
|
367
|
+
{
|
|
368
|
+
baseline: chars[0],
|
|
369
|
+
midline: chars[1],
|
|
370
|
+
peak: chars[2]
|
|
371
|
+
}
|
|
372
|
+
end
|
|
373
|
+
|
|
339
374
|
def animation_loop
|
|
340
375
|
position = 0
|
|
341
376
|
direction = 1
|
|
@@ -343,14 +378,18 @@ module RubyProgress
|
|
|
343
378
|
while @running
|
|
344
379
|
message_part = @message && !@message.empty? ? "#{@message} " : ''
|
|
345
380
|
# Enhanced line clearing for better daemon mode behavior
|
|
346
|
-
$stderr.print "\r\e[2K#{message_part}#{generate_dots(position, direction)}"
|
|
381
|
+
$stderr.print "\r\e[2K#{@start_chars}#{message_part}#{generate_dots(position, direction)}#{@end_chars}"
|
|
347
382
|
$stderr.flush
|
|
348
383
|
|
|
349
384
|
sleep @speed
|
|
350
385
|
|
|
351
386
|
position += direction
|
|
352
387
|
if position >= @length - 1
|
|
353
|
-
|
|
388
|
+
if @direction_mode == :forward_only
|
|
389
|
+
position = 0
|
|
390
|
+
else
|
|
391
|
+
direction = -1
|
|
392
|
+
end
|
|
354
393
|
elsif position <= 0
|
|
355
394
|
direction = 1
|
|
356
395
|
end
|
|
@@ -383,7 +422,11 @@ module RubyProgress
|
|
|
383
422
|
|
|
384
423
|
position += direction
|
|
385
424
|
if position >= @length - 1
|
|
386
|
-
|
|
425
|
+
if @direction_mode == :forward_only
|
|
426
|
+
position = 0
|
|
427
|
+
else
|
|
428
|
+
direction = -1
|
|
429
|
+
end
|
|
387
430
|
elsif position <= 0
|
|
388
431
|
direction = 1
|
|
389
432
|
end
|