From ac0968042ddb333de5e3c371cc79b3b4ef098356 Mon Sep 17 00:00:00 2001 From: Tom Li Dobnik Date: Fri, 20 Feb 2026 15:05:37 +0100 Subject: update --- .config/yazi/package.toml | 8 +- .config/yazi/plugins/compress.yazi/README.md | 175 +++++- .config/yazi/plugins/compress.yazi/main.lua | 697 ++++++++++++++++-------- .config/yazi/plugins/smart-enter.yazi/README.md | 8 +- .config/yazi/plugins/smart-enter.yazi/main.lua | 3 +- .config/yazi/yazi.toml | 4 + 6 files changed, 647 insertions(+), 248 deletions(-) (limited to '.config/yazi') diff --git a/.config/yazi/package.toml b/.config/yazi/package.toml index 869975b..7098a8d 100644 --- a/.config/yazi/package.toml +++ b/.config/yazi/package.toml @@ -1,12 +1,12 @@ [[plugin.deps]] use = "KKV9/compress" -rev = "60b24af" -hash = "ee025be766240cc98e671754ac836da3" +rev = "c9c16d8" +hash = "a68bde26a61da040131aa95069f638c2" [[plugin.deps]] use = "yazi-rs/plugins:smart-enter" -rev = "600614a" -hash = "c1a2739e9ef2d837030ccb4267be3ed1" +rev = "03cdd4b" +hash = "56fdabc96fc1f4d53c96eb884b02a5be" [flavor] deps = [] diff --git a/.config/yazi/plugins/compress.yazi/README.md b/.config/yazi/plugins/compress.yazi/README.md index 385fe38..ae1f329 100644 --- a/.config/yazi/plugins/compress.yazi/README.md +++ b/.config/yazi/plugins/compress.yazi/README.md @@ -1,48 +1,173 @@ -# ~~archive.yazi~~ compress.yazi +

🗜️ compress.yazi

+

+ A blazing fast, flexible archive plugin for Yazi
+ Effortlessly compress your files and folders with style! +

-A Yazi plugin that compresses selected files to an archive. Supporting yazi versions 0.2.5 and up. +--- -## Supported file types +## 📖 Table of Contents -| 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 | +- [Features](#-features) +- [Supported File Types](#-supported-file-types) +- [Installation](#%EF%B8%8F-installation) +- [Keymap Example](#-keymap-example) +- [Usage](#%EF%B8%8F-usage) +- [Flags](#%EF%B8%8F-flags) +- [Tips](#-tips) +- [Credits](#-credits) +--- -**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. +## 🚀 Features +- 🗂️ **Multi-format support:** zip, 7z, rar, tar, tar.gz, tar.xz, tar.bz2, tar.zst, tar.lz4, tar.lha +- 🌍 **Cross-platform:** Works on Unix & Windows +- 🔒 **Password protection:** Secure your archives (zip/7z/rar) +- 🛡️ **Header encryption:** Hide file lists (7z/rar) +- ⚡ **Compression level:** Choose your balance of speed vs. size +- 🛑 **Overwrite safety:** Never lose files by accident +- 🎯 **Seamless Yazi integration:** Fast, native-like UX -## Install +--- + +## 📦 Supported File Types + +| Extension | Default Command | 7z Command | Bsdtar Command (Win10+ & Unix) | +| ------------- | ----------------- | -------------- | ------------------------------ | +| `.zip` | `zip -r` | `7z a -tzip` | `tar -caf` | +| `.7z` | `7z a` | `7z a` | | +| `.rar` | `rar a` | | | +| `.tar` | `tar rpf` | | `tar rpf` | +| `.tar.gz` | `tar rpf + gzip` | `7z a -tgzip` | `tar -czf` | +| `.tar.xz` | `tar rpf + xz` | `7z a -txz` | `tar -cJf` | +| `.tar.bz2` | `tar rpf + bzip2` | `7z a -tbzip2` | `tar -cjf` | +| `.tar.zst` | `tar rpf + zstd` | | `tar --zstd -cf` | +| `.tar.lz4` | `tar rpf + lz4` | | | +| `.tar.lha` | `tar rpf + lha` | | | + +--- + +## ⚡️ Installation ```bash -# For Unix platforms +# Unix git clone https://github.com/KKV9/compress.yazi.git ~/.config/yazi/plugins/compress.yazi -## For Windows +# Windows (CMD, not PowerShell!) 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 +ya pkg add KKV9/compress ``` -- Add this to your `keymap.toml`: +--- + +### 🔧 Extras (Windows) + +To enable additional compression formats and features on Windows, follow these steps: + +1. **Install [7-Zip](https://www.7-zip.org/):** + Add `C:\Program Files\7-Zip` to your `PATH`. + This enables support for `.7z` archives and password-protected `.zip` files. + +2. **Alternative: Install [Nanazip](https://github.com/M2Team/NanaZip):** + A modern alternative to 7-Zip with similar functionality and extra features. + +3. **Install [WinRAR](https://www.win-rar.com/download.html):** + Add `C:\Program Files\WinRAR` to your `PATH`. + This enables support for `.rar` archives. + +4. **Install Additional Tools:** + To use formats like `lha`, `lz4`, `gzip`, etc., install their respective tools and ensure they are added to your `PATH`. + +--- + +## 🎹 Keymap Example + +Add this to your `keymap.toml`: + ```toml -[[manager.prepend_keymap]] -on = [ "c", "a" ] +[[mgr.prepend_keymap]] +on = [ "c", "a", "a" ] run = "plugin compress" desc = "Archive selected files" + +[[mgr.prepend_keymap]] +on = [ "c", "a", "p" ] +run = "plugin compress -p" +desc = "Archive selected files (password)" + +[[mgr.prepend_keymap]] +on = [ "c", "a", "h" ] +run = "plugin compress -ph" +desc = "Archive selected files (password+header)" + +[[mgr.prepend_keymap]] +on = [ "c", "a", "l" ] +run = "plugin compress -l" +desc = "Archive selected files (compression level)" + +[[mgr.prepend_keymap]] +on = [ "c", "a", "u" ] +run = "plugin compress -phl" +desc = "Archive selected files (password+header+level)" +``` + +--- + +## 🛠️ Usage + +1. **Select files/folders** in Yazi. +2. Press c a to open the archive dialog. +3. Choose: + - a for a standard archive + - p for password protection (zip/7z/rar) + - h to encrypt header (7z/rar) + - l to set compression level (all compression algorithims) + - u for all options together +4. **Type a name** for your archive (or leave blank for suggested name). +5. **Enter password** and/or **compression level** if prompted. +6. **Overwrite protect** if a file already exists, the new file will be given a suffix _#. +7. Enjoy your shiny new archive! + +--- + +## 🏳️‍🌈 Flags + +- Combine flags for more power! +- when separating flags with spaces, make sure to single quote them (eg., `'-ph rar'`) +- `-p` Password protect (zip/7z/rar) +- `-h` Encrypt header (7z/rar) +- `-l` Set compression level (all compression algorithims) +- `` Specify a default extention (eg., `7z`, `tar.gz`) + +#### Combining multiple flags: +```toml +[[mgr.prepend_keymap]] +on = [ "c", "a", "7" ] +run = "plugin compress '-ph 7z'" +desc = "Archive selected files to 7z (password+header)" +[[mgr.prepend_keymap]] +on = [ "c", "a", "r" ] +run = "plugin compress '-p -l rar'" +desc = "Archive selected files to rar (password+level)" ``` -## Usage +--- + +## 💡 Tips + +- The file extension **must** match a supported type. +- The required compression tool **must** be installed and in your `PATH` (7zip/rar etc.). +- If no extention is provided, the default extention (zip) will be appended automatically. + +--- + +## 📣 Credits + +Made with ❤️ for [Yazi](https://github.com/sxyazi/yazi) by [KKV9](https://github.com/KKV9). +Contributions are welcome! Feel free to submit a pull request. - - 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 index 333587f..2197bb2 100644 --- a/.config/yazi/plugins/compress.yazi/main.lua +++ b/.config/yazi/plugins/compress.yazi/main.lua @@ -1,228 +1,497 @@ --- 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" +-- Define flags and strings +local is_password, is_encrypted, is_level, cmd_password, cmd_level, default_extension = false, false, false, "", "", "zip" --- 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 +-- Function to check valid filename +local function is_valid_filename(name) + -- Trim whitespace from both ends + name = name:match("^%s*(.-)%s*$") + if name == "" then + return false + end + if is_windows then + -- Windows forbidden chars and reserved names + if name:find('[<>:"/\\|%?%*]') then + return false + end + else + -- Unix forbidden chars + if name:find("/") or name:find("%z") then + return false + end + end + return true 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 +-- Function to send notifications +local function notify_error(message, urgency) + ya.notify( + { + title = "Archive", + content = message, + level = urgency, + timeout = 5 + } + ) 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 +-- Function to check if 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 + +-- Function to change command arrays --> string -- Use first command available or first command +local function find_command_name(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 --- Append filename to it's parent directory +-- Function to append filename to it's parent directory url local function combine_url(path, file) - path, file = Url(path), Url(file) - return tostring(path:join(file)) + path, file = Url(path), Url(file) + return tostring(path:join(file)) end +-- Function to make a table of selected or hovered files: 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, names, tostring(tab.current.cwd) + end +) + +-- Table of archive commands +local archive_commands = { + ["%.zip$"] = { + {command = "zip", args = {"-r"}, level_arg = "-", level_min = 0, level_max = 9, passwordable = true}, + { + command = {"7z", "7zz", "7za"}, + args = {"a", "-tzip"}, + level_arg = "-mx=", + level_min = 0, + level_max = 9, + passwordable = true + }, + { + command = {"tar", "bsdtar"}, + args = {"-caf"}, + level_arg = {"--option", "compression-level="}, + level_min = 1, + level_max = 9 + } + }, + ["%.7z$"] = { + { + command = {"7z", "7zz", "7za"}, + args = {"a"}, + level_arg = "-mx=", + level_min = 0, + level_max = 9, + header_arg = "-mhe=on", + passwordable = true + } + }, + ["%.rar$"] = { + { + command = "rar", + args = {"a"}, + level_arg = "-m", + level_min = 0, + level_max = 5, + header_arg = "-hp", + passwordable = true + } + }, + ["%.tar.gz$"] = { + {command = {"tar", "bsdtar"}, args = {"rpf"}, level_arg = "-", level_min = 1, level_max = 9, compress = "gzip"}, + { + command = {"tar", "bsdtar"}, + args = {"rpf"}, + level_arg = "-mx=", + level_min = 1, + level_max = 9, + compress = "7z", + compress_args = {"a", "-tgzip"} + }, + { + command = {"tar", "bsdtar"}, + args = {"-czf"}, + level_arg = {"--option", "gzip:compression-level="}, + level_min = 1, + level_max = 9 + } + }, + ["%.tar.xz$"] = { + {command = {"tar", "bsdtar"}, args = {"rpf"}, level_arg = "-", level_min = 1, level_max = 9, compress = "xz"}, + { + command = {"tar", "bsdtar"}, + args = {"rpf"}, + level_arg = "-mx=", + level_min = 1, + level_max = 9, + compress = "7z", + compress_args = {"a", "-txz"} + }, + { + command = {"tar", "bsdtar"}, + args = {"-cJf"}, + level_arg = {"--option", "xz:compression-level="}, + level_min = 1, + level_max = 9 + } + }, + ["%.tar.bz2$"] = { + {command = {"tar", "bsdtar"}, args = {"rpf"}, level_arg = "-", level_min = 1, level_max = 9, compress = "bzip2"}, + { + command = {"tar", "bsdtar"}, + args = {"rpf"}, + level_arg = "-mx=", + level_min = 1, + level_max = 9, + compress = "7z", + compress_args = {"a", "-tbzip2"} + }, + { + command = {"tar", "bsdtar"}, + args = {"-cjf"}, + level_arg = {"--option", "bzip2:compression-level="}, + level_min = 1, + level_max = 9 + } + }, + ["%.tar.zst$"] = { + { + command = {"tar", "bsdtar"}, + args = {"rpf"}, + level_arg = "-", + level_min = 1, + level_max = 22, + compress = "zstd", + compress_args = {"--ultra"} + } + }, + ["%.tar.lz4$"] = { + { + command = {"tar", "bsdtar"}, + args = {"rpf"}, + level_arg = "-", + level_min = 1, + level_max = 12, + compress = "lz4" + } + }, + ["%.tar.lha$"] = { + { + command = {"tar", "bsdtar"}, + args = {"rpf"}, + level_arg = "-o", + level_min = 5, + level_max = 7, + compress = "lha", + compress_args = {"-a"} + } + }, + ["%.tar$"] = { + {command = {"tar", "bsdtar"}, args = {"rpf"}} + } +} + 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, + entry = function(_, job) + -- Parse flags and default extension + if job.args ~= nil then + for _, arg in ipairs(job.args) do + if arg:match("^%-(%w+)$") then + -- Handle combined flags (e.g., -phl) + for flag in arg:sub(2):gmatch(".") do + if flag == "p" then + is_password = true + elseif flag == "h" then + is_encrypted = true + elseif flag == "l" then + is_level = true + end + end + elseif arg:match("^[%w%.]+$") then + -- Handle default extension (e.g., 7z, zip) + if archive_commands["%." .. arg .. "$"] then + default_extension = arg + else + notify_error(string.format("Unsupported extension: %s", arg), "warn") + end + else + notify_error(string.format("Unknown argument: %s", arg), "warn") + end + end + end + + -- Exit visual mode + ya.emit("escape", {visual = true}) + -- Define file table and output_dir (pwd) + local path_fnames, fnames, output_dir = selected_or_hovered() + -- Get archive filename + local output_name, event = + ya.input( + { + title = "Create archive:", + pos = {"top-center", y = 3, w = 40} + } + ) + if event ~= 1 then + return + end + + -- Determine the default name for the archive + local default_name = #fnames == 1 and fnames[1] or Url(output_dir).name + output_name = output_name == "" and string.format("%s.%s", default_name, default_extension) or output_name + + -- Add default extension if none is specified + if not output_name:match("%.%w+$") then + output_name = string.format("%s.%s", output_name, default_extension) + end + + -- Validate the final archive filename + if not is_valid_filename(output_name) then + notify_error("Invalid archive filename", "error") + return + end + + -- Match user input to archive command + local archive_cmd, + archive_args, + archive_compress, + archive_level_arg, + archive_level_min, + archive_level_max, + archive_header_arg, + archive_passwordable, + archive_compress_args + local matched_pattern = false + for pattern, cmd_list in pairs(archive_commands) do + if output_name:match(pattern) then + matched_pattern = true -- Mark that file extension is correct + for _, cmd in ipairs(cmd_list) do + -- Check if archive_cmd is available + local find_command = type(cmd.command) == "table" and find_command_name(cmd.command) or cmd.command + if is_command_available(find_command) then + -- Check if compress_cmd (if listed) is available + if cmd.compress == nil or is_command_available(cmd.compress) then + archive_cmd = find_command + archive_args = cmd.args + archive_compress = cmd.compress or "" + archive_level_arg = is_level and cmd.level_arg or "" + archive_level_min = cmd.level_min + archive_level_max = cmd.level_max + archive_header_arg = is_encrypted and cmd.header_arg or "" + archive_passwordable = cmd.passwordable or false + archive_compress_args = cmd.compress_args or {} + break + end + end + end + if archive_cmd then + break + end + end + end + + -- Check if no archive command is available for the extension + if not matched_pattern then + notify_error("Unsupported file extension", "error") + return + end + + -- Check if no suitable archive program was found + if not archive_cmd then + notify_error("Could not find a suitable archive program for the selected file extension", "error") + return + end + + -- Check if archive command has multiple names + if type(archive_cmd) == "table" then + archive_cmd = find_command_name(archive_cmd) + 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 + + -- Add password arg if selected + if archive_passwordable and is_password then + local output_password, event = + ya.input( + { + title = "Enter password:", + obscure = true, + pos = {"top-center", y = 3, w = 40} + } + ) + if event ~= 1 then + return + end + if output_password ~= "" then + cmd_password = "-P" .. output_password + if archive_cmd == "rar" and is_encrypted then + cmd_password = archive_header_arg .. output_password -- Add archive arg for rar + end + table.insert(archive_args, cmd_password) + end + end + + -- Add header arg if selected for 7z + if is_encrypted and archive_header_arg ~= "" and archive_cmd ~= "rar" then + table.insert(archive_args, archive_header_arg) + end + + -- Add level arg if selected + if archive_level_arg ~= "" and is_level then + local output_level, event = + ya.input( + { + title = string.format("Enter compression level (%s - %s)", archive_level_min, archive_level_max), + pos = {"top-center", y = 3, w = 40} + } + ) + if event ~= 1 then + return + end + -- Validate user input for compression level + if + output_level ~= "" and tonumber(output_level) ~= nil and tonumber(output_level) >= archive_level_min and + tonumber(output_level) <= archive_level_max + then + cmd_level = + type(archive_level_arg) == "table" and archive_level_arg[#archive_level_arg] .. output_level or + archive_level_arg .. output_level + local target_args = archive_compress == "" and archive_args or archive_compress_args + if type(archive_level_arg) == "table" then + -- Insert each element of archive_level_arg (except last) into target_args at the correct position + for i = 1, #archive_level_arg - 1 do + table.insert(target_args, i, archive_level_arg[i]) + end + table.insert(target_args, #archive_level_arg, cmd_level) -- Add level at the end + else + -- Insert the compression level argument at the start if not a table + table.insert(target_args, 1, cmd_level) + end + else + notify_error("Invalid level specified. Using defaults.", "warn") + end + end + + -- Store the original output name for later use + local original_name = output_name + + -- If compression is needed, adjust the output name to exclude extensions like ".tar" + if archive_compress ~= "" then + output_name = output_name:match("(.*%.tar)") or output_name + end + + -- Create a temporary directory for intermediate files + local temp_dir_name = ".tmp_compress" + local temp_dir = combine_url(output_dir, temp_dir_name) + local temp_dir, _ = tostring(fs.unique_name(Url(temp_dir))) + + -- Attempt to create the temporary directory + local temp_dir_status, temp_dir_err = fs.create("dir_all", Url(temp_dir)) + if not temp_dir_status then + -- Notify the user if the temporary directory creation fails + notify_error(string.format("Failed to create temp directory, error code: %s", temp_dir_err), "error") + return + end + + -- Define the temporary output file path within the temporary directory + local temp_output_url = combine_url(temp_dir, output_name) + + -- Add files to the output archive + for filepath, filenames in pairs(path_fnames) do + -- Execute the archive command for each path and its respective files + local archive_status, archive_err = + Command(archive_cmd):arg(archive_args):arg(temp_output_url):arg(filenames):cwd(filepath):spawn():wait() + if not archive_status or not archive_status.success then + -- Notify the user if the archiving process fails and clean up the temporary directory + notify_error(string.format("Failed to create archive %s with '%s', error: %s", output_name, archive_cmd, archive_err), "error") + local cleanup_status, cleanup_err = fs.remove("dir_all", Url(temp_dir)) + if not cleanup_status then + notify_error(string.format("Failed to clean up temporary directory %s, error: %s", temp_dir, cleanup_err), "error") + end + return + end + end + + -- If compression is required, execute the compression command + if archive_compress ~= "" then + local compress_status, compress_err = + Command(archive_compress):arg(archive_compress_args):arg(temp_output_url):spawn():wait() + if not compress_status or not compress_status.success then + -- Notify the user if the compression process fails and clean up the temporary directory + notify_error(string.format("Failed to compress archive %s with '%s', error: %s", output_name, archive_compress, compress_err), "error") + local cleanup_status, cleanup_err = fs.remove("dir_all", Url(temp_dir)) + if not cleanup_status then + notify_error(string.format("Failed to clean up temporary directory %s, error: %s", temp_dir, cleanup_err), "error") + end + return + end + end + + -- Move the final file from the temporary directory to the output directory + local final_output_url, temp_url_processed = combine_url(output_dir, original_name), combine_url(temp_dir, original_name) + final_output_url, _ = tostring(fs.unique_name(Url(final_output_url))) + local move_status, move_err = os.rename(temp_url_processed, final_output_url) + if not move_status then + -- Notify the user if the move operation fails and clean up the temporary directory + notify_error(string.format("Failed to move %s to %s, error: %s", temp_url_processed, final_output_url, move_err), "error") + local cleanup_status, cleanup_err = fs.remove("dir_all", Url(temp_dir)) + if not cleanup_status then + notify_error(string.format("Failed to clean up temporary directory %s, error: %s", temp_dir, cleanup_err), "error") + end + return + end + + -- Cleanup the temporary directory after successful operation + local cleanup_status, cleanup_err = fs.remove("dir_all", Url(temp_dir)) + if not cleanup_status then + notify_error(string.format("Failed to clean up temporary directory %s, error: %s", temp_dir, cleanup_err), "error") + end + end } + diff --git a/.config/yazi/plugins/smart-enter.yazi/README.md b/.config/yazi/plugins/smart-enter.yazi/README.md index d4c6bbd..742f2e1 100644 --- a/.config/yazi/plugins/smart-enter.yazi/README.md +++ b/.config/yazi/plugins/smart-enter.yazi/README.md @@ -5,7 +5,7 @@ ## Installation ```sh -ya pack -a yazi-rs/plugins:smart-enter +ya pkg add yazi-rs/plugins:smart-enter ``` ## Usage @@ -13,7 +13,7 @@ ya pack -a yazi-rs/plugins:smart-enter Bind your l key to the plugin, in your `~/.config/yazi/keymap.toml`: ```toml -[[manager.prepend_keymap]] +[[mgr.prepend_keymap]] on = "l" run = "plugin smart-enter" desc = "Enter the child directory, or open the file" @@ -36,5 +36,5 @@ require("smart-enter"):setup { This plugin is MIT-licensed. For more information check the [LICENSE](LICENSE) file. -[open]: https://yazi-rs.github.io/docs/configuration/keymap/#manager.open -[enter]: https://yazi-rs.github.io/docs/configuration/keymap/#manager.enter +[open]: https://yazi-rs.github.io/docs/configuration/keymap/#mgr.open +[enter]: https://yazi-rs.github.io/docs/configuration/keymap/#mgr.enter diff --git a/.config/yazi/plugins/smart-enter.yazi/main.lua b/.config/yazi/plugins/smart-enter.yazi/main.lua index 37a465a..e9e2ec6 100644 --- a/.config/yazi/plugins/smart-enter.yazi/main.lua +++ b/.config/yazi/plugins/smart-enter.yazi/main.lua @@ -1,10 +1,11 @@ +--- @since 25.5.31 --- @sync entry local function setup(self, opts) self.open_multi = opts.open_multi end local function entry(self) local h = cx.active.current.hovered - ya.manager_emit(h and h.cha.is_dir and "enter" or "open", { hovered = not self.open_multi }) + ya.emit(h and h.cha.is_dir and "enter" or "open", { hovered = not self.open_multi }) end return { entry = entry, setup = setup } diff --git a/.config/yazi/yazi.toml b/.config/yazi/yazi.toml index 465b12c..1931861 100644 --- a/.config/yazi/yazi.toml +++ b/.config/yazi/yazi.toml @@ -1,2 +1,6 @@ [opener] edit = [{ run = 'nvim "$@"', block = true }] + +[mgr] +ratio = [2, 5, 5] +scrolloff = 4 -- cgit v1.2.3