aboutsummaryrefslogtreecommitdiffstats
path: root/lib/reline/unicode.rb
diff options
context:
space:
mode:
authoraycabta <aycabta@gmail.com>2020-08-28 02:09:34 +0900
committeraycabta <aycabta@gmail.com>2020-08-28 11:05:18 +0900
commit1f09c4362806e3ce8a7b15e0effc3abb7f53411d (patch)
tree725e6234de6094359251a267e8f05d0435c9ed92 /lib/reline/unicode.rb
parentcdd7d41046f6c91dfa8a1f0612dc686b79f6e849 (diff)
downloadruby-1f09c4362806e3ce8a7b15e0effc3abb7f53411d.tar.gz
[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.rb68
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