1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

[ruby/reline] Cache pasting state in processing a key

Because it's too slow.

The rendering time in IRB has been reduced as follows:

  start = Time.now

  def each_top_level_statement
    initialize_input
    catch(:TERM_INPUT) do
      loop do
        begin
          prompt
          unless l = lex
            throw :TERM_INPUT if @line == ''
          else
            @line_no += l.count("\n")
            next if l == "\n"
            @line.concat l
            if @code_block_open or @ltype or @continue or @indent > 0
              next
            end
          end
          if @line != "\n"
            @line.force_encoding(@io.encoding)
            yield @line, @exp_line_no
          end
          break if @io.eof?
          @line = ''
          @exp_line_no = @line_no

          @indent = 0
        rescue TerminateLineInput
          initialize_input
          prompt
        end
      end
    end
  end

  puts "Duration: #{Time.now - start} seconds"

0.22sec -> 0.14sec

https://github.com/ruby/reline/commit/b8b3dd52c0
This commit is contained in:
aycabta 2021-01-26 13:18:05 +09:00
parent 132e01a1c3
commit b69c965f47
2 changed files with 25 additions and 13 deletions

View file

@ -243,6 +243,7 @@ module Reline
loop do loop do
prev_pasting_state = Reline::IOGate.in_pasting? prev_pasting_state = Reline::IOGate.in_pasting?
read_io(config.keyseq_timeout) { |inputs| read_io(config.keyseq_timeout) { |inputs|
line_editor.set_pasting_state(Reline::IOGate.in_pasting?)
inputs.each { |c| inputs.each { |c|
line_editor.input_key(c) line_editor.input_key(c)
line_editor.rerender line_editor.rerender
@ -253,6 +254,7 @@ module Reline
end end
} }
if prev_pasting_state == true and not Reline::IOGate.in_pasting? and not line_editor.finished? if prev_pasting_state == true and not Reline::IOGate.in_pasting? and not line_editor.finished?
line_editor.set_pasting_state(false)
prev_pasting_state = false prev_pasting_state = false
line_editor.rerender_all line_editor.rerender_all
end end

View file

@ -58,13 +58,17 @@ class Reline::LineEditor
reset_variables(encoding: encoding) reset_variables(encoding: encoding)
end end
def set_pasting_state(in_pasting)
@in_pasting = in_pasting
end
def simplified_rendering? def simplified_rendering?
if finished? if finished?
false false
elsif @just_cursor_moving and not @rerender_all elsif @just_cursor_moving and not @rerender_all
true true
else else
not @rerender_all and not finished? and Reline::IOGate.in_pasting? not @rerender_all and not finished? and @in_pasting
end end
end end
@ -379,7 +383,7 @@ class Reline::LineEditor
# FIXME: end of logical line sometimes breaks # FIXME: end of logical line sometimes breaks
rendered = false rendered = false
if @add_newline_to_end_of_buffer if @add_newline_to_end_of_buffer
rerender_added_newline rerender_added_newline(prompt, prompt_width)
@add_newline_to_end_of_buffer = false @add_newline_to_end_of_buffer = false
else else
if @just_cursor_moving and not @rerender_all if @just_cursor_moving and not @rerender_all
@ -397,20 +401,25 @@ class Reline::LineEditor
else else
end end
end end
line = modify_lines(whole_lines)[@line_index]
if @is_multiline if @is_multiline
prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines, prompt)
if finished? if finished?
# Always rerender on finish because output_modifier_proc may return a different output. # Always rerender on finish because output_modifier_proc may return a different output.
line = modify_lines(whole_lines)[@line_index]
prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines, prompt)
render_partial(prompt, prompt_width, line, @first_line_started_from) render_partial(prompt, prompt_width, line, @first_line_started_from)
scroll_down(1) scroll_down(1)
Reline::IOGate.move_cursor_column(0) Reline::IOGate.move_cursor_column(0)
Reline::IOGate.erase_after_cursor Reline::IOGate.erase_after_cursor
elsif not rendered elsif not rendered
unless @in_pasting
line = modify_lines(whole_lines)[@line_index]
prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines, prompt)
render_partial(prompt, prompt_width, line, @first_line_started_from) render_partial(prompt, prompt_width, line, @first_line_started_from)
end end
end
@buffer_of_lines[@line_index] = @line @buffer_of_lines[@line_index] = @line
else else
line = modify_lines(whole_lines)[@line_index]
render_partial(prompt, prompt_width, line, 0) render_partial(prompt, prompt_width, line, 0)
if finished? if finished?
scroll_down(1) scroll_down(1)
@ -453,14 +462,15 @@ class Reline::LineEditor
end end
end end
private def rerender_added_newline private def rerender_added_newline(prompt, prompt_width)
scroll_down(1) scroll_down(1)
new_lines = whole_lines(index: @previous_line_index, line: @line) new_lines = whole_lines(index: @previous_line_index, line: @line)
prompt, prompt_width, = check_multiline_prompt(new_lines, prompt)
@buffer_of_lines[@previous_line_index] = @line @buffer_of_lines[@previous_line_index] = @line
@line = @buffer_of_lines[@line_index] @line = @buffer_of_lines[@line_index]
unless @in_pasting
render_partial(prompt, prompt_width, @line, @first_line_started_from + @started_from + 1, with_control: false) render_partial(prompt, prompt_width, @line, @first_line_started_from + @started_from + 1, with_control: false)
@cursor = @cursor_max = calculate_width(@line) @cursor = @cursor_max = calculate_width(@line)
end
@byte_pointer = @line.bytesize @byte_pointer = @line.bytesize
@highest_in_all += @highest_in_this @highest_in_all += @highest_in_this
@highest_in_this = calculate_height_by_width(prompt_width + @cursor_max) @highest_in_this = calculate_height_by_width(prompt_width + @cursor_max)
@ -1082,7 +1092,7 @@ class Reline::LineEditor
unless completion_occurs unless completion_occurs
@completion_state = CompletionState::NORMAL @completion_state = CompletionState::NORMAL
end end
if not Reline::IOGate.in_pasting? and @just_cursor_moving.nil? if not @in_pasting and @just_cursor_moving.nil?
if @previous_line_index and @buffer_of_lines[@previous_line_index] == @line if @previous_line_index and @buffer_of_lines[@previous_line_index] == @line
@just_cursor_moving = true @just_cursor_moving = true
elsif @previous_line_index.nil? and @buffer_of_lines[@line_index] == @line and old_line == @line elsif @previous_line_index.nil? and @buffer_of_lines[@line_index] == @line and old_line == @line
@ -1332,14 +1342,14 @@ class Reline::LineEditor
cursor_line = @line.byteslice(0, @byte_pointer) cursor_line = @line.byteslice(0, @byte_pointer)
insert_new_line(cursor_line, next_line) insert_new_line(cursor_line, next_line)
@cursor = 0 @cursor = 0
@check_new_auto_indent = true unless Reline::IOGate.in_pasting? @check_new_auto_indent = true unless @in_pasting
end end
end end
private def ed_unassigned(key) end # do nothing private def ed_unassigned(key) end # do nothing
private def process_insert(force: false) private def process_insert(force: false)
return if @continuous_insertion_buffer.empty? or (Reline::IOGate.in_pasting? and not force) return if @continuous_insertion_buffer.empty? or (@in_pasting and not force)
width = Reline::Unicode.calculate_width(@continuous_insertion_buffer) width = Reline::Unicode.calculate_width(@continuous_insertion_buffer)
bytesize = @continuous_insertion_buffer.bytesize bytesize = @continuous_insertion_buffer.bytesize
if @cursor == @cursor_max if @cursor == @cursor_max
@ -1374,7 +1384,7 @@ class Reline::LineEditor
str = key.chr str = key.chr
bytesize = 1 bytesize = 1
end end
if Reline::IOGate.in_pasting? if @in_pasting
@continuous_insertion_buffer << str @continuous_insertion_buffer << str
return return
elsif not @continuous_insertion_buffer.empty? elsif not @continuous_insertion_buffer.empty?