[ruby/reline] Fix split_by_width to retain color sequences

(https://github.com/ruby/reline/pull/490)

* Fix split_by_width to retain color sequences

* Add OSC escape sequence testcase of Reline::Unicode.split_by_width
This commit is contained in:
tomoya ishida 2023-03-26 00:01:30 +09:00 committed by git
parent 9bc2dbd33c
commit 60ca800d4f
2 changed files with 15 additions and 1 deletions

View file

@ -160,16 +160,21 @@ class Reline::Unicode
width = 0
rest = str.encode(Encoding::UTF_8)
in_zero_width = false
seq = String.new(encoding: encoding)
rest.scan(WIDTH_SCANNER) do |gc|
case
when gc[NON_PRINTING_START_INDEX]
in_zero_width = true
lines.last << NON_PRINTING_START
when gc[NON_PRINTING_END_INDEX]
in_zero_width = false
lines.last << NON_PRINTING_END
when gc[CSI_REGEXP_INDEX]
lines.last << gc[CSI_REGEXP_INDEX]
seq << gc[CSI_REGEXP_INDEX]
when gc[OSC_REGEXP_INDEX]
lines.last << gc[OSC_REGEXP_INDEX]
seq << gc[OSC_REGEXP_INDEX]
when gc[GRAPHEME_CLUSTER_INDEX]
gc = gc[GRAPHEME_CLUSTER_INDEX]
unless in_zero_width
@ -177,7 +182,7 @@ class Reline::Unicode
if (width += mbchar_width) > max_width
width = mbchar_width
lines << nil
lines << String.new(encoding: encoding)
lines << seq.dup
height += 1
end
end

View file

@ -18,6 +18,15 @@ class Reline::Unicode::Test < Reline::TestCase
assert_equal 2, Reline::Unicode.calculate_width('√', true)
end
def test_split_by_width
assert_equal [['abc', nil, 'de'], 2], Reline::Unicode.split_by_width('abcde', 3)
assert_equal [['abc', nil, 'def', nil, ''], 3], Reline::Unicode.split_by_width('abcdef', 3)
assert_equal [['ab', nil, 'あd', nil, 'ef'], 3], Reline::Unicode.split_by_width('abあdef', 3)
assert_equal [["ab\1zero\2c", nil, 'def', nil, ''], 3], Reline::Unicode.split_by_width("ab\1zero\2cdef", 3)
assert_equal [["\e[31mabc", nil, "\e[31md\e[42mef", nil, "\e[31m\e[42mg"], 3], Reline::Unicode.split_by_width("\e[31mabcd\e[42mefg", 3)
assert_equal [["ab\e]0;1\ac", nil, "\e]0;1\ad"], 2], Reline::Unicode.split_by_width("ab\e]0;1\acd", 3)
end
def test_take_range
assert_equal 'cdef', Reline::Unicode.take_range('abcdefghi', 2, 4)
assert_equal 'いう', Reline::Unicode.take_range('あいうえお', 2, 4)