Skip to content

Commit

Permalink
[ruby/reline] Expand the scanned array to later case statement more
Browse files Browse the repository at this point in the history
straightforward
(ruby/reline#526)

* Improve test coverage on Unicode.take_range

* Add test for Unicode.calculate_width

* Expand the scanned array to later case statement more straightforward
  • Loading branch information
st0012 authored and matzbot committed Mar 28, 2023
1 parent 417b1a3 commit 1e9a218
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 31 deletions.
54 changes: 23 additions & 31 deletions lib/reline/unicode.rb
Expand Up @@ -40,11 +40,6 @@ class Reline::Unicode
CSI_REGEXP = /\e\[[\d;]*[ABCDEFGHJKSTfminsuhl]/
OSC_REGEXP = /\e\]\d+(?:;[^;]+)*\a/
WIDTH_SCANNER = /\G(?:(#{NON_PRINTING_START})|(#{NON_PRINTING_END})|(#{CSI_REGEXP})|(#{OSC_REGEXP})|(\X))/o
NON_PRINTING_START_INDEX = 0
NON_PRINTING_END_INDEX = 1
CSI_REGEXP_INDEX = 2
OSC_REGEXP_INDEX = 3
GRAPHEME_CLUSTER_INDEX = 4

def self.get_mbchar_byte_size_by_first_char(c)
# Checks UTF-8 character byte size
Expand Down Expand Up @@ -132,15 +127,14 @@ def self.calculate_width(str, allow_escape_code = false)
width = 0
rest = str.encode(Encoding::UTF_8)
in_zero_width = false
rest.scan(WIDTH_SCANNER) do |gc|
rest.scan(WIDTH_SCANNER) do |non_printing_start, non_printing_end, csi, osc, gc|
case
when gc[NON_PRINTING_START_INDEX]
when non_printing_start
in_zero_width = true
when gc[NON_PRINTING_END_INDEX]
when non_printing_end
in_zero_width = false
when gc[CSI_REGEXP_INDEX], gc[OSC_REGEXP_INDEX]
when gc[GRAPHEME_CLUSTER_INDEX]
gc = gc[GRAPHEME_CLUSTER_INDEX]
when csi, osc
when gc
unless in_zero_width
width += get_mbchar_width(gc)
end
Expand All @@ -161,22 +155,21 @@ def self.split_by_width(str, max_width, encoding = str.encoding)
rest = str.encode(Encoding::UTF_8)
in_zero_width = false
seq = String.new(encoding: encoding)
rest.scan(WIDTH_SCANNER) do |gc|
rest.scan(WIDTH_SCANNER) do |non_printing_start, non_printing_end, csi, osc, gc|
case
when gc[NON_PRINTING_START_INDEX]
when non_printing_start
in_zero_width = true
lines.last << NON_PRINTING_START
when gc[NON_PRINTING_END_INDEX]
when non_printing_end
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]
when csi
lines.last << csi
seq << csi
when osc
lines.last << osc
seq << osc
when gc
unless in_zero_width
mbchar_width = get_mbchar_width(gc)
if (width += mbchar_width) > max_width
Expand Down Expand Up @@ -204,18 +197,17 @@ def self.take_range(str, start_col, max_width, encoding = str.encoding)
total_width = 0
rest = str.encode(Encoding::UTF_8)
in_zero_width = false
rest.scan(WIDTH_SCANNER) do |gc|
rest.scan(WIDTH_SCANNER) do |non_printing_start, non_printing_end, csi, osc, gc|
case
when gc[NON_PRINTING_START_INDEX]
when non_printing_start
in_zero_width = true
when gc[NON_PRINTING_END_INDEX]
when non_printing_end
in_zero_width = false
when gc[CSI_REGEXP_INDEX]
chunk << gc[CSI_REGEXP_INDEX]
when gc[OSC_REGEXP_INDEX]
chunk << gc[OSC_REGEXP_INDEX]
when gc[GRAPHEME_CLUSTER_INDEX]
gc = gc[GRAPHEME_CLUSTER_INDEX]
when csi
chunk << csi
when osc
chunk << osc
when gc
if in_zero_width
chunk << gc
else
Expand Down
20 changes: 20 additions & 0 deletions test/reline/test_unicode.rb
Expand Up @@ -29,6 +29,26 @@ def test_split_by_width

def test_take_range
assert_equal 'cdef', Reline::Unicode.take_range('abcdefghi', 2, 4)
assert_equal 'あde', Reline::Unicode.take_range('abあdef', 2, 4)
assert_equal 'zerocdef', Reline::Unicode.take_range("ab\1zero\2cdef", 2, 4)
assert_equal 'bzerocde', Reline::Unicode.take_range("ab\1zero\2cdef", 1, 4)
assert_equal "\e[31mcd\e[42mef", Reline::Unicode.take_range("\e[31mabcd\e[42mefg", 2, 4)
assert_equal "\e]0;1\acd", Reline::Unicode.take_range("ab\e]0;1\acd", 2, 3)
assert_equal 'いう', Reline::Unicode.take_range('あいうえお', 2, 4)
end

def test_calculate_width
assert_equal 9, Reline::Unicode.calculate_width('abcdefghi')
assert_equal 9, Reline::Unicode.calculate_width('abcdefghi', true)
assert_equal 7, Reline::Unicode.calculate_width('abあdef')
assert_equal 7, Reline::Unicode.calculate_width('abあdef', true)
assert_equal 14, Reline::Unicode.calculate_width("ab\1zero\2cdef")
assert_equal 6, Reline::Unicode.calculate_width("ab\1zero\2cdef", true)
assert_equal 19, Reline::Unicode.calculate_width("\e[31mabcd\e[42mefg")
assert_equal 7, Reline::Unicode.calculate_width("\e[31mabcd\e[42mefg", true)
assert_equal 12, Reline::Unicode.calculate_width("ab\e]0;1\acd")
assert_equal 4, Reline::Unicode.calculate_width("ab\e]0;1\acd", true)
assert_equal 10, Reline::Unicode.calculate_width('あいうえお')
assert_equal 10, Reline::Unicode.calculate_width('あいうえお', true)
end
end

0 comments on commit 1e9a218

Please sign in to comment.