diff options
author | aycabta <[email protected]> | 2020-08-28 02:09:34 +0900 |
---|---|---|
committer | aycabta <[email protected]> | 2020-08-28 11:05:18 +0900 |
commit | 1f09c4362806e3ce8a7b15e0effc3abb7f53411d (patch) | |
tree | 725e6234de6094359251a267e8f05d0435c9ed92 /lib/reline/unicode.rb | |
parent | cdd7d41046f6c91dfa8a1f0612dc686b79f6e849 (diff) |
[ruby/reline] Move width calculator methods to Reline::Unicode
https://github.com/ruby/reline/commit/f348ecd9f5
Diffstat (limited to 'lib/reline/unicode.rb')
-rw-r--r-- | lib/reline/unicode.rb | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/lib/reline/unicode.rb b/lib/reline/unicode.rb index 4b30f044f3..3b5ef6fb99 100644 --- a/lib/reline/unicode.rb +++ b/lib/reline/unicode.rb @@ -35,6 +35,12 @@ class Reline::Unicode } EscapedChars = EscapedPairs.keys.map(&:chr) + CSI_REGEXP = /\e\[[\d;]*[ABCDEFGHJKSTfminsuhl]/ + OSC_REGEXP = /\e\]\d+(?:;[^;]+)*\a/ + NON_PRINTING_START = "\1" + NON_PRINTING_END = "\2" + WIDTH_SCANNER = /\G(?:#{NON_PRINTING_START}|#{NON_PRINTING_END}|#{CSI_REGEXP}|#{OSC_REGEXP}|\X)/ + def self.get_mbchar_byte_size_by_first_char(c) # Checks UTF-8 character byte size case c.ord @@ -85,6 +91,68 @@ class Reline::Unicode end end + def self.calculate_width(str, allow_escape_code = false) + if allow_escape_code + width = 0 + rest = str.encode(Encoding::UTF_8) + in_zero_width = false + rest.scan(WIDTH_SCANNER) do |gc| + case gc + when NON_PRINTING_START + in_zero_width = true + when NON_PRINTING_END + in_zero_width = false + when CSI_REGEXP, OSC_REGEXP + else + unless in_zero_width + width += get_mbchar_width(gc) + end + end + end + width + else + str.encode(Encoding::UTF_8).grapheme_clusters.inject(0) { |w, gc| + w + get_mbchar_width(gc) + } + end + end + + def self.split_by_width(str, max_width, encoding) + lines = [String.new(encoding: encoding)] + height = 1 + width = 0 + rest = str.encode(Encoding::UTF_8) + in_zero_width = false + rest.scan(WIDTH_SCANNER) do |gc| + case gc + when NON_PRINTING_START + in_zero_width = true + when NON_PRINTING_END + in_zero_width = false + when CSI_REGEXP, OSC_REGEXP + lines.last << gc + else + unless in_zero_width + mbchar_width = get_mbchar_width(gc) + if (width += mbchar_width) > max_width + width = mbchar_width + lines << nil + lines << String.new(encoding: encoding) + height += 1 + end + end + lines.last << gc + end + end + # The cursor moves to next line in first + if width == max_width + lines << nil + lines << String.new(encoding: encoding) + height += 1 + end + [lines, height] + end + def self.get_next_mbchar_size(line, byte_pointer) grapheme = line.byteslice(byte_pointer..-1).grapheme_clusters.first grapheme ? grapheme.bytesize : 0 |