ruby-changes:64241
From: aycabta <ko1@a...>
Date: Thu, 17 Dec 2020 20:24:48 +0900 (JST)
Subject: [ruby-changes:64241] 2b8fa78176 (master): [ruby/reline] Support longer than screen height
https://git.ruby-lang.org/ruby.git/commit/?id=2b8fa78176 From 2b8fa7817643a9ac7632b66ffed7cb5fd3753966 Mon Sep 17 00:00:00 2001 From: aycabta <aycabta@g...> Date: Sun, 13 Dec 2020 11:30:05 +0900 Subject: [ruby/reline] Support longer than screen height https://github.com/ruby/reline/commit/e83a3de9ed diff --git a/lib/reline/line_editor.rb b/lib/reline/line_editor.rb index 65878fe..b80a184 100644 --- a/lib/reline/line_editor.rb +++ b/lib/reline/line_editor.rb @@ -123,6 +123,7 @@ class Reline::LineEditor https://github.com/ruby/ruby/blob/trunk/lib/reline/line_editor.rb#L123 def reset(prompt = '', encoding:) @rest_height = (Reline::IOGate.get_screen_size.first - 1) - Reline::IOGate.cursor_pos.y @screen_size = Reline::IOGate.get_screen_size + @screen_height = @screen_size.first reset_variables(prompt, encoding: encoding) @old_trap = Signal.trap('SIGINT') { @old_trap.call if @old_trap.respond_to?(:call) # can also be string, ex: "DEFAULT" @@ -132,6 +133,7 @@ class Reline::LineEditor https://github.com/ruby/ruby/blob/trunk/lib/reline/line_editor.rb#L133 @rest_height = (Reline::IOGate.get_screen_size.first - 1) - Reline::IOGate.cursor_pos.y old_screen_size = @screen_size @screen_size = Reline::IOGate.get_screen_size + @screen_height = @screen_size.first if old_screen_size.last < @screen_size.last # columns increase @rerender_all = true rerender @@ -202,6 +204,7 @@ class Reline::LineEditor https://github.com/ruby/ruby/blob/trunk/lib/reline/line_editor.rb#L204 @prompt_cache_time = nil @eof = false @continuous_insertion_buffer = String.new(encoding: @encoding) + @scroll_partial_screen = nil reset_line end @@ -287,28 +290,28 @@ class Reline::LineEditor https://github.com/ruby/ruby/blob/trunk/lib/reline/line_editor.rb#L290 end end - private def calculate_nearest_cursor - @cursor_max = calculate_width(line) + private def calculate_nearest_cursor(line_to_calc = @line, cursor = @cursor, started_from = @started_from, byte_pointer = @byte_pointer, update = true) + new_cursor_max = calculate_width(line_to_calc) new_cursor = 0 new_byte_pointer = 0 height = 1 max_width = @screen_size.last if @config.editing_mode_is?(:vi_command) - last_byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @line.bytesize) + last_byte_size = Reline::Unicode.get_prev_mbchar_size(line_to_calc, line_to_calc.bytesize) if last_byte_size > 0 - last_mbchar = @line.byteslice(@line.bytesize - last_byte_size, last_byte_size) + last_mbchar = line_to_calc.byteslice(line_to_calc.bytesize - last_byte_size, last_byte_size) last_width = Reline::Unicode.get_mbchar_width(last_mbchar) - cursor_max = @cursor_max - last_width + end_of_line_cursor = new_cursor_max - last_width else - cursor_max = @cursor_max + end_of_line_cursor = new_cursor_max end else - cursor_max = @cursor_max + end_of_line_cursor = new_cursor_max end - @line.encode(Encoding::UTF_8).grapheme_clusters.each do |gc| + line_to_calc.encode(Encoding::UTF_8).grapheme_clusters.each do |gc| mbchar_width = Reline::Unicode.get_mbchar_width(gc) now = new_cursor + mbchar_width - if now > cursor_max or now > @cursor + if now > end_of_line_cursor or now > cursor break end new_cursor += mbchar_width @@ -317,9 +320,15 @@ class Reline::LineEditor https://github.com/ruby/ruby/blob/trunk/lib/reline/line_editor.rb#L320 end new_byte_pointer += gc.bytesize end - @started_from = height - 1 - @cursor = new_cursor - @byte_pointer = new_byte_pointer + new_started_from = height - 1 + if update + @cursor = new_cursor + @cursor_max = new_cursor_max + @started_from = new_started_from + @byte_pointer = new_byte_pointer + else + [new_cursor, new_cursor_max, new_started_from, new_byte_pointer] + end end def rerender_all @@ -349,33 +358,37 @@ class Reline::LineEditor https://github.com/ruby/ruby/blob/trunk/lib/reline/line_editor.rb#L358 if @add_newline_to_end_of_buffer rerender_added_newline @add_newline_to_end_of_buffer = false - elsif @just_cursor_moving and not @rerender_all - just_move_cursor - @just_cursor_moving = false - return - elsif @previous_line_index or new_highest_in_this != @highest_in_this - rerender_changed_current_line - @previous_line_index = nil - rendered = true - elsif @rerender_all - rerender_all_lines - @rerender_all = false - rendered = true + else + if @just_cursor_moving and not @rerender_all + rendered = just_move_cursor + @just_cursor_moving = false + return + elsif @previous_line_index or new_highest_in_this != @highest_in_this + rerender_changed_current_line + @previous_line_index = nil + rendered = true + elsif @rerender_all + rerender_all_lines + @rerender_all = false + rendered = true + else + end end line = modify_lines(whole_lines)[@line_index] if @is_multiline prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines, prompt) if finished? # Always rerender on finish because output_modifier_proc may return a different output. - render_partial(prompt, prompt_width, line) + render_partial(prompt, prompt_width, line, @first_line_started_from) scroll_down(1) Reline::IOGate.move_cursor_column(0) Reline::IOGate.erase_after_cursor elsif not rendered - render_partial(prompt, prompt_width, line) + render_partial(prompt, prompt_width, line, @first_line_started_from) end + @buffer_of_lines[@line_index] = @line else - render_partial(prompt, prompt_width, line) + render_partial(prompt, prompt_width, line, 0) if finished? scroll_down(1) Reline::IOGate.move_cursor_column(0) @@ -384,13 +397,46 @@ class Reline::LineEditor https://github.com/ruby/ruby/blob/trunk/lib/reline/line_editor.rb#L397 end end + private def calculate_scroll_partial_screen(highest_in_all, cursor_y) + if @screen_height < highest_in_all + old_scroll_partial_screen = @scroll_partial_screen + if cursor_y == 0 + @scroll_partial_screen = 0 + elsif cursor_y == (highest_in_all - 1) + @scroll_partial_screen = highest_in_all - @screen_height + else + if @scroll_partial_screen + if cursor_y <= @scroll_partial_screen + @scroll_partial_screen = cursor_y + elsif (@scroll_partial_screen + @screen_height - 1) < cursor_y + @scroll_partial_screen = cursor_y - (@screen_height - 1) + end + else + if cursor_y > (@screen_height - 1) + @scroll_partial_screen = cursor_y - (@screen_height - 1) + else + @scroll_partial_screen = 0 + end + end + end + if @scroll_partial_screen != old_scroll_partial_screen + @rerender_all = true + end + else + if @scroll_partial_screen + @rerender_all = true + end + @scroll_partial_screen = nil + end + end + private def rerender_added_newline scroll_down(1) 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 @line = @buffer_of_lines[@line_index] - render_partial(prompt, prompt_width, @line, false) + render_partial(prompt, prompt_width, @line, @first_line_started_from + @started_from + 1, with_control: false) @cursor = @cursor_max = calculate_width(@line) @byte_pointer = @line.bytesize @highest_in_all += @highest_in_this @@ -409,14 +455,25 @@ class Reline::LineEditor https://github.com/ruby/ruby/blob/trunk/lib/reline/line_editor.rb#L455 else calculate_height_by_lines(@buffer_of_lines[0..(@line_index - 1)], prompt_list || prompt) end - @line = @buffer_of_lines[@line_index] - move_cursor_down(new_first_line_started_from - @first_line_started_from) - @first_line_started_from = new_first_line_started_from - calculate_nearest_cursor - @started_from = calculate_height_by_width(prompt_width + @cursor) - 1 - move_cursor_down(@started_from) - Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last) + first_line_diff = new_first_line_started_from - @first_line_started_from + new_cursor, _, new_started_from, _ = calculate_nearest_cursor(@line, @cursor, @started_from, @byte_pointer, false) + new_started_from = calculate_height_by_width(prompt_width + new_cursor) - 1 + calculate_scroll_partial_screen(@highest_in_all, new_first_line_started_from + new_started_from) @previous_line_index = nil + if @rerender_all + @line = @buffer_of_lines[@line_index] + rerender_all_lines + @rerender_all = false + true + else + @line = @buffer_of_lines[@line_index] + @first_line_started_from = new_first_line_started_from + @started_from = new_started_from + @cursor = new_cursor + move_cursor_down(first_line_diff + @started_from) + Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last) + false + end end private def rerender_changed_current_line @@ -479,35 +536,42 @@ class Reline::LineEditor https://github.com/ruby/ruby/blob/trunk/lib/reline/line_editor.rb#L536 height = calculate_height_by_width(width) back += height end - if back > @highest_in_all + old_highest_in_all = @highest_in_all + if @line_index.zero? + new_first_line_started_from = 0 + else + new_first_line_started_from = calculate_height_by_lines(new_buffer[0..(@line_index - 1)], prompt_list || prompt) + end + new_started_from = calculate_height_by_width(pr (... truncated) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/