class Unicode::DisplayWidth

Constants

ASCII_NON_ZERO_REGEX
DATA_DIRECTORY
FIRST_4096
INDEX
INDEX_FILENAME
INITIAL_DEPTH
UNICODE_VERSION
VERSION

Public Class Methods

decompress_index(index, level) click to toggle source
# File lib/unicode/display_width/index.rb, line 13
def self.decompress_index(index, level)
  index.flat_map{ |value|
    if level > 0
      if value.instance_of?(Array)
        value[15] ||= nil
        decompress_index(value, level - 1)
      else
        decompress_index([value] * 16, level - 1)
      end
    else
      if value.instance_of?(Array)
        value[15] ||= nil
        value
      else
        [value] * 16
      end
    end
  }
end
emoji_extra_width_of(string, ambiguous = 1, overwrite = {}, _ = {}) click to toggle source
# File lib/unicode/display_width.rb, line 85
def self.emoji_extra_width_of(string, ambiguous = 1, overwrite = {}, _ = {})
  require "unicode/emoji"

  extra_width = 0
  modifier_regex = /[#{ Unicode::Emoji::EMOJI_MODIFIERS.pack("U*") }]/
  zwj_regex = /(?<=#{ [Unicode::Emoji::ZWJ].pack("U") })./

  string.scan(Unicode::Emoji::REGEX){ |emoji|
    extra_width += 2 * emoji.scan(modifier_regex).size

    emoji.scan(zwj_regex){ |zwj_succ|
      extra_width += self.of(zwj_succ, ambiguous, overwrite)
    }
  }

  extra_width
end
new(ambiguous: 1, overwrite: {}, emoji: false) click to toggle source
# File lib/unicode/display_width.rb, line 103
def initialize(ambiguous: 1, overwrite: {}, emoji: false)
  @ambiguous = ambiguous
  @overwrite = overwrite
  @emoji     = emoji
end
of(string, ambiguous = 1, overwrite = {}, options = {}) click to toggle source
# File lib/unicode/display_width.rb, line 11
def self.of(string, ambiguous = 1, overwrite = {}, options = {})
  if overwrite.empty?
    # Optimization for ASCII-only strings without certain control symbols
    if string.ascii_only?
      if string.match?(ASCII_NON_ZERO_REGEX)
        res = string.gsub(ASCII_NON_ZERO_REGEX, "").size - string.count("\b")
        res < 0 ? 0 : res
      else
        string.size
      end
    else
      width_no_overwrite(string, ambiguous, options)
    end
  else
    width_all_features(string, ambiguous, overwrite, options)
  end
end
width_all_features(string, ambiguous, overwrite, options) click to toggle source

Same as .width_no_overwrite - but with applying overwrites for each char

# File lib/unicode/display_width.rb, line 56
def self.width_all_features(string, ambiguous, overwrite, options)
  # Sum of all chars widths
  res = string.codepoints.sum{ |codepoint|
    next overwrite[codepoint] if overwrite[codepoint]

    if codepoint > 15 && codepoint < 161 # very common
      next 1
    elsif codepoint < 0x1001
      width = FIRST_4096[codepoint]
    else
      width = INDEX
      depth = INITIAL_DEPTH
      while (width = width[codepoint / depth]).instance_of? Array
        codepoint %= depth
        depth /= 16
      end
    end

    width == :A ? ambiguous : (width || 1)
  }

  # Substract emoji error
  res -= emoji_extra_width_of(string, ambiguous, overwrite) if options[:emoji]

  # Return result + prevent negative lengths
  res < 0 ? 0 : res
end
width_no_overwrite(string, ambiguous, options = {}) click to toggle source
# File lib/unicode/display_width.rb, line 29
def self.width_no_overwrite(string, ambiguous, options = {})
  # Sum of all chars widths
  res = string.codepoints.sum{ |codepoint|
    if codepoint > 15 && codepoint < 161 # very common
      next 1
    elsif codepoint < 0x1001
      width = FIRST_4096[codepoint]
    else
      width = INDEX
      depth = INITIAL_DEPTH
      while (width = width[codepoint / depth]).instance_of? Array
        codepoint %= depth
        depth /= 16
      end
    end

    width == :A ? ambiguous : (width || 1)
  }

  # Substract emoji error
  res -= emoji_extra_width_of(string, ambiguous) if options[:emoji]

  # Return result + prevent negative lengths
  res < 0 ? 0 : res
end

Public Instance Methods

get_config(**kwargs) click to toggle source
# File lib/unicode/display_width.rb, line 109
def get_config(**kwargs)
  [
    kwargs[:ambiguous] || @ambiguous,
    kwargs[:overwrite] || @overwrite,
    { emoji: kwargs[:emoji] || @emoji },
  ]
end
of(string, **kwargs) click to toggle source
# File lib/unicode/display_width.rb, line 117
def of(string, **kwargs)
  self.class.of(string, *get_config(**kwargs))
end