You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

220 lines
5.1 KiB

local M = {}
local get_yanked_info = ya.sync(function()
local cwd = cx.active.current.cwd
local cut = cx.yanked.is_cut
local yanked = {}
for _, url in ipairs(cx.yanked:urls()) do
yanked[#yanked + 1] = { url = url, name = tostring(url.name) }
end
return { cwd = cwd, cut = cut, yanked = yanked }
end)
local function rename_default(name, attempt)
if attempt and attempt > 1 then
local suffix = string.format("-%d", attempt)
local stem = name:match("^(.+)%..-$") or name
local ext = name:match("%.(.+)$") or ""
if ext ~= "" then
return stem .. suffix .. "." .. ext
else
return name .. suffix
end
end
local suffix = os.date("-%y%m%d")
local stem = name:match("^(.+)%..-$") or name
local ext = name:match("%.(.+)$") or ""
if ext ~= "" then
return stem .. suffix .. "." .. ext
else
return name .. suffix
end
end
--Choices:
-- 0: Merge — merge directory contents, overwrite individual files
-- 1: Merge all — same, applied to all remaining conflicts
-- 2: Replace — replace destination entirely (delete then copy)
-- 3: Rename — prompt for a new name
-- 4: Skip — skip this item
-- 5: Cancel(nil) — abort
local function pick_conflict(name)
return ya.pick({
title = "Paste conflict: " .. name,
items = {
"Merge",
"Merge all remaining",
"Replace",
"Rename",
"Skip",
"Cancel",
},
})
end
function M:entry(job)
local info = get_yanked_info()
local cwd, cut, yanked = info.cwd, info.cut, info.yanked
if #yanked == 0 then
return
end
local follow = job.args.follow or false
local resolved = {}
-- Partition: check each yanked item for conflicts
local conflicts = {}
for _, item in ipairs(yanked) do
local dest = cwd:join(item.name)
local cha = fs.cha(dest)
if cha ~= nil then
conflicts[#conflicts + 1] = { url = item.url, dest = dest, name = item.name }
else
resolved[#resolved + 1] = {
from = tostring(item.url),
to = tostring(dest),
overwrite = false,
replace = false,
}
end
end
-- Dispatch helper
local function dispatch(items)
if #items > 0 then
ya.emit("paste_resolved", {
cut = cut,
follow = follow,
items = items,
})
end
end
-- Process conflicts
local merge_all = false
for _, item in ipairs(conflicts) do
if merge_all then
resolved[#resolved + 1] = {
from = tostring(item.url),
to = tostring(item.dest),
overwrite = true,
replace = false,
}
else
local choice = pick_conflict(item.name)
if choice == nil or choice == 5 then
-- Cancel: paste what we have so far, then abort
dispatch(resolved)
return
elseif choice == 0 then
-- Merge current
resolved[#resolved + 1] = {
from = tostring(item.url),
to = tostring(item.dest),
overwrite = true,
replace = false,
}
elseif choice == 1 then
-- Merge all remaining
merge_all = true
resolved[#resolved + 1] = {
from = tostring(item.url),
to = tostring(item.dest),
overwrite = true,
replace = false,
}
elseif choice == 2 then
-- Replace
resolved[#resolved + 1] = {
from = tostring(item.url),
to = tostring(item.dest),
overwrite = true,
replace = true,
}
elseif choice == 3 then
-- Rename: loop until a non-conflicting name is chosen or cancelled
local attempt = 0
while true do
attempt = attempt + 1
local default = rename_default(item.name, attempt)
local value, event = ya.input({
title = "New name",
value = default,
pos = { "center", w = 60 },
})
if event ~= 1 then
-- User cancelled the input — skip this item
break
end
local new_dest = cwd:join(value)
if fs.cha(new_dest) == nil then
-- No conflict — add and continue
resolved[#resolved + 1] = {
from = tostring(item.url),
to = tostring(new_dest),
overwrite = false,
replace = false,
}
break
else
-- New name also conflicts — show the conflict dialog again
local sub_choice = pick_conflict(value)
if sub_choice == nil or sub_choice == 5 then
-- Cancel everything
dispatch(resolved)
return
elseif sub_choice == 0 then
resolved[#resolved + 1] = {
from = tostring(item.url),
to = tostring(new_dest),
overwrite = true,
replace = false,
}
break
elseif sub_choice == 1 then
merge_all = true
resolved[#resolved + 1] = {
from = tostring(item.url),
to = tostring(new_dest),
overwrite = true,
replace = false,
}
break
elseif sub_choice == 2 then
resolved[#resolved + 1] = {
from = tostring(item.url),
to = tostring(new_dest),
overwrite = true,
replace = true,
}
break
elseif sub_choice == 3 then
-- Rename again — increment attempt for different default
-- (loop continues)
elseif sub_choice == 4 then
-- Skip
break
end
end
end
elseif choice == 4 then
-- Skip: do nothing
end
end
end
-- Dispatch all resolved items
dispatch(resolved)
end
return M