NOTE: the `o` and `c` keymaps will continue to work. This only changes the text labels and adds new keymaps for `y` and `n`. * chore: replace ok and cancel with yes and no in confirmation window * chore: allow to configure labels and keymaps for confirmation window * chore: remove potential duplicate cancel keymaps * chore: update README and oil.txt * chore: nowait on confirm mappings and cleanup * refactor: fully transition to yes/no * move the config from under the `confirmation` key to the `preview` key, which is already in use for customizing the window * fully default to yes/no, keeping the o/c keybindings for backwards compatibility * make all of the `cancel` keybindings explicit (q, C-c, esc) * more dynamically choose highlighting of the action labels * refactor: just use yes/no and abandon configuration --------- Co-authored-by: Steven Arcangeli <stevearc@stevearc.com>
187 lines
5.4 KiB
Lua
187 lines
5.4 KiB
Lua
local columns = require("oil.columns")
|
|
local config = require("oil.config")
|
|
local layout = require("oil.layout")
|
|
local util = require("oil.util")
|
|
local M = {}
|
|
|
|
---@param actions oil.Action[]
|
|
---@return boolean
|
|
local function is_simple_edit(actions)
|
|
local num_create = 0
|
|
local num_copy = 0
|
|
local num_move = 0
|
|
for _, action in ipairs(actions) do
|
|
-- If there are any deletes, it is not a simple edit
|
|
if action.type == "delete" then
|
|
return false
|
|
elseif action.type == "create" then
|
|
num_create = num_create + 1
|
|
elseif action.type == "copy" then
|
|
num_copy = num_copy + 1
|
|
-- Cross-adapter copies are not simple
|
|
if util.parse_url(action.src_url) ~= util.parse_url(action.dest_url) then
|
|
return false
|
|
end
|
|
elseif action.type == "move" then
|
|
num_move = num_move + 1
|
|
-- Cross-adapter moves are not simple
|
|
if util.parse_url(action.src_url) ~= util.parse_url(action.dest_url) then
|
|
return false
|
|
end
|
|
end
|
|
end
|
|
-- More than one move/copy is complex
|
|
if num_move > 1 or num_copy > 1 then
|
|
return false
|
|
end
|
|
-- More than 5 creates is complex
|
|
if num_create > 5 then
|
|
return false
|
|
end
|
|
return true
|
|
end
|
|
|
|
---@param winid integer
|
|
---@param bufnr integer
|
|
---@param lines string[]
|
|
local function render_lines(winid, bufnr, lines)
|
|
util.render_text(bufnr, lines, {
|
|
v_align = "top",
|
|
h_align = "left",
|
|
winid = winid,
|
|
actions = { "[Y]es", "[N]o" },
|
|
})
|
|
end
|
|
|
|
---@param actions oil.Action[]
|
|
---@param should_confirm nil|boolean
|
|
---@param cb fun(proceed: boolean)
|
|
M.show = vim.schedule_wrap(function(actions, should_confirm, cb)
|
|
-- The schedule wrap ensures that we actually enter the floating window.
|
|
-- Not sure why it doesn't work without that
|
|
if should_confirm == false or #actions == 0 then
|
|
cb(true)
|
|
return
|
|
end
|
|
if should_confirm == nil and config.skip_confirm_for_simple_edits and is_simple_edit(actions) then
|
|
cb(true)
|
|
return
|
|
end
|
|
|
|
-- Create the buffer
|
|
local bufnr = vim.api.nvim_create_buf(false, true)
|
|
vim.bo[bufnr].bufhidden = "wipe"
|
|
local lines = {}
|
|
local max_line_width = 0
|
|
for _, action in ipairs(actions) do
|
|
local adapter = util.get_adapter_for_action(action)
|
|
local line
|
|
if action.type == "change" then
|
|
---@cast action oil.ChangeAction
|
|
line = columns.render_change_action(adapter, action)
|
|
else
|
|
line = adapter.render_action(action)
|
|
end
|
|
table.insert(lines, line)
|
|
local line_width = vim.api.nvim_strwidth(line)
|
|
if line_width > max_line_width then
|
|
max_line_width = line_width
|
|
end
|
|
end
|
|
table.insert(lines, "")
|
|
|
|
-- Create the floating window
|
|
local width, height = layout.calculate_dims(max_line_width, #lines + 1, config.preview)
|
|
local ok, winid = pcall(vim.api.nvim_open_win, bufnr, true, {
|
|
relative = "editor",
|
|
width = width,
|
|
height = height,
|
|
row = math.floor((layout.get_editor_height() - height) / 2),
|
|
col = math.floor((layout.get_editor_width() - width) / 2),
|
|
zindex = 152, -- render on top of the floating window title
|
|
style = "minimal",
|
|
border = config.preview.border,
|
|
})
|
|
if not ok then
|
|
vim.notify(string.format("Error showing oil preview window: %s", winid), vim.log.levels.ERROR)
|
|
cb(false)
|
|
end
|
|
vim.bo[bufnr].filetype = "oil_preview"
|
|
vim.bo[bufnr].syntax = "oil_preview"
|
|
for k, v in pairs(config.preview.win_options) do
|
|
vim.api.nvim_set_option_value(k, v, { scope = "local", win = winid })
|
|
end
|
|
|
|
render_lines(winid, bufnr, lines)
|
|
|
|
-- Attach autocmds and keymaps
|
|
local cancel
|
|
local confirm
|
|
local autocmds = {}
|
|
local function make_callback(value)
|
|
return function()
|
|
confirm = function() end
|
|
cancel = function() end
|
|
for _, id in ipairs(autocmds) do
|
|
vim.api.nvim_del_autocmd(id)
|
|
end
|
|
autocmds = {}
|
|
vim.api.nvim_win_close(winid, true)
|
|
cb(value)
|
|
end
|
|
end
|
|
cancel = make_callback(false)
|
|
confirm = make_callback(true)
|
|
vim.api.nvim_create_autocmd("BufLeave", {
|
|
callback = function()
|
|
cancel()
|
|
end,
|
|
once = true,
|
|
nested = true,
|
|
buffer = bufnr,
|
|
})
|
|
vim.api.nvim_create_autocmd("WinLeave", {
|
|
callback = function()
|
|
cancel()
|
|
end,
|
|
once = true,
|
|
nested = true,
|
|
})
|
|
table.insert(
|
|
autocmds,
|
|
vim.api.nvim_create_autocmd("VimResized", {
|
|
callback = function()
|
|
if vim.api.nvim_win_is_valid(winid) then
|
|
width, height = layout.calculate_dims(max_line_width, #lines, config.preview)
|
|
vim.api.nvim_win_set_config(winid, {
|
|
relative = "editor",
|
|
width = width,
|
|
height = height,
|
|
row = math.floor((layout.get_editor_height() - height) / 2),
|
|
col = math.floor((layout.get_editor_width() - width) / 2),
|
|
zindex = 152, -- render on top of the floating window title
|
|
})
|
|
render_lines(winid, bufnr, lines)
|
|
end
|
|
end,
|
|
})
|
|
)
|
|
|
|
-- We used to use [C]ancel to cancel, so preserve the old keymap
|
|
local cancel_keys = { "n", "N", "c", "C", "q", "<C-c>", "<Esc>" }
|
|
for _, cancel_key in ipairs(cancel_keys) do
|
|
vim.keymap.set("n", cancel_key, function()
|
|
cancel()
|
|
end, { buffer = bufnr, nowait = true })
|
|
end
|
|
|
|
-- We used to use [O]k to confirm, so preserve the old keymap
|
|
local confirm_keys = { "y", "Y", "o", "O" }
|
|
for _, confirm_key in ipairs(confirm_keys) do
|
|
vim.keymap.set("n", confirm_key, function()
|
|
confirm()
|
|
end, { buffer = bufnr, nowait = true })
|
|
end
|
|
end)
|
|
|
|
return M
|