mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
[ruby/reline] Move width calculator methods to Reline::Unicode
https://github.com/ruby/reline/commit/f348ecd9f5
This commit is contained in:
parent
cdd7d41046
commit
1f09c43628
2 changed files with 72 additions and 64 deletions
|
@ -50,12 +50,6 @@ class Reline::LineEditor
|
||||||
CompletionJourneyData = Struct.new('CompletionJourneyData', :preposing, :postposing, :list, :pointer)
|
CompletionJourneyData = Struct.new('CompletionJourneyData', :preposing, :postposing, :list, :pointer)
|
||||||
MenuInfo = Struct.new('MenuInfo', :target, :list)
|
MenuInfo = Struct.new('MenuInfo', :target, :list)
|
||||||
|
|
||||||
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 initialize(config, encoding)
|
def initialize(config, encoding)
|
||||||
@config = config
|
@config = config
|
||||||
@completion_append_character = ''
|
@completion_append_character = ''
|
||||||
|
@ -234,40 +228,8 @@ class Reline::LineEditor
|
||||||
width.div(@screen_size.last) + 1
|
width.div(@screen_size.last) + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
private def split_by_width(prompt, str, max_width)
|
private def split_by_width(str, max_width)
|
||||||
lines = [String.new(encoding: @encoding)]
|
Reline::Unicode.split_by_width(str, max_width, @encoding)
|
||||||
height = 1
|
|
||||||
width = 0
|
|
||||||
rest = "#{prompt}#{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 = Reline::Unicode.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
|
end
|
||||||
|
|
||||||
private def scroll_down(val)
|
private def scroll_down(val)
|
||||||
|
@ -511,7 +473,7 @@ class Reline::LineEditor
|
||||||
end
|
end
|
||||||
|
|
||||||
private def render_partial(prompt, prompt_width, line_to_render, with_control = true)
|
private def render_partial(prompt, prompt_width, line_to_render, with_control = true)
|
||||||
visual_lines, height = split_by_width(prompt, line_to_render.nil? ? '' : line_to_render, @screen_size.last)
|
visual_lines, height = split_by_width(line_to_render.nil? ? prompt : prompt + line_to_render, @screen_size.last)
|
||||||
if with_control
|
if with_control
|
||||||
if height > @highest_in_this
|
if height > @highest_in_this
|
||||||
diff = height - @highest_in_this
|
diff = height - @highest_in_this
|
||||||
|
@ -1081,29 +1043,7 @@ class Reline::LineEditor
|
||||||
end
|
end
|
||||||
|
|
||||||
private def calculate_width(str, allow_escape_code = false)
|
private def calculate_width(str, allow_escape_code = false)
|
||||||
if allow_escape_code
|
Reline::Unicode.calculate_width(str, 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 += Reline::Unicode.get_mbchar_width(gc)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
width
|
|
||||||
else
|
|
||||||
str.encode(Encoding::UTF_8).grapheme_clusters.inject(0) { |w, gc|
|
|
||||||
w + Reline::Unicode.get_mbchar_width(gc)
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private def key_delete(key)
|
private def key_delete(key)
|
||||||
|
|
|
@ -35,6 +35,12 @@ class Reline::Unicode
|
||||||
}
|
}
|
||||||
EscapedChars = EscapedPairs.keys.map(&:chr)
|
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)
|
def self.get_mbchar_byte_size_by_first_char(c)
|
||||||
# Checks UTF-8 character byte size
|
# Checks UTF-8 character byte size
|
||||||
case c.ord
|
case c.ord
|
||||||
|
@ -85,6 +91,68 @@ class Reline::Unicode
|
||||||
end
|
end
|
||||||
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)
|
def self.get_next_mbchar_size(line, byte_pointer)
|
||||||
grapheme = line.byteslice(byte_pointer..-1).grapheme_clusters.first
|
grapheme = line.byteslice(byte_pointer..-1).grapheme_clusters.first
|
||||||
grapheme ? grapheme.bytesize : 0
|
grapheme ? grapheme.bytesize : 0
|
||||||
|
|
Loading…
Add table
Reference in a new issue