Module: RubyProgress::Utils

Defined in:
lib/ruby-progress/utils.rb

Overview

Universal terminal utilities shared between progress indicators

Class Method Summary collapse

Class Method Details

.clear_line(output_stream = :stderr) ⇒ Object



15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/ruby-progress/utils.rb', line 15

def self.clear_line(output_stream = :stderr)
  io = case output_stream
       when :stdout
         $stdout
       when :stderr
         $stderr
       else
         # allow passing an IO-like object (e.g. StringIO) directly
         output_stream.respond_to?(:print) ? output_stream : $stderr
       end

  io.print "\r\e[K"
end

.clear_line_aggressiveObject

Enhanced line clearing for daemon mode that handles output interruption



30
31
32
33
34
# File 'lib/ruby-progress/utils.rb', line 30

def self.clear_line_aggressive
  $stderr.print "\r\e[2K"    # Clear entire current line
  $stderr.print "\e[1A\e[2K" # Move up one line and clear it too
  $stderr.print "\r"         # Return to start of line
end

.complete_with_clear(message, success: true, show_checkmark: false, output_stream: :warn, icons: {}) ⇒ Object

Clear current line and display completion message Convenience method that combines line clearing with message display



92
93
94
95
# File 'lib/ruby-progress/utils.rb', line 92

def self.complete_with_clear(message, success: true, show_checkmark: false, output_stream: :warn, icons: {})
  clear_line(output_stream) if output_stream != :warn # warn already includes clear in display_completion
  display_completion(message, success: success, show_checkmark: show_checkmark, output_stream: output_stream, icons: icons)
end

.display_completion(message, success: true, show_checkmark: false, output_stream: :warn, icons: {}) ⇒ Object

Universal completion message display

Parameters:

  • message (String)

    The message to display

  • success (Boolean) (defaults to: true)

    Whether this represents success or failure

  • show_checkmark (Boolean) (defaults to: false)

    Whether to show checkmark/X symbols

  • output_stream (Symbol) (defaults to: :warn)

    Where to output (:stdout, :stderr, :warn)



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/ruby-progress/utils.rb', line 41

def self.display_completion(message, success: true, show_checkmark: false, output_stream: :warn, icons: {})
  return unless message

  # Determine the mark to show. If checkmarks are enabled, prefer the
  # default icons but allow overrides via icons hash. If checkmarks are not
  # enabled, still show a custom icon when provided via CLI options.
  mark = ''
  if show_checkmark
    icon = success ? (icons[:success] || '') : (icons[:error] || '🛑')
    mark = "#{icon} "
  else
    custom_icon = success ? icons[:success] : icons[:error]
    mark = custom_icon ? "#{custom_icon} " : ''
  end

  formatted_message = "#{mark}#{message}"

  # Resolve destination IO: support symbols (:stdout/:stderr/:warn) or an IO-like object
  dest_io = case output_stream
            when :stdout
              $stdout
            when :stderr
              $stderr
            when :warn
              $stderr
            else
              output_stream.respond_to?(:print) ? output_stream : $stderr
            end

  # Only treat explicit :stdout and :stderr as non-clearing requests.
  # For :warn and any other/custom stream, clear the current line first.
  unless %i[stdout stderr].include?(output_stream)
    # Always include a leading carriage return when clearing to match
    # terminal behavior expected by the test-suite.
    dest_io.print "\r\e[2K"
    dest_io.flush if dest_io.respond_to?(:flush)
  end

  # Emit the message to the resolved destination IO. Use warn/puts when targeting
  # the standard streams to preserve familiar behavior (warn writes to $stderr).
  if dest_io == $stdout
    $stdout.puts formatted_message
  elsif dest_io == $stderr
    warn formatted_message
  else
    dest_io.puts formatted_message
  end
end

.ends_valid?(ends_string) ⇒ Boolean

Validate ends string: must be non-empty and even-length (handles multi-byte chars)

Returns:

  • (Boolean)


114
115
116
117
118
119
# File 'lib/ruby-progress/utils.rb', line 114

def self.ends_valid?(ends_string)
  return false unless ends_string && !ends_string.empty?

  chars = ends_string.each_char.to_a
  !chars.empty? && (chars.length % 2).zero?
end

.hide_cursorObject

Terminal cursor control



7
8
9
# File 'lib/ruby-progress/utils.rb', line 7

def self.hide_cursor
  $stderr.print "\e[?25l"
end

.parse_ends(ends_string) ⇒ Array<String>

Parse start/end characters for animation wrapping

Parameters:

  • ends_string (String)

    Even-length string to split in half for start/end chars

Returns:

  • (Array<String>)

    Array with [start_chars, end_chars]



100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/ruby-progress/utils.rb', line 100

def self.parse_ends(ends_string)
  return ['', ''] unless ends_string && !ends_string.empty?

  chars = ends_string.each_char.to_a
  return ['', ''] if chars.length.odd? || chars.empty?

  mid_point = chars.length / 2
  start_chars = chars[0...mid_point].join
  end_chars = chars[mid_point..-1].join

  [start_chars, end_chars]
end

.show_cursorObject



11
12
13
# File 'lib/ruby-progress/utils.rb', line 11

def self.show_cursor
  $stderr.print "\e[?25h"
end