summaryrefslogtreecommitdiff
path: root/.config/yazi/plugins/compress.yazi
diff options
context:
space:
mode:
Diffstat (limited to '.config/yazi/plugins/compress.yazi')
-rw-r--r--.config/yazi/plugins/compress.yazi/LICENSE21
-rw-r--r--.config/yazi/plugins/compress.yazi/README.md48
-rw-r--r--.config/yazi/plugins/compress.yazi/main.lua228
3 files changed, 297 insertions, 0 deletions
diff --git a/.config/yazi/plugins/compress.yazi/LICENSE b/.config/yazi/plugins/compress.yazi/LICENSE
new file mode 100644
index 0000000..7ce7a2f
--- /dev/null
+++ b/.config/yazi/plugins/compress.yazi/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2024 CiarĂ¡n O'Brien
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/.config/yazi/plugins/compress.yazi/README.md b/.config/yazi/plugins/compress.yazi/README.md
new file mode 100644
index 0000000..385fe38
--- /dev/null
+++ b/.config/yazi/plugins/compress.yazi/README.md
@@ -0,0 +1,48 @@
+# ~~archive.yazi~~ compress.yazi
+
+A Yazi plugin that compresses selected files to an archive. Supporting yazi versions 0.2.5 and up.
+
+## Supported file types
+
+| Extention | Unix Command | Windows Command |
+| ------------- | ------------- | --------------- |
+| .zip | zip -r | 7z a -tzip |
+| .7z | 7z a | 7z a |
+| .tar | tar rpf | tar rpf |
+| .tar.gz | gzip | 7z a -tgzip |
+| .tar.xz | xz | 7z a -txz |
+| .tar.bz2 | bzip2 | 7z a -tbzip2 |
+| .tar.zst | zstd | zstd |
+
+
+**NOTE:** Windows users are required to install 7-Zip and add 7z.exe to the `path` environment variable, only tar archives will be available otherwise.
+
+
+## Install
+
+```bash
+# For Unix platforms
+git clone https://github.com/KKV9/compress.yazi.git ~/.config/yazi/plugins/compress.yazi
+
+## For Windows
+git clone https://github.com/KKV9/compress.yazi.git %AppData%\yazi\config\plugins\compress.yazi
+
+# Or with yazi plugin manager
+ya pack -a KKV9/compress
+```
+
+- Add this to your `keymap.toml`:
+
+```toml
+[[manager.prepend_keymap]]
+on = [ "c", "a" ]
+run = "plugin compress"
+desc = "Archive selected files"
+```
+
+## Usage
+
+ - Select files or folders to add, then press `c` `a` to create a new archive.
+ - Type a name for the new file.
+ - The file extention must match one of the supported filetype extentions.
+ - The desired archive/compression command must be installed on your system.
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,
+}