local M = {} local function str_splice(string, start_idx, end_idx) local new_content = string:sub(1, start_idx - 1) if end_idx then return new_content .. string:sub(end_idx + 1) else return new_content end end local function str_rfind(string, idx, needle) for i = idx, 1, -1 do if string:sub(i, i - 1 + needle:len()) == needle then return i end end end local function get_to_line_end(string, idx) local newline = string:find('\n', idx, true) local to_end = newline and string:sub(idx, newline - 1) or string:sub(idx) return to_end, newline end M.decode_json = function(content) local ok, data = pcall(vim.json.decode, content, { luanil = { object = true } }) while not ok do local char = data:match('invalid token at character (%d+)$') if char then local to_end, newline = get_to_line_end(content, char) if to_end:match('^//') then content = str_splice(content, char, newline) goto continue end end char = data:match('Expected object key string but found [^%s]+ at character (%d+)$') char = char or data:match('Expected value but found T_ARR_END at character (%d+)') if char then local comma_idx = str_rfind(content, char, ',') if comma_idx then content = str_splice(content, comma_idx, comma_idx) goto continue end end error(data) ::continue:: ok, data = pcall(vim.json.decode, content, { luanil = { object = true } }) end return data end return M