diff --git a/lib/reline/line_editor.rb b/lib/reline/line_editor.rb index bfffd17d59..91ffcf6431 100644 --- a/lib/reline/line_editor.rb +++ b/lib/reline/line_editor.rb @@ -223,7 +223,7 @@ def eof? def reset_variables(prompt = '') @prompt = prompt.gsub("\n", "\\n") - @mark_pointer = nil + @mark_position = nil @is_multiline = false @finished = false @history_pointer = nil @@ -2303,15 +2303,22 @@ def finish end private def em_set_mark(key) - @mark_pointer = [@byte_pointer, @line_index] + cursor_column = Reline::Unicode.calculate_width(current_line.byteslice(0, @byte_pointer)) + @mark_position = [@line_index, cursor_column] end alias_method :set_mark, :em_set_mark private def em_exchange_mark(key) - return unless @mark_pointer - new_pointer = [@byte_pointer, @line_index] - @byte_pointer, @line_index = @mark_pointer - @mark_pointer = new_pointer + return unless @mark_position + line_index, cursor_column = @mark_position + em_set_mark(key) + if @buffer_of_lines.size <= line_index + @line_index = @buffer_of_lines.size - 1 + @byte_pointer = current_line.bytesize + else + @line_index = line_index + calculate_nearest_cursor(cursor_column) + end end alias_method :exchange_point_and_mark, :em_exchange_mark diff --git a/test/reline/test_key_actor_emacs.rb b/test/reline/test_key_actor_emacs.rb index aa608641c3..532c0f17dd 100644 --- a/test/reline/test_key_actor_emacs.rb +++ b/test/reline/test_key_actor_emacs.rb @@ -1245,16 +1245,16 @@ def test_em_set_mark_and_em_exchange_mark assert_line_around_cursor('aaa bbb ccc ddd', '') input_keys("\C-a\eF\eF") assert_line_around_cursor('aaa bbb', ' ccc ddd') - assert_equal(nil, @line_editor.instance_variable_get(:@mark_pointer)) + assert_equal(nil, @line_editor.instance_variable_get(:@mark_position)) input_keys("\x00") # C-Space assert_line_around_cursor('aaa bbb', ' ccc ddd') - assert_equal([7, 0], @line_editor.instance_variable_get(:@mark_pointer)) + assert_equal([0, 7], @line_editor.instance_variable_get(:@mark_position)) input_keys("\C-a") assert_line_around_cursor('', 'aaa bbb ccc ddd') - assert_equal([7, 0], @line_editor.instance_variable_get(:@mark_pointer)) + assert_equal([0, 7], @line_editor.instance_variable_get(:@mark_position)) input_key_by_symbol(:em_exchange_mark) assert_line_around_cursor('aaa bbb', ' ccc ddd') - assert_equal([0, 0], @line_editor.instance_variable_get(:@mark_pointer)) + assert_equal([0, 0], @line_editor.instance_variable_get(:@mark_position)) end def test_em_exchange_mark_without_mark @@ -1262,10 +1262,33 @@ def test_em_exchange_mark_without_mark assert_line_around_cursor('aaa bbb ccc ddd', '') input_keys("\C-a\ef") assert_line_around_cursor('aaa', ' bbb ccc ddd') - assert_equal(nil, @line_editor.instance_variable_get(:@mark_pointer)) + assert_equal(nil, @line_editor.instance_variable_get(:@mark_position)) input_key_by_symbol(:em_exchange_mark) assert_line_around_cursor('aaa', ' bbb ccc ddd') - assert_equal(nil, @line_editor.instance_variable_get(:@mark_pointer)) + assert_equal(nil, @line_editor.instance_variable_get(:@mark_position)) + end + + def test_em_exchange_mark_multibyte + input_keys("aaaaaaaaaaあああああ") + input_keys("\C-b\C-b") + assert_line_around_cursor('aaaaaaaaaaあああ', 'ああ') + input_keys("\x00") # C-Space + input_keys("\C-e\C-w") + input_keys("ああbbbbbああああああ") + input_key_by_symbol(:em_exchange_mark) + assert_line_around_cursor('ああbbbbbあああ', 'あああ') + end + + def test_em_exchange_mark_line_disappear + input_key_by_symbol(:insert_multiline_text, char: "aaa\nbbb\nccc") + input_keys("\C-b\C-b") + input_keys("\x00") # C-Space + assert_line_around_cursor('c', 'cc') + input_keys("\C-a\C-h\C-p\C-a") + assert_line_around_cursor('', 'aaa') + input_key_by_symbol(:em_exchange_mark) + # If mark line does not exist, moves to the end of the input + assert_line_around_cursor('bbbccc', '') end def test_modify_lines_with_wrong_rs