diff --git a/lib/reline/line_editor.rb b/lib/reline/line_editor.rb index bcd7cae1d1..74198491da 100644 --- a/lib/reline/line_editor.rb +++ b/lib/reline/line_editor.rb @@ -2029,8 +2029,16 @@ def finish last_byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer) @byte_pointer += bytesize last_mbchar = @line.byteslice((@byte_pointer - bytesize - last_byte_size), last_byte_size) - if last_byte_size != 0 and (last_mbchar + str).grapheme_clusters.size == 1 - width = 0 + combined_char = last_mbchar + str + if last_byte_size != 0 and combined_char.grapheme_clusters.size == 1 + # combined char + last_mbchar_width = Reline::Unicode.get_mbchar_width(last_mbchar) + combined_char_width = Reline::Unicode.get_mbchar_width(combined_char) + if combined_char_width > last_mbchar_width + width = combined_char_width - last_mbchar_width + else + width = 0 + end end @cursor += width @cursor_max += width diff --git a/lib/reline/unicode.rb b/lib/reline/unicode.rb index 80cc54a05e..6000c9f82a 100644 --- a/lib/reline/unicode.rb +++ b/lib/reline/unicode.rb @@ -79,6 +79,8 @@ def self.escape_for_print(str) require 'reline/unicode/east_asian_width' + HalfwidthDakutenHandakuten = /[\u{FF9E}\u{FF9F}]/ + MBCharWidthRE = / (? [#{ EscapedChars.map {|c| "\\x%02x" % c.ord }.join }] (?# ^ + char, such as ^M, ^H, ^[, ...) @@ -93,6 +95,12 @@ def self.escape_for_print(str) #{ EastAsianWidth::TYPE_H } | #{ EastAsianWidth::TYPE_NA } | #{ EastAsianWidth::TYPE_N } + )(?!#{ HalfwidthDakutenHandakuten }) + | (? + (?: #{ EastAsianWidth::TYPE_H } + | #{ EastAsianWidth::TYPE_NA } + | #{ EastAsianWidth::TYPE_N }) + #{ HalfwidthDakutenHandakuten } ) | (? #{EastAsianWidth::TYPE_A} @@ -109,7 +117,7 @@ def self.get_mbchar_width(mbchar) m = mbchar.encode(Encoding::UTF_8).match(MBCharWidthRE) case when m.nil? then 1 # TODO should be U+FFFD � REPLACEMENT CHARACTER - when m[:width_2_1], m[:width_2_2] then 2 + when m[:width_2_1], m[:width_2_2], m[:width_2_3] then 2 when m[:width_3] then 3 when m[:width_0] then 0 when m[:width_1] then 1 diff --git a/test/reline/test_key_actor_emacs.rb b/test/reline/test_key_actor_emacs.rb index 5ace062cc2..fb879e5fcd 100644 --- a/test/reline/test_key_actor_emacs.rb +++ b/test/reline/test_key_actor_emacs.rb @@ -2306,6 +2306,22 @@ def test_ed_argument_digit_by_meta_num assert_line('abcd') end + def test_halfwidth_kana_width_dakuten + input_keys('ガギゲゴ') + assert_byte_pointer_size('ガギゲゴ') + assert_cursor(8) + assert_cursor_max(8) + input_keys("\C-b\C-b", false) + assert_byte_pointer_size('ガギ') + assert_cursor(4) + assert_cursor_max(8) + input_keys('グ', false) + assert_byte_pointer_size('ガギグ') + assert_cursor(6) + assert_cursor_max(10) + assert_line('ガギグゲゴ') + end + def test_input_unknown_char input_keys('͸') # U+0378 (unassigned) assert_line('͸')