-- Copyright 2025 David Vazgenovich Shakaryan local mp_utils = require('mp.utils') local util = {} function util.copy_table(t) local u = {} for k, v in pairs(t) do u[k] = v end return u end function util.reverse(t) for i = 1, #t/2 do t[i], t[#t-i+1] = t[#t-i+1], t[i] end end function util.strip(str) return (str:gsub('^%s*(.-)%s*$', '%1')) end function util.strip_ne(str) if str == nil then return nil end local str = util.strip(tostring(str)) return str ~= '' and str or nil end -- skips over utf8 continuation bytes (10xxxxxx) -- valid positions range from 1 to #str + 1 (*after* the last byte) function util.utf8_seek(str, pos, n) local step = n > 0 and 1 or -1 local test = n > 0 and function() return pos > #str end or function() return pos <= 1 end while n ~= 0 and not test() do repeat pos = pos + step until test() or bit.band(str:byte(pos), 0xc0) ~= 0x80 n = n - step end return pos end -- wraps string into a table of strings. spaces are not removed, resulting in -- width-1 visible chars; newlines and end of string are handled similarly for -- consistency. words longer than width are not broken. optional cont_width can -- be specified to use a different width for continuation lines. function util.wrap(str, width, cont_width) local t = {} local start, stop = 0, 0 while stop < #str do local i = str:find('[ \n]', stop + 1) or #str + 1 if i - start >= width then t[#t+1] = str:sub(start, stop) start = stop + 1 if cont_width then width = cont_width end end stop = i if str:byte(stop) == 10 or stop >= #str then t[#t+1] = str:sub(start, stop - 1) .. ' ' start = stop + 1 end end return t end function util.read_json_file(path) local f = io.open(path, 'r') if not f then return {} end local json = f:read('*all') f:close() return mp_utils.parse_json(json) end function util.write_json_file(path, data) local f = io.open(path, 'w') f:write(mp_utils.format_json(data), '\n') f:close() end -- merges tables `t' and `u', using key `k' for identity. the order from `u' is -- always respected, preserving the relative order from `t' when possible. function util.stable_kmerge(t, u, k) local pos = {} for i, v in ipairs(u) do pos[v[k]] = i end local res = {} local seen = {} local function append(v) if not seen[v[k]] then res[#res+1] = v seen[v[k]] = true end end local ind = 1 for _, v in ipairs(t) do if pos[v[k]] then while ind <= pos[v[k]] do append(u[ind]) ind = ind + 1 end end append(v) end for i = ind, #u do append(u[i]) end return res end return util