From 6c4468bd3bbcbc27cb3fd5dc03a6faabf1a8a6a3 Mon Sep 17 00:00:00 2001 From: "alex.tenkoff" Date: Mon, 24 Nov 2025 20:25:09 +0700 Subject: [PATCH] Remove ouch.yazi plugin --- config/yazi/plugins/ouch.yazi | 1 - config/yazi/plugins/ouch.yazi/LICENSE | 21 ++++ config/yazi/plugins/ouch.yazi/README.md | 79 +++++++++++++ config/yazi/plugins/ouch.yazi/main.lua | 148 ++++++++++++++++++++++++ 4 files changed, 248 insertions(+), 1 deletion(-) delete mode 160000 config/yazi/plugins/ouch.yazi create mode 100644 config/yazi/plugins/ouch.yazi/LICENSE create mode 100644 config/yazi/plugins/ouch.yazi/README.md create mode 100644 config/yazi/plugins/ouch.yazi/main.lua diff --git a/config/yazi/plugins/ouch.yazi b/config/yazi/plugins/ouch.yazi deleted file mode 160000 index 2496cd9..0000000 --- a/config/yazi/plugins/ouch.yazi +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 2496cd9ac2d1fb52597b22ae84f3af06c826a86d diff --git a/config/yazi/plugins/ouch.yazi/LICENSE b/config/yazi/plugins/ouch.yazi/LICENSE new file mode 100644 index 0000000..3f9d766 --- /dev/null +++ b/config/yazi/plugins/ouch.yazi/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 ndtoan96 + +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/ouch.yazi/README.md b/config/yazi/plugins/ouch.yazi/README.md new file mode 100644 index 0000000..e09b3df --- /dev/null +++ b/config/yazi/plugins/ouch.yazi/README.md @@ -0,0 +1,79 @@ +# ouch.yazi + +[ouch](https://github.com/ouch-org/ouch) plugin for [Yazi](https://github.com/sxyazi/yazi). + +![ouch.yazi](https://github.com/ndtoan96/ouch.yazi/assets/33489972/946397ec-b37b-4bf4-93f1-c676fc8e59f2) + +## Features +- Archive preview +- Compression + +## Installation + +### Yazi package manager +```bash +ya pack -a ndtoan96/ouch +``` + +### Git +```bash +# Linux/macOS +git clone https://github.com/ndtoan96/ouch.yazi.git ~/.config/yazi/plugins/ouch.yazi + +# Windows with cmd +git clone https://github.com/ndtoan96/ouch.yazi.git %AppData%\yazi\config\plugins\ouch.yazi + +# Windows with powershell +git clone https://github.com/ndtoan96/ouch.yazi.git "$($env:APPDATA)\yazi\config\plugins\ouch.yazi" +``` + +Make sure you have [ouch](https://github.com/ouch-org/ouch) installed and in your `PATH`. + +## Usage + +### Preview +For archive preview, add this to your `yazi.toml`: + +```toml +[plugin] +prepend_previewers = [ + # Archive previewer + { mime = "application/*zip", run = "ouch" }, + { mime = "application/x-tar", run = "ouch" }, + { mime = "application/x-bzip2", run = "ouch" }, + { mime = "application/x-7z-compressed", run = "ouch" }, + { mime = "application/x-rar", run = "ouch" }, + { mime = "application/x-xz", run = "ouch" }, + { mime = "application/xz", run = "ouch" }, +] +``` + +Now go to an archive on Yazi, you should see the archive's content in the preview pane. You can use `J` and `K` to roll up and down the preview. + +If you want to change the icon or the style of text, you can modify the `peek` function in `init.lua` file (all of them are stored in the `lines` variable). + +### Compression +For compession, add this to your `keymap.toml`: + +```toml +[[manager.prepend_keymap]] +on = ["C"] +run = "plugin ouch" +desc = "Compress with ouch" +``` + +The plugin uses `zip` format by default. You can change the format when you name the output file, `ouch` will detect format based on file extension. + +And, for example, if you would like to set `7z` as default format, you can use `plugin ouch 7z`. + +### Decompression +This plugin does not provide a decompression feature because it already is supported by Yazi. +To decompress with `ouch`, configure the opener in `yazi.toml`. + +```toml +[opener] +extract = [ + { run = 'ouch d -y "%*"', desc = "Extract here with ouch", for = "windows" }, + { run = 'ouch d -y "$@"', desc = "Extract here with ouch", for = "unix" }, +] +``` diff --git a/config/yazi/plugins/ouch.yazi/main.lua b/config/yazi/plugins/ouch.yazi/main.lua new file mode 100644 index 0000000..f642eb3 --- /dev/null +++ b/config/yazi/plugins/ouch.yazi/main.lua @@ -0,0 +1,148 @@ +local M = {} + +function M:peek(job) + local child = Command("ouch") + :args({ "l", "-t", "-y", tostring(job.file.url) }) + :stdout(Command.PIPED) + :stderr(Command.PIPED) + :spawn() + local limit = job.area.h + local file_name = string.match(tostring(job.file.url), ".*[/\\](.*)") + local lines = string.format("📁 \x1b[2m%s\x1b[0m\n", file_name) + local num_lines = 1 + local num_skip = 0 + repeat + local line, event = child:read_line() + if event == 1 then + ya.err(tostring(event)) + elseif event ~= 0 then + break + end + + if line:find('Archive', 1, true) ~= 1 and line:find('[INFO]', 1, true) ~= 1 then + if num_skip >= job.skip then + lines = lines .. line + num_lines = num_lines + 1 + else + num_skip = num_skip + 1 + end + end + until num_lines >= limit + + child:start_kill() + if job.skip > 0 and num_lines < limit then + ya.manager_emit( + "peek", + { tostring(math.max(0, job.skip - (limit - num_lines))), only_if = tostring(job.file.url), upper_bound = "" } + ) + else + ya.preview_widgets(job, { ui.Text(lines):area(job.area) }) + end +end + +function M:seek(job) + local h = cx.active.current.hovered + if h and h.url == job.file.url then + local step = math.floor(job.units * job.area.h / 10) + ya.manager_emit("peek", { + math.max(0, cx.active.preview.skip + step), + only_if = tostring(job.file.url), + }) + end +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 + +-- Get the files that need to be compressed and infer a default archive name +local get_compression_target = ya.sync(function() + local tab = cx.active + local default_name + local paths = {} + if #tab.selected == 0 then + if tab.current.hovered then + local name = tab.current.hovered.name + default_name = name + table.insert(paths, name) + else + return + end + else + default_name = tab.current.cwd.name + for _, url in pairs(tab.selected) do + table.insert(paths, tostring(url)) + end + -- The compression targets are aquired, now unselect them + ya.manager_emit("escape", {}) + end + return paths, default_name +end) + +local function invoke_compress_command(paths, name) + local cmd_output, err_code = Command("ouch") + :args({ "c", "-y" }) + :args(paths) + :arg(name) + :stderr(Command.PIPED) + :output() + if err_code ~= nil then + ya.notify({ + title = "Failed to run ouch command", + content = "Status: " .. err_code, + timeout = 5.0, + level = "error", + }) + elseif not cmd_output.status.success then + ya.notify({ + title = "Compression failed: status code " .. cmd_output.status.code, + content = cmd_output.stderr, + timeout = 5.0, + level = "error", + }) + end +end + +function M:entry(job) + local default_fmt = job.args[1] + if default_fmt == nil then + default_fmt = "zip" + end + + ya.manager_emit("escape", { visual = true }) + + -- Get the files that need to be compressed and infer a default archive name + local paths, default_name = get_compression_target() + + -- Get archive name from user + local output_name, name_event = ya.input({ + title = "Create archive:", + value = default_name .. "." .. default_fmt, + position = { "top-center", y = 3, w = 40 }, + }) + if name_event ~= 1 then + return + end + + -- Get confirmation if file exists + if file_exists(output_name) then + local confirm, confirm_event = ya.input({ + title = "Overwrite " .. output_name .. "? (y/N)", + position = { "top-center", y = 3, w = 40 }, + }) + if not (confirm_event == 1 and confirm:lower() == "y") then + return + end + end + + invoke_compress_command(paths, output_name) +end + +return M