Skip to content

Commit

Permalink
Fix line wrapped cursor position
Browse files Browse the repository at this point in the history
Cursor position calculation was wrong when the input line contains "\1" or CSI escape sequence.
  • Loading branch information
tompng committed Dec 9, 2024
1 parent 6a7e249 commit 3aad601
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 1 deletion.
2 changes: 1 addition & 1 deletion lib/reline/line_editor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,7 @@ def render_line_differential(old_items, new_items)
# Calculate cursor position in word wrapped content.
def wrapped_cursor_position
prompt_width = calculate_width(prompt_list[@line_index], true)
line_before_cursor = whole_lines[@line_index].byteslice(0, @byte_pointer)
line_before_cursor = Reline::Unicode.escape_for_print(whole_lines[@line_index].byteslice(0, @byte_pointer))
wrapped_line_before_cursor = split_line_by_width(' ' * prompt_width + line_before_cursor, screen_width)
wrapped_cursor_y = wrapped_prompt_and_input_lines[0...@line_index].sum(&:size) + wrapped_line_before_cursor.size - 1
wrapped_cursor_x = calculate_width(wrapped_line_before_cursor.last)
Expand Down
29 changes: 29 additions & 0 deletions test/reline/test_line_editor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,35 @@ def test_retrieve_completion_quote
end
end

class CursorPositionTest < Reline::TestCase
def setup
@line_editor = Reline::LineEditor.new(nil)
@line_editor.instance_variable_set(:@config, Reline::Config.new)
end

def test_cursor_position_with_escaped_input
@line_editor.instance_variable_set(:@screen_size, [4, 16])
@line_editor.instance_variable_set(:@prompt, "\e[1mprompt\e[0m> ")
@line_editor.instance_variable_set(:@buffer_of_lines, ["\e[1m\0\1\2\3\4\5\6\7abcd"])
@line_editor.instance_variable_set(:@line_index, 0)
# prompt> ^[[1m^@^
# A^B^C^D^E^F^Gabc
# d
@line_editor.instance_variable_set(:@byte_pointer, 0)
assert_equal [8, 0], @line_editor.wrapped_cursor_position
@line_editor.instance_variable_set(:@byte_pointer, 5)
assert_equal [15, 0], @line_editor.wrapped_cursor_position
@line_editor.instance_variable_set(:@byte_pointer, 6)
assert_equal [1, 1], @line_editor.wrapped_cursor_position
@line_editor.instance_variable_set(:@byte_pointer, 14)
assert_equal [15, 1], @line_editor.wrapped_cursor_position
@line_editor.instance_variable_set(:@byte_pointer, 15)
assert_equal [0, 2], @line_editor.wrapped_cursor_position
@line_editor.instance_variable_set(:@byte_pointer, 16)
assert_equal [1, 2], @line_editor.wrapped_cursor_position
end
end

class RenderLineDifferentialTest < Reline::TestCase
class TestIO < Reline::IO
def write(string)
Expand Down

0 comments on commit 3aad601

Please sign in to comment.