-- 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 -- 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 return util