Skip to content

Commit 094dcd4

Browse files
authored
Use cursor-x-coordinate instead of byte_pointer in em_exchange_mark (#868)
Marked byte_position could be an invalid byte position when the marked line is edited. Use cursor position and move to the nearest valid position instead.
1 parent 16a026e commit 094dcd4

2 files changed

Lines changed: 42 additions & 12 deletions

File tree

lib/reline/line_editor.rb

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ def eof?
224224

225225
def reset_variables(prompt = '')
226226
@prompt = prompt.gsub("\n", "\\n")
227-
@mark_pointer = nil
227+
@mark_position = nil
228228
@is_multiline = false
229229
@finished = false
230230
@history_pointer = nil
@@ -2318,15 +2318,22 @@ def finish
23182318
end
23192319

23202320
private def em_set_mark(key)
2321-
@mark_pointer = [@byte_pointer, @line_index]
2321+
cursor_column = Reline::Unicode.calculate_width(current_line.byteslice(0, @byte_pointer))
2322+
@mark_position = [@line_index, cursor_column]
23222323
end
23232324
alias_method :set_mark, :em_set_mark
23242325

23252326
private def em_exchange_mark(key)
2326-
return unless @mark_pointer
2327-
new_pointer = [@byte_pointer, @line_index]
2328-
@byte_pointer, @line_index = @mark_pointer
2329-
@mark_pointer = new_pointer
2327+
return unless @mark_position
2328+
line_index, cursor_column = @mark_position
2329+
em_set_mark(key)
2330+
if @buffer_of_lines.size <= line_index
2331+
@line_index = @buffer_of_lines.size - 1
2332+
@byte_pointer = current_line.bytesize
2333+
else
2334+
@line_index = line_index
2335+
calculate_nearest_cursor(cursor_column)
2336+
end
23302337
end
23312338
alias_method :exchange_point_and_mark, :em_exchange_mark
23322339

test/reline/test_key_actor_emacs.rb

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1245,27 +1245,50 @@ def test_em_set_mark_and_em_exchange_mark
12451245
assert_line_around_cursor('aaa bbb ccc ddd', '')
12461246
input_keys("\C-a\eF\eF")
12471247
assert_line_around_cursor('aaa bbb', ' ccc ddd')
1248-
assert_equal(nil, @line_editor.instance_variable_get(:@mark_pointer))
1248+
assert_equal(nil, @line_editor.instance_variable_get(:@mark_position))
12491249
input_keys("\x00") # C-Space
12501250
assert_line_around_cursor('aaa bbb', ' ccc ddd')
1251-
assert_equal([7, 0], @line_editor.instance_variable_get(:@mark_pointer))
1251+
assert_equal([0, 7], @line_editor.instance_variable_get(:@mark_position))
12521252
input_keys("\C-a")
12531253
assert_line_around_cursor('', 'aaa bbb ccc ddd')
1254-
assert_equal([7, 0], @line_editor.instance_variable_get(:@mark_pointer))
1254+
assert_equal([0, 7], @line_editor.instance_variable_get(:@mark_position))
12551255
input_key_by_symbol(:em_exchange_mark)
12561256
assert_line_around_cursor('aaa bbb', ' ccc ddd')
1257-
assert_equal([0, 0], @line_editor.instance_variable_get(:@mark_pointer))
1257+
assert_equal([0, 0], @line_editor.instance_variable_get(:@mark_position))
12581258
end
12591259

12601260
def test_em_exchange_mark_without_mark
12611261
input_keys('aaa bbb ccc ddd')
12621262
assert_line_around_cursor('aaa bbb ccc ddd', '')
12631263
input_keys("\C-a\ef")
12641264
assert_line_around_cursor('aaa', ' bbb ccc ddd')
1265-
assert_equal(nil, @line_editor.instance_variable_get(:@mark_pointer))
1265+
assert_equal(nil, @line_editor.instance_variable_get(:@mark_position))
12661266
input_key_by_symbol(:em_exchange_mark)
12671267
assert_line_around_cursor('aaa', ' bbb ccc ddd')
1268-
assert_equal(nil, @line_editor.instance_variable_get(:@mark_pointer))
1268+
assert_equal(nil, @line_editor.instance_variable_get(:@mark_position))
1269+
end
1270+
1271+
def test_em_exchange_mark_multibyte
1272+
input_keys("aaaaaaaaaaあああああ")
1273+
input_keys("\C-b\C-b")
1274+
assert_line_around_cursor('aaaaaaaaaaあああ', 'ああ')
1275+
input_keys("\x00") # C-Space
1276+
input_keys("\C-e\C-w")
1277+
input_keys("ああbbbbbああああああ")
1278+
input_key_by_symbol(:em_exchange_mark)
1279+
assert_line_around_cursor('ああbbbbbあああ', 'あああ')
1280+
end
1281+
1282+
def test_em_exchange_mark_line_disappear
1283+
input_key_by_symbol(:insert_multiline_text, char: "aaa\nbbb\nccc")
1284+
input_keys("\C-b\C-b")
1285+
input_keys("\x00") # C-Space
1286+
assert_line_around_cursor('c', 'cc')
1287+
input_keys("\C-a\C-h\C-p\C-a")
1288+
assert_line_around_cursor('', 'aaa')
1289+
input_key_by_symbol(:em_exchange_mark)
1290+
# If mark line does not exist, moves to the end of the input
1291+
assert_line_around_cursor('bbbccc', '')
12691292
end
12701293

12711294
def test_modify_lines_with_wrong_rs

0 commit comments

Comments
 (0)