-------------------------------------------------------------------------------- -- Enum local enum_metatable = { __tostring = function (e) return 'Enum:' .. e.name or 'Enum: no name' end, __concat = function (a, b) return tostring(a) .. tostring(b) end, } local function enum (t) local e = {} for _, v in ipairs(t) do e[v] = setmetatable({ name = v }, enum_metatable) end return e end -------------------------------------------------------------------------------- -- Unicode local UNICODE_CHAR_PATTERN = '[\01-\127\192-\255][\128-\191]*' local UNICODE_ZERO_WIDTH_CHARACTERS = {} for i = 128, 191 do UNICODE_ZERO_WIDTH_CHARACTERS['\204'..string.char(i)] = true end for i = 128, 175 do UNICODE_ZERO_WIDTH_CHARACTERS['\205'..string.char(i)] = true end local function iterate_utf8_chars (str) -- TODO: Detect invalid codepoints. return str:gmatch(UNICODE_CHAR_PATTERN) end local function utf8_string_length (str) assert(type(str) == 'string') local len = 0 for char in iterate_utf8_chars(str) do if not UNICODE_ZERO_WIDTH_CHARACTERS[char] then len = len + 1 end end return len end -------------------------------------------------------------------------------- -- L utility local function width_of_strings_in_l (l, start_i, stop_i) -- Argument fixing and Error Checking assert(type(l) == 'table') local start_i, stop_i = start_i or 1, stop_i or #l assert(type(start_i) == 'number') assert(type(stop_i) == 'number') -- Do stuff local width = 0 for i = start_i, stop_i do local item_width = 0 if type(l[i]) == 'string' then item_width = utf8_string_length(l[i]) elseif l[i].est_width then item_width = l[i].est_width end width = width + item_width end -- Return return width end -------------------------------------------------------------------------------- return { TABLE_TYPE = enum { 'EMPTY', 'SEQUENCE', 'STRING_MAP', 'PURE_MAP', 'MIXED', 'SET' }, DISPLAY = { HIDE = 1, SMALL = 2, INLINE = 3, EXPAND = 4 }, utf8_string_length = utf8_string_length, width_of_strings_in_l = width_of_strings_in_l, }