diff --git a/yazi/init.lua b/yazi/init.lua index 606f974..857c54b 100644 --- a/yazi/init.lua +++ b/yazi/init.lua @@ -44,4 +44,6 @@ setup { require("archivemount"):setup() require("chmod") -require("starship").setup() +require("diff") +require("sudo") +require("starship"):setup() diff --git a/yazi/plugins/diff.yazi/init.lua b/yazi/plugins/diff.yazi/init.lua new file mode 100644 index 0000000..32eb5fc --- /dev/null +++ b/yazi/plugins/diff.yazi/init.lua @@ -0,0 +1,37 @@ +local function info(content) + return ya.notify { + title = "Diff", + content = content, + timeout = 5, + } +end + +local selected_url = ya.sync(function() + for _, u in pairs(cx.active.selected) do + return u + end +end) + +local hovered_url = ya.sync(function() + local h = cx.active.current.hovered + return h and h.url +end) + +return { + entry = function() + local a, b = selected_url(), hovered_url() + if not a then + return info("No file selected") + elseif not b then + return info("No file hovered") + end + + local output, err = Command("diff"):arg("-Naur"):arg(tostring(a)):arg(tostring(b)):output() + if not output then + return info("Failed to run diff, error: " .. err) + end + + ya.clipboard(output.stdout) + info("Diff copied to clipboard") + end, +} diff --git a/yazi/plugins/sudo.yazi/init.lua b/yazi/plugins/sudo.yazi/init.lua new file mode 100644 index 0000000..46f8f76 --- /dev/null +++ b/yazi/plugins/sudo.yazi/init.lua @@ -0,0 +1,196 @@ +local fs = os.getenv("HOME") .. "/.config/yazi/plugins/sudo.yazi/fs.nu" + +function string:ends_with_char(suffix) + return self:sub(-#suffix) == suffix +end + +function string:is_path() + local i = self:find("/") + return self == "." or self == ".." or i and i ~= #self +end + +local function list_map(self, f) + local i = nil + return function() + local v + i, v = next(self, i) + if v then + return f(v) + else + return nil + end + end +end + +local get_state = ya.sync(function(_, cmd) + if cmd == "paste" or cmd == "link" then + local yanked = {} + for _, url in pairs(cx.yanked) do + table.insert(yanked, tostring(url)) + end + + if #yanked == 0 then + return {} + end + + return { + kind = cmd, + value = { + is_cut = cx.yanked.is_cut, + yanked = yanked, + }, + } + elseif cmd == "create" then + return { kind = cmd } + elseif cmd == "remove" then + local selected = {} + + if #cx.active.selected ~= 0 then + for _, url in pairs(cx.active.selected) do + table.insert(selected, tostring(url)) + end + else + table.insert(selected, tostring(cx.active.current.hovered.url)) + end + + return { + kind = cmd, + value = { + selected = selected, + }, + } + elseif cmd == "rename" and #cx.active.selected == 0 then + return { + kind = cmd, + value = { + hovered = tostring(cx.active.current.hovered.url), + }, + } + else + return {} + end +end) + +local function sudo_cmd() + return { "sudo", "-k", "--" } +end + +local function extend_list(self, list) + for _, value in ipairs(list) do + table.insert(self, value) + end +end + +local function extend_iter(self, iter) + for item in iter do + table.insert(self, item) + end +end + +local function execute(command) + ya.manager_emit("shell", { + table.concat(command, " "), + block = true, + confirm = true, + }) +end + +local function sudo_paste(value) + local args = sudo_cmd() + + table.insert(args, fs) + if value.is_cut then + table.insert(args, "mv") + else + table.insert(args, "cp") + end + if value.force then + table.insert(args, "--force") + end + extend_iter(args, list_map(value.yanked, ya.quote)) + + execute(args) +end + +local function sudo_link(value) + local args = sudo_cmd() + + extend_list(args, { fs, "ln" }) + if value.relative then + table.insert(args, "--relative") + end + extend_iter(args, list_map(value.yanked, ya.quote)) + + execute(args) +end + +local function sudo_create() + local name, event = ya.input({ + title = "sudo create:", + position = { "top-center", y = 2, w = 40 }, + }) + + -- Input and confirm + if event == 1 and not name:is_path() then + local args = sudo_cmd() + + if name:ends_with_char("/") then + extend_list(args, { "mkdir", "-p" }) + else + table.insert(args, "touch") + end + table.insert(args, ya.quote(name)) + + execute(args) + end +end + +local function sudo_rename(value) + local new_name, event = ya.input({ + title = "sudo rename:", + position = { "top-center", y = 2, w = 40 }, + }) + + -- Input and confirm + if event == 1 and not new_name:is_path() then + local args = sudo_cmd() + extend_list(args, { "mv", ya.quote(value.hovered), ya.quote(new_name) }) + execute(args) + end +end + +local function sudo_remove(value) + local args = sudo_cmd() + + extend_list(args, { fs, "rm" }) + if value.is_permanent then + table.insert(args, "--permanent") + end + extend_iter(args, list_map(value.selected, ya.quote)) + + execute(args) +end + +return { + entry = function(_, args) + -- https://github.com/sxyazi/yazi/issues/1553#issuecomment-2309119135 + ya.manager_emit("escape", { visual = true }) + + local state = get_state(args[1]) + + if state.kind == "paste" then + state.value.force = args[2] == "-f" + sudo_paste(state.value) + elseif state.kind == "link" then + state.value.relative = args[2] == "-r" + sudo_link(state.value) + elseif state.kind == "create" then + sudo_create() + elseif state.kind == "remove" then + state.value.is_permanent = args[2] == "-P" + sudo_remove(state.value) + elseif state.kind == "rename" then + sudo_rename(state.value) + end + end, +}