module Say

author: Kyle Yetter

Constants

BACKGROUND_CODE
BAD_CLOSE
COLOR_NAMES
COLOR_VALUES
ESCAPE_MAP

Basic ANSI Color Escape Constants ####################

FOREGROUND_CODE
FormatError
RX_CLOSE_TAG
RX_COLOR_ARG
RX_COLOR_VALUE
RX_COLOR_WORD

Regular Expressions #####################################

RX_ESCAPE
RX_HEX_CODE
RX_OPEN_TAG
RX_TAGS
RX_TEXT
STYLE_CODES
VERSION

Public Class Methods

color_escape_code(fg_or_bg, color_name) click to toggle source
# File lib/say.rb, line 267
def self.color_escape_code(fg_or_bg, color_name)
  if color_name && !color_name.empty?
    if color_name =~ RX_HEX_CODE
      fg_or_bg == :bg ? xterm256_bg(color_name) : xterm256_fg(color_name)
    else
      full_name =
        COLOR_NAMES.fetch(color_name.downcase) do | i |
          fail FormatError, "`%s' is not a valid color name" % color_name
        end
      sprintf(fg_or_bg == :bg ? BACKGROUND_CODE : FOREGROUND_CODE, COLOR_VALUES[full_name])
    end
  end
end
color_scan( text ) click to toggle source
# File lib/say.rb, line 281
def self.color_scan( text )
  foreground = []
  background = []
  styles     = []
  out = ''

  text = text.gsub( RX_COLOR_ARG, '<\1>%\4</\1>' )

  until text.nil? or text.empty?
    print_escape = false

    case text
    when RX_ESCAPE
      text = $'
      out << ESCAPE_MAP[ $1 ]

    when RX_CLOSE_TAG
      text = $'

      if style_char = $1
        style_char.each_char { | c | styles.delete( STYLE_CODES.fetch(c) ) }
      elsif colors = $2
        fg, bg = colors.split( '@', 2 )

        if value = color_escape_code(:fg, fg)
          if current = foreground.last and current != value
            display_map = COLOR_VALUES.invert
            expected    = display_map[ current ]
            got         = display_map[ value ]
            fail FormatError, BAD_CLOSE % [ expected, got ]
          end
          foreground.pop
        end

        if value = color_escape_code(:bg, bg)
          if current = background.last and current != value
            display_map = COLOR_VALUES.invert
            expected    = display_map[current]
            got         = display_map[value]
            fail FormatError, BAD_CLOSE % [expected, got]
          end
          background.pop
        end
      end

      print_escape = true

    when RX_OPEN_TAG
      text = $'

      if style_char = $1
        style_char.each_char { |c| styles << STYLE_CODES.fetch(c) }
      elsif colors = $2
        fg, bg = colors.split('@', 2)
        value = color_escape_code(:fg, fg) and foreground << value
        value = color_escape_code(:bg, bg) and background << value
      end

      print_escape = true

    when RX_TEXT
      text = $'
      out << $1

    else
      raise "this shouldn't happen: (#{ __FILE__ }@#{ __LINE__ })"

    end

    if print_escape
      out << "\e[0m"
      value = foreground.last and out << value
      value = background.last and out << value
      out << styles.join('')
    end
  end

  if foreground.length + background.length + styles.length > 0
    out << "\e[0m"
  end

  return out
end
color_value( name ) click to toggle source

Methods ###########################################

# File lib/say.rb, line 258
def self.color_value( name )
  if name and not name.empty?
    full_name = COLOR_NAMES.fetch( name.downcase ) do | i |
      raise( FormatError, "`%s' is not a valid color name" % name )
    end
    COLOR_VALUES[ full_name ]
  end
end
say( *args ) click to toggle source
# File lib/say.rb, line 375
def say( *args )
  puts( say_format( *args ) )
end
say_format( *args ) click to toggle source
# File lib/say.rb, line 365
def say_format( *args )
  args = [ args ].flatten!
  format = args.shift.to_s
  sprintf( Say.color_scan( format ), *args )
end
say_print( *args ) click to toggle source
# File lib/say.rb, line 371
def say_print( *args )
  print( say_format( *args ) )
end

Public Instance Methods

say( *args ) click to toggle source
# File lib/say.rb, line 375
def say( *args )
  puts( say_format( *args ) )
end

Private Instance Methods

say_format( *args ) click to toggle source
# File lib/say.rb, line 365
def say_format( *args )
  args = [ args ].flatten!
  format = args.shift.to_s
  sprintf( Say.color_scan( format ), *args )
end
say_print( *args ) click to toggle source
# File lib/say.rb, line 371
def say_print( *args )
  print( say_format( *args ) )
end