From ea82cbb1c0b778dd946c717cceace53fab391ba8 Mon Sep 17 00:00:00 2001 From: Tom Li Dobnik Date: Sat, 9 Aug 2025 17:12:43 +0200 Subject: init --- .config/yazi/plugins/compress.yazi/main.lua | 228 ++++++++++++++++++++++++++++ 1 file changed, 228 insertions(+) create mode 100644 .config/yazi/plugins/compress.yazi/main.lua (limited to '.config/yazi/plugins/compress.yazi/main.lua') diff --git a/.config/yazi/plugins/compress.yazi/main.lua b/.config/yazi/plugins/compress.yazi/main.lua new file mode 100644 index 0000000..333587f --- /dev/null +++ b/.config/yazi/plugins/compress.yazi/main.lua @@ -0,0 +1,228 @@ +-- Send error notification +local function notify_error(message, urgency) + ya.notify({ + title = "Archive", + content = message, + level = urgency, + timeout = 5, + }) +end + +-- Check for windows +local is_windows = ya.target_family() == "windows" + +-- Make table of selected or hovered: path = filenames +local selected_or_hovered = ya.sync(function() + local tab, paths, names, path_fnames = cx.active, {}, {}, {} + for _, u in pairs(tab.selected) do + paths[#paths + 1] = tostring(u:parent()) + names[#names + 1] = tostring(u:name()) + end + if #paths == 0 and tab.current.hovered then + paths[1] = tostring(tab.current.hovered.url:parent()) + names[1] = tostring(tab.current.hovered.name) + end + for idx, name in ipairs(names) do + if not path_fnames[paths[idx]] then + path_fnames[paths[idx]] = {} + end + table.insert(path_fnames[paths[idx]], name) + end + return path_fnames, tostring(tab.current.cwd) +end) + +-- Check if archive command is available +local function is_command_available(cmd) + local stat_cmd + + if is_windows then + stat_cmd = string.format("where %s > nul 2>&1", cmd) + else + stat_cmd = string.format("command -v %s >/dev/null 2>&1", cmd) + end + + local cmd_exists = os.execute(stat_cmd) + if cmd_exists then + return true + else + return false + end +end + +-- Archive command list --> string +local function find_binary(cmd_list) + for _, cmd in ipairs(cmd_list) do + if is_command_available(cmd) then + return cmd + end + end + return cmd_list[1] -- Return first command as fallback +end + +-- Check if file exists +local function file_exists(name) + local f = io.open(name, "r") + if f ~= nil then + io.close(f) + return true + else + return false + end +end + +-- Append filename to it's parent directory +local function combine_url(path, file) + path, file = Url(path), Url(file) + return tostring(path:join(file)) +end + +return { + entry = function() + -- Exit visual mode + ya.manager_emit("escape", { visual = true }) + + -- Define file table and output_dir (pwd) + local path_fnames, output_dir = selected_or_hovered() + + -- Get input + local output_name, event = ya.input({ + title = "Create archive:", + position = { "top-center", y = 3, w = 40 }, + }) + if event ~= 1 then + return + end + + -- Use appropriate archive command + local archive_commands = { + ["%.zip$"] = { command = "zip", args = { "-r" } }, + ["%.7z$"] = { command = { "7z", "7zz" }, args = { "a" } }, + ["%.tar.gz$"] = { command = "tar", args = { "rpf" }, compress = "gzip" }, + ["%.tar.xz$"] = { command = "tar", args = { "rpf" }, compress = "xz" }, + ["%.tar.bz2$"] = { command = "tar", args = { "rpf" }, compress = "bzip2" }, + ["%.tar.zst$"] = { command = "tar", args = { "rpf" }, compress = "zstd", compress_args = { "--rm" } }, + ["%.tar$"] = { command = "tar", args = { "rpf" } }, + } + + if is_windows then + archive_commands = { + ["%.zip$"] = { command = "7z", args = { "a", "-tzip" } }, + ["%.7z$"] = { command = "7z", args = { "a" } }, + ["%.tar.gz$"] = { + command = "tar", + args = { "rpf" }, + compress = "7z", + compress_args = { "a", "-tgzip", "-sdel", output_name }, + }, + ["%.tar.xz$"] = { + command = "tar", + args = { "rpf" }, + compress = "7z", + compress_args = { "a", "-txz", "-sdel", output_name }, + }, + ["%.tar.bz2$"] = { + command = "tar", + args = { "rpf" }, + compress = "7z", + compress_args = { "a", "-tbzip2", "-sdel", output_name }, + }, + ["%.tar.zst$"] = { command = "tar", args = { "rpf" }, compress = "zstd", compress_args = { "--rm" } }, + ["%.tar$"] = { command = "tar", args = { "rpf" } }, + } + end + + -- Match user input to archive command + local archive_cmd, archive_args, archive_compress, archive_compress_args + for pattern, cmd_pair in pairs(archive_commands) do + if output_name:match(pattern) then + archive_cmd = cmd_pair.command + archive_args = cmd_pair.args + archive_compress = cmd_pair.compress + archive_compress_args = cmd_pair.compress_args or {} + end + end + + -- Check if archive command has multiple names + if type(archive_cmd) == "table" then + archive_cmd = find_binary(archive_cmd) + end + + -- Check if no archive command is available for the extention + if not archive_cmd then + notify_error("Unsupported file extention", "error") + return + end + + -- Exit if archive command is not available + if not is_command_available(archive_cmd) then + notify_error(string.format("%s not available", archive_cmd), "error") + return + end + + -- Exit if compress command is not available + if archive_compress and not is_command_available(archive_compress) then + notify_error(string.format("%s compression not available", archive_compress), "error") + return + end + + -- If file exists show overwrite prompt + local output_url = combine_url(output_dir, output_name) + while true do + if file_exists(output_url) then + local overwrite_answer = ya.input({ + title = "Overwrite " .. output_name .. "? y/N:", + position = { "top-center", y = 3, w = 40 }, + }) + if overwrite_answer:lower() ~= "y" then + notify_error("Operation canceled", "warn") + return -- If no overwrite selected, exit + else + local rm_status, rm_err = os.remove(output_url) + if not rm_status then + notify_error(string.format("Failed to remove %s, exit code %s", output_name, rm_err), "error") + return + end -- If overwrite fails, exit + end + end + if archive_compress and not output_name:match("%.tar$") then + output_name = output_name:match("(.*%.tar)") -- Test for .tar and .tar.* + output_url = combine_url(output_dir, output_name) -- Update output_url + else + break + end + end + + -- Add to output archive in each path, their respective files + for path, names in pairs(path_fnames) do + local archive_status, archive_err = + Command(archive_cmd):args(archive_args):arg(output_url):args(names):cwd(path):spawn():wait() + if not archive_status or not archive_status.success then + notify_error( + string.format( + "%s with selected files failed, exit code %s", + archive_args, + archive_status and archive_status.code or archive_err + ), + "error" + ) + end + end + + -- Use compress command if needed + if archive_compress then + local compress_status, compress_err = + Command(archive_compress):args(archive_compress_args):arg(output_name):cwd(output_dir):spawn():wait() + if not compress_status or not compress_status.success then + notify_error( + string.format( + "%s with %s failed, exit code %s", + archive_compress, + output_name, + compress_status and compress_status.code or compress_err + ), + "error" + ) + end + end + end, +} -- cgit v1.2.3