diff --git a/nvim/lua/darcula/haven/init.lua b/nvim/lua/darcula/haven/init.lua index 0855e10..947f513 100644 --- a/nvim/lua/darcula/haven/init.lua +++ b/nvim/lua/darcula/haven/init.lua @@ -117,25 +117,61 @@ local diff_strings = function(a, b) return vim.text.diff(a, b, {algorithm = "minimal"}) end -local create_save_file_path = function(buf_info) - local encode = function(str) - return str:gsub("\r?\n", "\r\n"):gsub( - "([^%w%-%.%_%~ ])", - function(c) - return string.format("%%%02X", string.byte(c)) - end - ):gsub(" ", "+") +local hash_path = function(path) + return vim.fn.sha256(path) +end + +local get_save_base_path = function(buf_info) + return vim.fs.joinpath(haven_config.haven_path, hash_path(buf_info.name)) +end + +local create_save_data_file_path = function(buf_info) + return get_save_base_path(buf_info) .. ".data" +end + +local create_save_src_file_path = function(buf_info) + return get_save_base_path(buf_info) .. ".src" +end + +local legacy_decode = function(str) + if str == nil then + return "" end - return vim.fs.joinpath( - haven_config.haven_path, - encode(buf_info.name) .. ".save" + return str:gsub("+", " "):gsub( + "%%(%x%x)", + function(x) + return string.char(tonumber(x, 16)) + end ) end +local save_source_file = function(buf_info) + local src_file = create_save_src_file_path(buf_info) + local file, err = io.open(src_file, "w+") + if file == nil then + print_message(true, err) + return false + end + + _, err = file:write(buf_info.name .. line_ending) + if err ~= nil then + print_message(true, err) + file:close() + return false + end + + file:close() + return true +end + local save_change_file = function(buf_info, lines, save_file) active_saves[save_file] = nil + if not save_source_file(buf_info) then + return + end + local file, err = io.open(save_file, "a") if file == nil then print_message(true, err) @@ -203,7 +239,7 @@ local read_change_file = function(save_file) end local process_file_changed = function(buf_info) - local save_file = create_save_file_path(buf_info) + local save_file = create_save_data_file_path(buf_info) local changed_data = changed_lookup[save_file] local immediate = vim.fn.filereadable(save_file) == 0 @@ -270,7 +306,7 @@ local check_requirements = function() if buf_info ~= nil and #buf_info > 0 then buf_info = buf_info[1] if buf_info.name:len() ~= 0 and vim.fn.filereadable(buf_info.name) ~= 0 then - if changed_lookup[create_save_file_path(buf_info)] == nil then + if changed_lookup[create_save_data_file_path(buf_info)] == nil then for _, is_included in pairs(haven_config.inclusions) do if is_included(buf_info.name, haven_config) then return true, buf_info @@ -555,6 +591,95 @@ local show_picker = function(entries) ):find() end +local migrate = function() + local history_files = + scan.scan_dir(haven_config.haven_path, {hidden = true, depth = 1}) + + for _, history_file in ipairs(history_files) do + if history_file:ends_with(".save") then + local old_path_part = + Path:new(history_file):make_relative(haven_config.haven_path):sub(1, -6) + + local original_path = legacy_decode(old_path_part) + if original_path == "" then + print_message(true, "skipping invalid legacy file: " .. history_file) + else + local new_data_file = create_save_data_file_path({name = original_path}) + local new_src_file = create_save_src_file_path({name = original_path}) + + local old_file = io.open(history_file, "r") + if old_file == nil then + print_message(true, "failed to read legacy file: " .. history_file) + else + local contents = old_file:read("*a") or "" + old_file:close() + + local data_ok = false + local src_ok = false + + do + local f, err = io.open(new_data_file, "w+") + if f == nil then + print_message(true, err) + else + local ok, write_err = f:write(contents) + f:close() + if ok == nil then + print_message(true, write_err) + else + data_ok = true + end + end + end + + do + local f, err = io.open(new_src_file, "w+") + if f == nil then + print_message(true, err) + else + local ok, write_err = f:write(original_path .. line_ending) + f:close() + if ok == nil then + print_message(true, write_err) + else + src_ok = true + end + end + end + + if data_ok and src_ok then + local ok, rm_err = os.remove(history_file) + if ok then + print("migrated: " .. history_file) + else + print_message( + true, + "migration failed: " .. history_file .. " " .. tostring(rm_err) + ) + end + else + print_message(true, "migration failed for: " .. history_file) + pcall( + function() + if Path:new(new_data_file):exists() then + Path:new(new_data_file):rm() + end + end + ) + pcall( + function() + if Path:new(new_src_file):exists() then + Path:new(new_src_file):rm() + end + end + ) + end + end + end + end + end +end + M.setup = function(config) if config == nil then config = {} @@ -641,37 +766,46 @@ M.setup = function(config) return end + migrate() setup_autocmds() end M.clean = function() - local decode = function(str) - if str == nil then - return "" - end - - return str:gsub("+", " "):gsub( - "%%(%x%x)", - function(x) - return string.char(tonumber(x, 16)) - end - ) - end - local history_files = scan.scan_dir(haven_config.haven_path, {hidden = true, depth = 1}) + for _, history_file in ipairs(history_files) do - local source_path = - Path:new( - decode(Path:new(history_file):make_relative(haven_config.haven_path)):sub( - 1, - -6 - ) - ) - if not source_path:exists() then - local history_path = Path:new(history_file) - print("removing: " .. history_path:absolute()) - history_path:rm() + if history_file:ends_with(".src") then + local src_path = Path:new(history_file) + local file, err = io.open(history_file, "r") + + if file == nil then + print_message(true, err) + else + local original_path = file:read("*l") or "" + file:close() + + if original_path == "" or not Path:new(original_path):exists() then + local base = history_file:sub(1, -5) + local data_file = base .. ".data" + + if Path:new(data_file):exists() then + print("removing: " .. data_file) + pcall( + function() + Path:new(data_file):rm() + end + ) + end + + print("removing: " .. history_file) + pcall( + function() + src_path:rm() + end + ) + end + end end end end @@ -697,7 +831,7 @@ M.history = function(bufname) local buf_info = vim.fn.getbufinfo(bufname) if buf_info ~= nil and #buf_info > 0 then buf_info = buf_info[1] - local save_file = create_save_file_path(buf_info) + local save_file = create_save_data_file_path(buf_info) if vim.fn.filereadable(save_file) ~= 0 then local entries, err = read_change_file(save_file) if entries == nil then