module Colours::RainbowColours

Constants

DEFAULT_RAINBOW_SPREAD
#

DEFAULT_RAINBOW_SPREAD

#
STRIP_ANSI
#

Colours::RainbowColours::STRIP_ANSI

Checking for escape sequences (and a number).

Official documentation can be seen here:

https://ruby-doc.org/core/Regexp.html#method-c-new
#

Public Class Methods

check_for_trollop_being_available_or_exit() click to toggle source
#

Colours::RainbowColours.check_for_trollop_being_available_or_exit

#
# File lib/colours/rainbow_colours/check_for_trollop_being_available_or_exit.rb, line 12
def self.check_for_trollop_being_available_or_exit
  # ======================================================================= #
  # First check whether the user has the Trollop gem installed.
  # ======================================================================= #
  unless Object.const_defined? :Trollop
    e
    e 'Trollop is not installed. Please install it via:'
    e
    e '  gem install trollop'
    e
    exit
  end
end
do_parse_via_rainbow_colours( i = ARGV ) click to toggle source
#

Colours::RainbowColours.do_parse_via_rainbow_colours

This is the rainbow_colours initializer.

#
# File lib/colours/rainbow_colours/do_parse_via_rainbow_colours.rb, line 37
  def self.do_parse_via_rainbow_colours(
      i = ARGV
    )
    check_for_trollop_being_available_or_exit
    # ======================================================================= #
    # Setup the trollop-parser instance next.
    # ======================================================================= #
    trollop_parser = Trollop::Parser.new {
      banner <<HEADER

Usage: rainbow_colours [OPTION]... [FILE]...

Display one or several files. Alternatively, obtain input via STDIN.

With no FILE, or when FILE is -, read standard input.

HEADER
      banner ''
      # ll | rainbowc -a
      opt :animate,   'Enable psychedelics',        short: 'a', :default => false
      opt :spread,    'Rainbow spread',             short: 'p', :default => DEFAULT_RAINBOW_SPREAD
      opt :freq,      'Rainbow frequency',          short: 'F', :default => 0.1
      opt :seed,      'Rainbow seed, 0 = random',   short: 'S', :default => 0
      opt :duration,  'Animation duration',         short: 'd', :default => 12
      opt :speed,     'Animation speed',            short: 's', :default => 20.0
      opt :invert,    'Invert fg and bg',           short: 'i', :default => false
      opt :truecolor, '24-bit (truecolor)',         short: 't', :default => false
      opt :force,     'Force color even when stdout is not a tty', short: 'f', :default => false
      opt :help,      'Show this help menu',        short: 'h'
      banner <<FOOTER

Examples:

  rainbow_colours f - g      Output f's contents, then stdin, then g's contents.
  rainbow_colours            Copy standard input to standard output.
  fortune | rainbow_colours  Display a rainbow cookie.

FOOTER
    } # End of the help-banner.
    # ======================================================================= #
    # Keep the Trollop instance assigned to the variable opts.
    # ======================================================================= #
    opts = Trollop.with_standard_exception_handling(trollop_parser) {
      begin
        o = trollop_parser.parse(i) # Parse the given input here.
      rescue Trollop::HelpNeeded # If we need some more help.
        string_io_buffer = StringIO.new
        trollop_parser.educate(string_io_buffer) # <- display the help message and then exit.
        string_io_buffer.rewind
        opts = {
          animate:  false,
          speed:     20,
          duration:  12,
          os:       rand(256),
          spread:   8.0,
          freq:     0.3
        }
        splitted = string_io_buffer.read.split("\n")
        ::Colours.cat(splitted, opts)
        e
        string_io_buffer.close # Close the buffer again.
        exit 1
      end
      o
    }

    p.die(:spread,   'must be >= 0.1') if opts[:spread]   < 0.1
    p.die(:duration, 'must be >= 0.1') if opts[:duration] < 0.1
    p.die(:speed,    'must be >= 0.1') if opts[:speed]    < 0.1

    # ======================================================================= #
    # Build up the option-hash next.
    # ======================================================================= #
    opts[:os] = opts[:seed]
    opts[:os] = rand(256) if opts[:os] == 0

    begin
      if ARGV.empty?
        files = [:stdin]
      else
        files = ARGV[0..-1]
      end
      files.each { |file|
        case file
        when '-', :stdin
          fd = ARGF
        end
        begin
          fd = File.open(file) unless fd == ARGF
          if $stdout.tty? or opts[:force]
            # =============================================================== #
            # Work on TTY terminals. This also includes terminals such
            # as KDE Konsole. The second argument are the options passed
            # towards Colours.cat().
            # =============================================================== #
            ::Colours.cat(fd, opts)
          else
            until fd.eof? do
              # ============================================================= #
              # Keep on writing the input to $stdout here.
              # ============================================================= #
              $stdout.write(fd.read(8192))
            end
          end
        rescue Errno::ENOENT
          report_no_such_file_or_directory(file)
          exit 1
        rescue Errno::EACCES
          report_permission_denied(file)
          exit 1
        rescue Errno::EISDIR
          report_is_a_directory(file)
          exit 1
        rescue Errno::EPIPE
          exit 1
        end
      }
    rescue Interrupt
    end
  end
e(i = '') click to toggle source
#

Colours::RainbowColours.e

#
# File lib/colours/rainbow_colours/print_rainbow_line.rb, line 18
def self.e(i = '')
  ::Colours.e(i)
end
print_rainbow_line( string = 'Hello world!', defaults = {}, options_hash = {} ) click to toggle source
#

Colours::RainbowColours.print_rainbow_line

This line will do the colourizing part, on a per-line basis.

The second and third arguments are Hashes.

Simple invocation example:

Colours::RainbowColours.print_rainbow_line("Hello world! \n" * 80)
#
println_ani( str, opts = {} ) click to toggle source
#

Colours::RainbowColours.println_ani

This method here will be called if the “animate option” was enabled, that is, set to true.

#
# File lib/colours/rainbow_colours/println_ani.rb, line 17
def self.println_ani(
    str, opts = {}
  )
  return if str.empty? # Return early in this case.
  (1..opts[:duration]).each { |irrelevant_variable|
    print "\e[#{str.length}D"
    opts[:os] += opts[:spread]
    # ===================================================================== #
    # Next, delegate to println_plain():
    # ===================================================================== #
    println_plain(str, opts)
    sleep 1.0/opts[:speed]
  }
end
println_plain( str = "Hello world! Good morning sunshine.\n", defaults = {}, opts = { spread: DEFAULT_RAINBOW_SPREAD, os: rand(256), truecolor: true } ) click to toggle source
#

Colours::RainbowColours.println_plain

This method will colourize the given input line.

Usage example:

Colours::RainbowColours.println_plain
Colours::RainbowColours.println_plain 'one two three four five six seven eight'
#
# File lib/colours/rainbow_colours/println_plain.rb, line 24
def self.println_plain(
    str      = "Hello world! Good morning sunshine.\n",
    defaults = {},
    opts     = {
      spread:    DEFAULT_RAINBOW_SPREAD,
      os:        rand(256),
      truecolor: true
    }
  )
  print returnln_plain(str, defaults, opts)
end
rainbow( frequency = 0.1, i ) click to toggle source
#

Colours::RainbowColours.rainbow

Do the colour calculations next, via the rainbow() method.

The frequency is typically a value such as 0.1.

We will calculate the RGB values here (R, G, B).

Invocation example:

Colours::RainbowColours.rainbow(:default, 3)  # => "#A5D604"
Colours::RainbowColours.rainbow(:default, 12) # => "#F66C1C"
#
# File lib/colours/rainbow_colours/rainbow.rb, line 24
def self.rainbow(
    frequency = 0.1, i
  )
  case frequency
  when nil,
       :default
    frequency = 0.1
  end
  red   = Math.sin(frequency * i + 0) * 127 + 128
  green = Math.sin(frequency * i + 2 * Math::PI/3) * 127 + 128
  blue  = Math.sin(frequency * i + 4 * Math::PI/3) * 127 + 128
  '#%02X%02X%02X' % [ red, green, blue ]
end
report_is_a_directory(file) click to toggle source
#

Colours::RainbowColours.report_is_a_directory

#
# File lib/colours/rainbow_colours/report_errors.rb, line 21
def self.report_is_a_directory(file)
  e "Colours::RainbowColours: #{file}: Is a directory"
end
report_no_such_file_or_directory(file) click to toggle source
#

Colours::RainbowColours.report_no_such_file_or_directory

#
# File lib/colours/rainbow_colours/report_errors.rb, line 14
def self.report_no_such_file_or_directory(file)
  e "Colours::RainbowColours: #{file}: No such file or directory"
end
report_permission_denied(file) click to toggle source
#

Colours::RainbowColours.report_permission_denied

#
# File lib/colours/rainbow_colours/report_errors.rb, line 28
def self.report_permission_denied(file)
  e "Colours::RainbowColours: #{file}: Permission denied"
end
returnln_plain( str = "Hello world! Good morning sunshine.\n", defaults = {}, options_hash = { spread: DEFAULT_RAINBOW_SPREAD, os: rand(256), truecolor: true } ) click to toggle source
#

Colours::RainbowColours.returnln_plain

This will return a rainbow-coloured text.

The first argument is the text that you wish to display.

Invocation example:

puts Colours::RainbowColours.returnln_plain('abc def ' * 1000)
#
# File lib/colours/rainbow_colours/returnln_plain.rb, line 26
def self.returnln_plain(
    str          = "Hello world! Good morning sunshine.\n",
    defaults     = {},
    options_hash = {
      spread:    DEFAULT_RAINBOW_SPREAD,
      os:        rand(256),
      truecolor: true
    }
  )
  options_hash.merge!(defaults)
  RainbowColours.set_mode(options_hash[:truecolor])
  the_chars = str.chomp.chars # We obtain the individual characters here.
  # ======================================================================= #
  # Iterate over the chars. i, aka the second argument, is the index.
  # ======================================================================= #
  result = ''.dup
  the_chars.each_with_index { |character, index|
    # ===================================================================== #
    # Delegate towards the toplevel-method rainbow().
    # ===================================================================== #
    division_result = (
      options_hash[:os]+index / options_hash[:spread]
    )
    # ===================================================================== #
    # Next, we will obtain some ASCII value such as '#A5D604':
    # ===================================================================== #
    code = RainbowColours.rainbow(options_hash[:freq], division_result)
    # ===================================================================== #
    # Delegate towards Paint[] next. The painted character will be
    # displayed one-per-char.
    # This will yield a String such as "\e[38;2;16;236;130mo\e[0m".
    # ===================================================================== #
    result << Paint[character, *[ (:black if options_hash[:invert]), code ].compact ]
  }
  return result
end
set_mode(truecolor) click to toggle source
#

Colours::RainbowColours.set_mode

#
# File lib/colours/rainbow_colours/set_mode.rb, line 14
def self.set_mode(truecolor)
  begin
    unless Object.const_defined? :Paint
      require 'paint'
    end
    @paint_mode_detected ||= Paint.mode
    Paint.mode = truecolor ? 0xffffff : @paint_mode_detected
  rescue LoadError; end
end