123456789_123456789_123456789_123456789_123456789_

Module: IRB::Color

Relationships & Source Files
Namespace Children
Classes:
Defined in: lib/irb/color.rb

Constant Summary

Class Attribute Summary

Class Method Summary

Class Attribute Details

.colorable?Boolean (readonly)

[ GitHub ]

  
# File 'lib/irb/color.rb', line 79

def colorable?
  $stdout.tty? && supported? && (/mswin|mingw/ =~ RUBY_PLATFORM || (ENV.key?('TERM') && ENV['TERM'] != 'dumb'))
end

.supported?Boolean (readonly, private)

[ GitHub ]

  
# File 'lib/irb/color.rb', line 164

def supported?
  return @supported if defined?(@supported)
  @supported = Ripper::Lexer::Elem.method_defined?(:state)
end

Class Method Details

.clear

[ GitHub ]

  
# File 'lib/irb/color.rb', line 104

def clear
  return '' unless colorable?
  "\e[#{CLEAR}m"
end

.colorize(text, seq)

[ GitHub ]

  
# File 'lib/irb/color.rb', line 109

def colorize(text, seq)
  return text unless colorable?
  seq = seq.map { |s| "\e[#{const_get(s)}m" }.join('')
  "#{seq}#{text}#{clear}"
end

.colorize_code(code, complete: true, ignore_error: false)

If complete is false (code is incomplete), this does not warn compile_error. This option is needed to avoid warning a user when the compile_error is happening because the input is not wrong but just incomplete.

[ GitHub ]

  
# File 'lib/irb/color.rb', line 118

def colorize_code(code, complete: true, ignore_error: false)
  return code unless colorable?

  symbol_state = SymbolState.new
  colored = +''
  length = 0
  end_seen = false

  scan(code, allow_last_error: !complete) do |token, str, expr|
    # IRB::ColorPrinter skips colorizing fragments with any invalid token
    if ignore_error && ERROR_TOKENS.include?(token)
      return Reline::Unicode.escape_for_print(code)
    end

    in_symbol = symbol_state.scan_token(token)
    str.each_line do |line|
      line = Reline::Unicode.escape_for_print(line)
      if seq = dispatch_seq(token, expr, line, in_symbol: in_symbol)
        colored << seq.map { |s| "\e[#{s}m" }.join('')
        colored << line.sub(/\Z/, clear)
      else
        colored << line
      end
    end
    length += str.bytesize
    end_seen = true if token == :on___end__
  end

  # give up colorizing incomplete Ripper tokens
  unless end_seen or length == code.bytesize
    return Reline::Unicode.escape_for_print(code)
  end

  colored
end

.dispatch_seq(token, expr, str, in_symbol:) (private)

[ GitHub ]

  
# File 'lib/irb/color.rb', line 202

def dispatch_seq(token, expr, str, in_symbol:)
  if ERROR_TOKENS.include?(token)
    TOKEN_SEQ_EXPRS[token][0]
  elsif in_symbol
    [YELLOW]
  elsif TOKEN_KEYWORDS.fetch(token, []).include?(str)
    [CYAN, BOLD]
  elsif (seq, exprs = TOKEN_SEQ_EXPRS[token]; (expr & (exprs || 0)) != 0)
    seq
  else
    nil
  end
end

.inspect_colorable?(obj, seen: {}.compare_by_identity) ⇒ Boolean

[ GitHub ]

  
# File 'lib/irb/color.rb', line 83

def inspect_colorable?(obj, seen: {}.compare_by_identity)
  case obj
  when String, Symbol, Regexp, Integer, Float, FalseClass, TrueClass, NilClass
    true
  when Hash
    without_circular_ref(obj, seen: seen) do
      obj.all? { |k, v| inspect_colorable?(k, seen: seen) && inspect_colorable?(v, seen: seen) }
    end
  when Array
    without_circular_ref(obj, seen: seen) do
      obj.all? { |o| inspect_colorable?(o, seen: seen) }
    end
  when Range
    inspect_colorable?(obj.begin, seen: seen) && inspect_colorable?(obj.end, seen: seen)
  when Module
    !obj.name.nil?
  else
    false
  end
end

.scan(code, allow_last_error:) (private)

[ GitHub ]

  
# File 'lib/irb/color.rb', line 169

def scan(code, allow_last_error:)
  pos = [1, 0]

  verbose, $VERBOSE = $VERBOSE, nil
  RubyLex.compile_with_errors_suppressed(code) do |inner_code, line_no|
    lexer = Ripper::Lexer.new(inner_code, '(ripper)', line_no)
    if lexer.respond_to?(:scan) # Ruby 2.7+
      lexer.scan.each do |elem|
        str = elem.tok
        next if allow_last_error and /meets end of file|unexpected end-of-input/ =~ elem.message
        next if ([elem.pos[0], elem.pos[1] + str.bytesize] <=> pos) <= 0

        str.each_line do |line|
          if line.end_with?("\n")
            pos[0] += 1
            pos[1] = 0
          else
            pos[1] += line.bytesize
          end
        end

        yield(elem.event, str, elem.state)
      end
    else
      lexer.parse.each do |elem|
        yield(elem.event, elem.tok, elem.state)
      end
    end
  end
ensure
  $VERBOSE = verbose
end

.without_circular_ref(obj, seen:, &block) (private)

[ GitHub ]

  
# File 'lib/irb/color.rb', line 156

def without_circular_ref(obj, seen:, &block)
  return false if seen.key?(obj)
  seen[obj] = true
  block.call
ensure
  seen.delete(obj)
end