From 16d68a57e5da61e0cddfc30379881f2e8ac41e3c Mon Sep 17 00:00:00 2001 From: tompng Date: Fri, 3 Nov 2023 17:44:46 +0900 Subject: [PATCH] Consider fullwidth take_range in differential rendering --- lib/reline/line_editor.rb | 17 ++++++----------- test/reline/test_line_editor.rb | 30 ++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/lib/reline/line_editor.rb b/lib/reline/line_editor.rb index 6877a0409c..79ff744130 100644 --- a/lib/reline/line_editor.rb +++ b/lib/reline/line_editor.rb @@ -373,9 +373,11 @@ def render_line_differential(old_items, new_items) Reline::IOGate.move_cursor_column base_x @output.write "\e[0m#{' ' * width}" else - x, w, content = new_items[level] - content = Reline::Unicode.take_range(content, base_x - x, width) unless x == base_x && w == width - Reline::IOGate.move_cursor_column base_x + x, _w, content = new_items[level] + cover_begin = base_x != 0 && new_levels[base_x - 1] == level + cover_end = new_levels[base_x + width] == level + content, pos = Reline::Unicode.take_mbchar_range(content, base_x - x, width, cover_begin: cover_begin, cover_end: cover_end, padding: true) + Reline::IOGate.move_cursor_column x + pos @output.write "\e[0m#{content}\e[0m" end base_x += width @@ -654,13 +656,6 @@ def add_dialog_proc(name, p, context = nil) DIALOG_DEFAULT_HEIGHT = 20 - private def padding_space_with_escape_sequences(str, width) - padding_width = width - calculate_width(str, true) - # padding_width should be only positive value. But macOS and Alacritty returns negative value. - padding_width = 0 if padding_width < 0 - str + (' ' * padding_width) - end - private def dialog_range(dialog, dialog_y) x_range = dialog.column...dialog.column + dialog.width y_range = dialog_y + dialog.vertical_offset...dialog_y + dialog.vertical_offset + dialog.contents.size @@ -734,7 +729,7 @@ def add_dialog_proc(name, p, context = nil) dialog.contents = contents.map.with_index do |item, i| line_sgr = i == pointer ? enhanced_sgr : default_sgr str_width = dialog.width - (scrollbar_pos.nil? ? 0 : @block_elem_width) - str = padding_space_with_escape_sequences(Reline::Unicode.take_range(item, 0, str_width), str_width) + str, = Reline::Unicode.take_mbchar_range(item, 0, str_width, padding: true) colored_content = "#{line_sgr}#{str}" if scrollbar_pos if scrollbar_pos <= (i * 2) and (i * 2 + 1) < (scrollbar_pos + bar_height) diff --git a/test/reline/test_line_editor.rb b/test/reline/test_line_editor.rb index a5fcc3e2a1..016fbc8c3f 100644 --- a/test/reline/test_line_editor.rb +++ b/test/reline/test_line_editor.rb @@ -106,6 +106,36 @@ def test_dialog_move end end + def test_multibyte + base = [0, 12, '一二三一二三'] + left = [0, 3, 'LLL'] + right = [9, 3, 'RRR'] + front = [3, 6, 'FFFFFF'] + # 一 FFFFF 三 + # 一二三一二三 + assert_output '[COL_2]二三一二' do + @line_editor.render_line_differential([base, front], [base, nil]) + end + + # LLLFFFFF 三 + # LLL 三一二三 + assert_output '[COL_3] 三一二' do + @line_editor.render_line_differential([base, left, front], [base, left, nil]) + end + + # 一 FFFFFRRR + # 一二三一 RRR + assert_output '[COL_2]二三一 ' do + @line_editor.render_line_differential([base, right, front], [base, right, nil]) + end + + # LLLFFFFFRRR + # LLL 三一 RRR + assert_output '[COL_3] 三一 ' do + @line_editor.render_line_differential([base, left, right, front], [base, left, right, nil]) + end + end + def test_complex state_a = [nil, [19, 7, 'bbbbbbb'], [15, 8, 'cccccccc'], [10, 5, 'ddddd'], [18, 4, 'eeee'], [1, 3, 'fff'], [17, 2, 'gg'], [7, 1, 'h']] state_b = [[5, 9, 'aaaaaaaaa'], nil, [15, 8, 'cccccccc'], nil, [18, 4, 'EEEE'], [25, 4, 'ffff'], [17, 2, 'gg'], [2, 2, 'hh']]