зеркало из https://github.com/github/ruby.git
[ruby/reline] Support longer than screen height
https://github.com/ruby/reline/commit/e83a3de9ed
This commit is contained in:
Родитель
9908177857
Коммит
2b8fa78176
|
@ -123,6 +123,7 @@ class Reline::LineEditor
|
||||||
def reset(prompt = '', encoding:)
|
def reset(prompt = '', encoding:)
|
||||||
@rest_height = (Reline::IOGate.get_screen_size.first - 1) - Reline::IOGate.cursor_pos.y
|
@rest_height = (Reline::IOGate.get_screen_size.first - 1) - Reline::IOGate.cursor_pos.y
|
||||||
@screen_size = Reline::IOGate.get_screen_size
|
@screen_size = Reline::IOGate.get_screen_size
|
||||||
|
@screen_height = @screen_size.first
|
||||||
reset_variables(prompt, encoding: encoding)
|
reset_variables(prompt, encoding: encoding)
|
||||||
@old_trap = Signal.trap('SIGINT') {
|
@old_trap = Signal.trap('SIGINT') {
|
||||||
@old_trap.call if @old_trap.respond_to?(:call) # can also be string, ex: "DEFAULT"
|
@old_trap.call if @old_trap.respond_to?(:call) # can also be string, ex: "DEFAULT"
|
||||||
|
@ -132,6 +133,7 @@ class Reline::LineEditor
|
||||||
@rest_height = (Reline::IOGate.get_screen_size.first - 1) - Reline::IOGate.cursor_pos.y
|
@rest_height = (Reline::IOGate.get_screen_size.first - 1) - Reline::IOGate.cursor_pos.y
|
||||||
old_screen_size = @screen_size
|
old_screen_size = @screen_size
|
||||||
@screen_size = Reline::IOGate.get_screen_size
|
@screen_size = Reline::IOGate.get_screen_size
|
||||||
|
@screen_height = @screen_size.first
|
||||||
if old_screen_size.last < @screen_size.last # columns increase
|
if old_screen_size.last < @screen_size.last # columns increase
|
||||||
@rerender_all = true
|
@rerender_all = true
|
||||||
rerender
|
rerender
|
||||||
|
@ -202,6 +204,7 @@ class Reline::LineEditor
|
||||||
@prompt_cache_time = nil
|
@prompt_cache_time = nil
|
||||||
@eof = false
|
@eof = false
|
||||||
@continuous_insertion_buffer = String.new(encoding: @encoding)
|
@continuous_insertion_buffer = String.new(encoding: @encoding)
|
||||||
|
@scroll_partial_screen = nil
|
||||||
reset_line
|
reset_line
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -287,28 +290,28 @@ class Reline::LineEditor
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private def calculate_nearest_cursor
|
private def calculate_nearest_cursor(line_to_calc = @line, cursor = @cursor, started_from = @started_from, byte_pointer = @byte_pointer, update = true)
|
||||||
@cursor_max = calculate_width(line)
|
new_cursor_max = calculate_width(line_to_calc)
|
||||||
new_cursor = 0
|
new_cursor = 0
|
||||||
new_byte_pointer = 0
|
new_byte_pointer = 0
|
||||||
height = 1
|
height = 1
|
||||||
max_width = @screen_size.last
|
max_width = @screen_size.last
|
||||||
if @config.editing_mode_is?(:vi_command)
|
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
|
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)
|
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
|
else
|
||||||
cursor_max = @cursor_max
|
end_of_line_cursor = new_cursor_max
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
cursor_max = @cursor_max
|
end_of_line_cursor = new_cursor_max
|
||||||
end
|
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)
|
mbchar_width = Reline::Unicode.get_mbchar_width(gc)
|
||||||
now = new_cursor + mbchar_width
|
now = new_cursor + mbchar_width
|
||||||
if now > cursor_max or now > @cursor
|
if now > end_of_line_cursor or now > cursor
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
new_cursor += mbchar_width
|
new_cursor += mbchar_width
|
||||||
|
@ -317,9 +320,15 @@ class Reline::LineEditor
|
||||||
end
|
end
|
||||||
new_byte_pointer += gc.bytesize
|
new_byte_pointer += gc.bytesize
|
||||||
end
|
end
|
||||||
@started_from = height - 1
|
new_started_from = height - 1
|
||||||
@cursor = new_cursor
|
if update
|
||||||
@byte_pointer = new_byte_pointer
|
@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
|
end
|
||||||
|
|
||||||
def rerender_all
|
def rerender_all
|
||||||
|
@ -349,33 +358,37 @@ class Reline::LineEditor
|
||||||
if @add_newline_to_end_of_buffer
|
if @add_newline_to_end_of_buffer
|
||||||
rerender_added_newline
|
rerender_added_newline
|
||||||
@add_newline_to_end_of_buffer = false
|
@add_newline_to_end_of_buffer = false
|
||||||
elsif @just_cursor_moving and not @rerender_all
|
else
|
||||||
just_move_cursor
|
if @just_cursor_moving and not @rerender_all
|
||||||
@just_cursor_moving = false
|
rendered = just_move_cursor
|
||||||
return
|
@just_cursor_moving = false
|
||||||
elsif @previous_line_index or new_highest_in_this != @highest_in_this
|
return
|
||||||
rerender_changed_current_line
|
elsif @previous_line_index or new_highest_in_this != @highest_in_this
|
||||||
@previous_line_index = nil
|
rerender_changed_current_line
|
||||||
rendered = true
|
@previous_line_index = nil
|
||||||
elsif @rerender_all
|
rendered = true
|
||||||
rerender_all_lines
|
elsif @rerender_all
|
||||||
@rerender_all = false
|
rerender_all_lines
|
||||||
rendered = true
|
@rerender_all = false
|
||||||
|
rendered = true
|
||||||
|
else
|
||||||
|
end
|
||||||
end
|
end
|
||||||
line = modify_lines(whole_lines)[@line_index]
|
line = modify_lines(whole_lines)[@line_index]
|
||||||
if @is_multiline
|
if @is_multiline
|
||||||
prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines, prompt)
|
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.
|
||||||
render_partial(prompt, prompt_width, line)
|
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
|
||||||
render_partial(prompt, prompt_width, line)
|
render_partial(prompt, prompt_width, line, @first_line_started_from)
|
||||||
end
|
end
|
||||||
|
@buffer_of_lines[@line_index] = @line
|
||||||
else
|
else
|
||||||
render_partial(prompt, prompt_width, line)
|
render_partial(prompt, prompt_width, line, 0)
|
||||||
if finished?
|
if finished?
|
||||||
scroll_down(1)
|
scroll_down(1)
|
||||||
Reline::IOGate.move_cursor_column(0)
|
Reline::IOGate.move_cursor_column(0)
|
||||||
|
@ -384,13 +397,46 @@ class Reline::LineEditor
|
||||||
end
|
end
|
||||||
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
|
private def rerender_added_newline
|
||||||
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)
|
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]
|
||||||
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)
|
@cursor = @cursor_max = calculate_width(@line)
|
||||||
@byte_pointer = @line.bytesize
|
@byte_pointer = @line.bytesize
|
||||||
@highest_in_all += @highest_in_this
|
@highest_in_all += @highest_in_this
|
||||||
|
@ -409,14 +455,25 @@ class Reline::LineEditor
|
||||||
else
|
else
|
||||||
calculate_height_by_lines(@buffer_of_lines[0..(@line_index - 1)], prompt_list || prompt)
|
calculate_height_by_lines(@buffer_of_lines[0..(@line_index - 1)], prompt_list || prompt)
|
||||||
end
|
end
|
||||||
@line = @buffer_of_lines[@line_index]
|
first_line_diff = new_first_line_started_from - @first_line_started_from
|
||||||
move_cursor_down(new_first_line_started_from - @first_line_started_from)
|
new_cursor, _, new_started_from, _ = calculate_nearest_cursor(@line, @cursor, @started_from, @byte_pointer, false)
|
||||||
@first_line_started_from = new_first_line_started_from
|
new_started_from = calculate_height_by_width(prompt_width + new_cursor) - 1
|
||||||
calculate_nearest_cursor
|
calculate_scroll_partial_screen(@highest_in_all, new_first_line_started_from + new_started_from)
|
||||||
@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)
|
|
||||||
@previous_line_index = nil
|
@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
|
end
|
||||||
|
|
||||||
private def rerender_changed_current_line
|
private def rerender_changed_current_line
|
||||||
|
@ -479,35 +536,42 @@ class Reline::LineEditor
|
||||||
height = calculate_height_by_width(width)
|
height = calculate_height_by_width(width)
|
||||||
back += height
|
back += height
|
||||||
end
|
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(prompt_width + @cursor) - 1
|
||||||
|
if back > old_highest_in_all
|
||||||
scroll_down(back - 1)
|
scroll_down(back - 1)
|
||||||
move_cursor_up(back - 1)
|
move_cursor_up(back - 1)
|
||||||
elsif back < @highest_in_all
|
elsif back < old_highest_in_all
|
||||||
scroll_down(back)
|
scroll_down(back)
|
||||||
Reline::IOGate.erase_after_cursor
|
Reline::IOGate.erase_after_cursor
|
||||||
(@highest_in_all - back - 1).times do
|
(old_highest_in_all - back - 1).times do
|
||||||
scroll_down(1)
|
scroll_down(1)
|
||||||
Reline::IOGate.erase_after_cursor
|
Reline::IOGate.erase_after_cursor
|
||||||
end
|
end
|
||||||
move_cursor_up(@highest_in_all - 1)
|
move_cursor_up(old_highest_in_all - 1)
|
||||||
end
|
end
|
||||||
|
calculate_scroll_partial_screen(back, new_first_line_started_from + new_started_from)
|
||||||
render_whole_lines(new_buffer, prompt_list || prompt, prompt_width)
|
render_whole_lines(new_buffer, prompt_list || prompt, prompt_width)
|
||||||
move_cursor_up(back - 1)
|
|
||||||
if @prompt_proc
|
if @prompt_proc
|
||||||
prompt = prompt_list[@line_index]
|
prompt = prompt_list[@line_index]
|
||||||
prompt_width = calculate_width(prompt, true)
|
prompt_width = calculate_width(prompt, true)
|
||||||
end
|
end
|
||||||
@highest_in_all = back
|
|
||||||
@highest_in_this = calculate_height_by_width(prompt_width + @cursor_max)
|
@highest_in_this = calculate_height_by_width(prompt_width + @cursor_max)
|
||||||
@first_line_started_from =
|
@highest_in_all = back
|
||||||
if @line_index.zero?
|
@first_line_started_from = new_first_line_started_from
|
||||||
0
|
@started_from = new_started_from
|
||||||
else
|
if @scroll_partial_screen
|
||||||
calculate_height_by_lines(new_buffer[0..(@line_index - 1)], prompt_list || prompt)
|
Reline::IOGate.move_cursor_up(@screen_height - (@first_line_started_from + @started_from - @scroll_partial_screen) - 1)
|
||||||
end
|
Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
|
||||||
@started_from = calculate_height_by_width(prompt_width + @cursor) - 1
|
else
|
||||||
move_cursor_down(@first_line_started_from + @started_from)
|
move_cursor_down(@first_line_started_from + @started_from - back + 1)
|
||||||
Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
|
Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private def render_whole_lines(lines, prompt, prompt_width)
|
private def render_whole_lines(lines, prompt, prompt_width)
|
||||||
|
@ -519,9 +583,15 @@ class Reline::LineEditor
|
||||||
else
|
else
|
||||||
line_prompt = prompt
|
line_prompt = prompt
|
||||||
end
|
end
|
||||||
height = render_partial(line_prompt, prompt_width, line, false)
|
height = render_partial(line_prompt, prompt_width, line, rendered_height, with_control: false)
|
||||||
if index < (lines.size - 1)
|
if index < (lines.size - 1)
|
||||||
scroll_down(1)
|
if @scroll_partial_screen
|
||||||
|
if (@scroll_partial_screen - height) < rendered_height and (@scroll_partial_screen + @screen_height - 1) >= (rendered_height + height)
|
||||||
|
move_cursor_down(1)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
scroll_down(1)
|
||||||
|
end
|
||||||
rendered_height += height
|
rendered_height += height
|
||||||
else
|
else
|
||||||
rendered_height += height - 1
|
rendered_height += height - 1
|
||||||
|
@ -530,8 +600,34 @@ class Reline::LineEditor
|
||||||
rendered_height
|
rendered_height
|
||||||
end
|
end
|
||||||
|
|
||||||
private def render_partial(prompt, prompt_width, line_to_render, with_control = true)
|
private def render_partial(prompt, prompt_width, line_to_render, this_started_from, with_control: true)
|
||||||
visual_lines, height = split_by_width(line_to_render.nil? ? prompt : prompt + line_to_render, @screen_size.last)
|
visual_lines, height = split_by_width(line_to_render.nil? ? prompt : prompt + line_to_render, @screen_size.last)
|
||||||
|
cursor_up_from_last_line = 0
|
||||||
|
# TODO: This logic would be sometimes buggy if this logical line isn't the current @line_index.
|
||||||
|
if @scroll_partial_screen
|
||||||
|
last_visual_line = this_started_from + (height - 1)
|
||||||
|
last_screen_line = @scroll_partial_screen + (@screen_height - 1)
|
||||||
|
if (@scroll_partial_screen - this_started_from) >= height
|
||||||
|
# Render nothing because this line is before the screen.
|
||||||
|
visual_lines = []
|
||||||
|
elsif this_started_from > last_screen_line
|
||||||
|
# Render nothing because this line is after the screen.
|
||||||
|
visual_lines = []
|
||||||
|
else
|
||||||
|
deleted_lines_before_screen = []
|
||||||
|
if @scroll_partial_screen > this_started_from and last_visual_line >= @scroll_partial_screen
|
||||||
|
# A part of visual lines are before the screen.
|
||||||
|
deleted_lines_before_screen = visual_lines.shift((@scroll_partial_screen - this_started_from) * 2)
|
||||||
|
deleted_lines_before_screen.compact!
|
||||||
|
end
|
||||||
|
if this_started_from <= last_screen_line and last_screen_line < last_visual_line
|
||||||
|
# A part of visual lines are after the screen.
|
||||||
|
visual_lines.pop((last_visual_line - last_screen_line) * 2)
|
||||||
|
end
|
||||||
|
move_cursor_up(deleted_lines_before_screen.size - @started_from)
|
||||||
|
cursor_up_from_last_line = @started_from - deleted_lines_before_screen.size
|
||||||
|
end
|
||||||
|
end
|
||||||
if with_control
|
if with_control
|
||||||
if height > @highest_in_this
|
if height > @highest_in_this
|
||||||
diff = height - @highest_in_this
|
diff = height - @highest_in_this
|
||||||
|
@ -545,10 +641,14 @@ class Reline::LineEditor
|
||||||
@highest_in_this = height
|
@highest_in_this = height
|
||||||
end
|
end
|
||||||
move_cursor_up(@started_from)
|
move_cursor_up(@started_from)
|
||||||
|
cursor_up_from_last_line = height - 1 - @started_from
|
||||||
@started_from = calculate_height_by_width(prompt_width + @cursor) - 1
|
@started_from = calculate_height_by_width(prompt_width + @cursor) - 1
|
||||||
end
|
end
|
||||||
Reline::IOGate.move_cursor_column(0)
|
if Reline::Unicode::CSI_REGEXP.match?(prompt + line_to_render)
|
||||||
|
@output.write "\e[0m" # clear character decorations
|
||||||
|
end
|
||||||
visual_lines.each_with_index do |line, index|
|
visual_lines.each_with_index do |line, index|
|
||||||
|
Reline::IOGate.move_cursor_column(0)
|
||||||
if line.nil?
|
if line.nil?
|
||||||
if calculate_width(visual_lines[index - 1], true) == Reline::IOGate.get_screen_size.last
|
if calculate_width(visual_lines[index - 1], true) == Reline::IOGate.get_screen_size.last
|
||||||
# reaches the end of line
|
# reaches the end of line
|
||||||
|
@ -580,15 +680,18 @@ class Reline::LineEditor
|
||||||
@pre_input_hook&.call
|
@pre_input_hook&.call
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
Reline::IOGate.erase_after_cursor
|
unless visual_lines.empty?
|
||||||
Reline::IOGate.move_cursor_column(0)
|
Reline::IOGate.erase_after_cursor
|
||||||
|
Reline::IOGate.move_cursor_column(0)
|
||||||
|
end
|
||||||
if with_control
|
if with_control
|
||||||
# Just after rendring, so the cursor is on the last line.
|
# Just after rendring, so the cursor is on the last line.
|
||||||
if finished?
|
if finished?
|
||||||
Reline::IOGate.move_cursor_column(0)
|
Reline::IOGate.move_cursor_column(0)
|
||||||
else
|
else
|
||||||
# Moves up from bottom of lines to the cursor position.
|
# Moves up from bottom of lines to the cursor position.
|
||||||
move_cursor_up(height - 1 - @started_from)
|
move_cursor_up(cursor_up_from_last_line)
|
||||||
|
# This logic is buggy if a fullwidth char is wrapped because there is only one halfwidth at end of a line.
|
||||||
Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
|
Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -624,9 +727,9 @@ class Reline::LineEditor
|
||||||
modify_lines(whole_lines).each_with_index do |line, index|
|
modify_lines(whole_lines).each_with_index do |line, index|
|
||||||
if @prompt_proc
|
if @prompt_proc
|
||||||
pr = prompt_list[index]
|
pr = prompt_list[index]
|
||||||
height = render_partial(pr, calculate_width(pr), line, false)
|
height = render_partial(pr, calculate_width(pr), line, back, with_control: false)
|
||||||
else
|
else
|
||||||
height = render_partial(prompt, prompt_width, line, false)
|
height = render_partial(prompt, prompt_width, line, back, with_control: false)
|
||||||
end
|
end
|
||||||
if index < (@buffer_of_lines.size - 1)
|
if index < (@buffer_of_lines.size - 1)
|
||||||
move_cursor_down(height)
|
move_cursor_down(height)
|
||||||
|
|
|
@ -105,7 +105,8 @@ begin
|
||||||
|
|
||||||
def test_finish_autowrapped_line_in_the_middle_of_lines
|
def test_finish_autowrapped_line_in_the_middle_of_lines
|
||||||
start_terminal(20, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/bin/multiline_repl}, startup_message: 'Multiline REPL.')
|
start_terminal(20, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/bin/multiline_repl}, startup_message: 'Multiline REPL.')
|
||||||
write("[{'user'=>{'email'=>'abcdef@abcdef', 'id'=>'ABC'}, 'version'=>4, 'status'=>'succeeded'}]#{"\C-b"*7}\n")
|
write("[{'user'=>{'email'=>'abcdef@abcdef', 'id'=>'ABC'}, 'version'=>4, 'status'=>'succeeded'}]#{"\C-b"*7}")
|
||||||
|
write("\n")
|
||||||
close
|
close
|
||||||
assert_screen(<<~EOC)
|
assert_screen(<<~EOC)
|
||||||
Multiline REPL.
|
Multiline REPL.
|
||||||
|
@ -452,6 +453,147 @@ begin
|
||||||
EOC
|
EOC
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_longer_than_screen_height
|
||||||
|
start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/bin/multiline_repl}, startup_message: 'Multiline REPL.')
|
||||||
|
write(<<~EOC.chomp)
|
||||||
|
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
|
||||||
|
EOC
|
||||||
|
close
|
||||||
|
assert_screen(<<~EOC)
|
||||||
|
prompt> prompt
|
||||||
|
prompt> end
|
||||||
|
prompt> end
|
||||||
|
prompt> end
|
||||||
|
prompt> end
|
||||||
|
EOC
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_longer_than_screen_height_with_scroll_back
|
||||||
|
start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/bin/multiline_repl}, startup_message: 'Multiline REPL.')
|
||||||
|
write(<<~EOC.chomp)
|
||||||
|
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
|
||||||
|
EOC
|
||||||
|
write("\C-p" * 6)
|
||||||
|
close
|
||||||
|
assert_screen(<<~EOC)
|
||||||
|
prompt> rescue Terminate
|
||||||
|
LineInput
|
||||||
|
prompt> initialize_inp
|
||||||
|
ut
|
||||||
|
prompt> prompt
|
||||||
|
EOC
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_longer_than_screen_height_with_complex_scroll_back
|
||||||
|
start_terminal(4, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/bin/multiline_repl}, startup_message: 'Multiline REPL.')
|
||||||
|
write(<<~EOC.chomp)
|
||||||
|
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
|
||||||
|
EOC
|
||||||
|
sleep 0.3
|
||||||
|
write("\C-p" * 5)
|
||||||
|
write("\C-n" * 3)
|
||||||
|
close
|
||||||
|
assert_screen(<<~EOC)
|
||||||
|
ut
|
||||||
|
prompt> prompt
|
||||||
|
prompt> end
|
||||||
|
prompt> end
|
||||||
|
EOC
|
||||||
|
end
|
||||||
|
|
||||||
private def write_inputrc(content)
|
private def write_inputrc(content)
|
||||||
File.open(@inputrc_file, 'w') do |f|
|
File.open(@inputrc_file, 'w') do |f|
|
||||||
f.write content
|
f.write content
|
||||||
|
|
Загрузка…
Ссылка в новой задаче