ruby-changes:73669
From: tompng <ko1@a...>
Date: Thu, 22 Sep 2022 00:37:50 +0900 (JST)
Subject: [ruby-changes:73669] 9f68687879 (master): [ruby/irb] Scan every single characters in IRB::Color.scan
https://git.ruby-lang.org/ruby.git/commit/?id=9f68687879 From 9f686878794291b088d07866c00f8056a0c7dec7 Mon Sep 17 00:00:00 2001 From: tompng <tomoyapenguin@g...> Date: Sun, 7 Aug 2022 20:58:17 +0900 Subject: [ruby/irb] Scan every single characters in IRB::Color.scan https://github.com/ruby/irb/commit/d14e56a65d --- lib/irb/color.rb | 55 +++++++++++++++++++++++++------------------------- test/irb/test_color.rb | 2 ++ 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/lib/irb/color.rb b/lib/irb/color.rb index 8307af25a9..401966d181 100644 --- a/lib/irb/color.rb +++ b/lib/irb/color.rb @@ -128,10 +128,14 @@ module IRB # :nodoc: https://github.com/ruby/ruby/blob/trunk/lib/irb/color.rb#L128 symbol_state = SymbolState.new colored = +'' - length = 0 - end_seen = false scan(code, allow_last_error: !complete) do |token, str, expr| + # handle uncolorable code + if token.nil? + colored << Reline::Unicode.escape_for_print(str) + next + end + # IRB::ColorPrinter skips colorizing fragments with any invalid token if ignore_error && ERROR_TOKENS.include?(token) return Reline::Unicode.escape_for_print(code) @@ -147,15 +151,7 @@ module IRB # :nodoc: https://github.com/ruby/ruby/blob/trunk/lib/irb/color.rb#L151 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 @@ -170,33 +166,38 @@ module IRB # :nodoc: https://github.com/ruby/ruby/blob/trunk/lib/irb/color.rb#L166 end 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) + byte_pos = 0 + line_positions = [0] + inner_code.lines.each do |line| + line_positions << line_positions.last + line.bytesize + end + + on_scan = proc do |elem| + str = elem.tok + start_pos = line_positions[elem.pos[0] - 1] + elem.pos[1] + end_pos = start_pos + str.bytesize + next if start_pos < byte_pos + + yield(nil, inner_code.byteslice(byte_pos...start_pos), nil) if byte_pos < start_pos + yield(elem.event, str, elem.state) + byte_pos = end_pos + end + 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) + on_scan.call(elem) end else - lexer.parse.each do |elem| - yield(elem.event, elem.tok, elem.state) + lexer.parse.sort_by(&:pos).each do |elem| + on_scan.call(elem) end end + # yield uncolorable DATA section + yield(nil, inner_code.byteslice(byte_pos...inner_code.bytesize), nil) if byte_pos < inner_code.bytesize end ensure $VERBOSE = verbose diff --git a/test/irb/test_color.rb b/test/irb/test_color.rb index 6ad64a0ae2..73e9b389c2 100644 --- a/test/irb/test_color.rb +++ b/test/irb/test_color.rb @@ -88,6 +88,8 @@ module TestIRB https://github.com/ruby/ruby/blob/trunk/test/irb/test_color.rb#L88 "foo(*%W(bar))" => "foo(*#{RED}#{BOLD}%W(#{CLEAR}#{RED}bar#{CLEAR}#{RED}#{BOLD})#{CLEAR})", "$stdout" => "#{GREEN}#{BOLD}$stdout#{CLEAR}", "__END__" => "#{GREEN}__END__#{CLEAR}", + "foo\n__END__\nbar" => "foo\n#{GREEN}__END__#{CLEAR}\nbar", + "foo\n<<A\0\0bar\nA\nbaz" => "foo\n#{RED}<<A#{CLEAR}^@^@bar\n#{RED}A#{CLEAR}\nbaz", } # specific to Ruby 2.7+ -- cgit v1.2.1 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/