A constant of all-bit 1 to match any Ripper's state in dispatch_seq
Following pry's colors where possible, but sometimes having a compromise like making backtick and regexp as red (string's color, because they're sharing tokens).
# File ruby-3.1.2/lib/irb/color.rb, line 104
def clear(colorable: colorable?)
return '' unless colorable
"\e[#{CLEAR}m"
end
# File ruby-3.1.2/lib/irb/color.rb, line 79
def colorable?
$stdout.tty? && (/mswin|mingw/ =~ RUBY_PLATFORM || (ENV.key?('TERM') && ENV['TERM'] != 'dumb'))
end
# File ruby-3.1.2/lib/irb/color.rb, line 109
def colorize(text, seq, colorable: colorable?)
return text unless colorable
seq = seq.map { |s| "\e[#{const_get(s)}m" }.join('')
"#{seq}#{text}#{clear(colorable: colorable)}"
end
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.
# File ruby-3.1.2/lib/irb/color.rb, line 118
def colorize_code(code, complete: true, ignore_error: false, colorable: colorable?)
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(colorable: colorable))
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
# File ruby-3.1.2/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
# File ruby-3.1.2/lib/irb/color.rb, line 197
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
# File ruby-3.1.2/lib/irb/color.rb, line 164
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