feat: can cancel out of progress window
This commit is contained in:
parent
9871ca9737
commit
273c2cecbf
7 changed files with 128 additions and 58 deletions
|
|
@ -1,6 +1,6 @@
|
|||
local M = {}
|
||||
|
||||
---@param exe_modifier nil|string
|
||||
---@param exe_modifier nil|false|string
|
||||
---@param num integer
|
||||
---@return string
|
||||
local function perm_to_str(exe_modifier, num)
|
||||
|
|
@ -36,9 +36,9 @@ M.mode_to_octal_str = function(mode)
|
|||
end
|
||||
|
||||
---@param str string String of 3 characters
|
||||
---@return integer
|
||||
---@return nil|integer
|
||||
local function str_to_mode(str)
|
||||
local r, w, x = unpack(vim.split(str, ""))
|
||||
local r, w, x = unpack(vim.split(str, "", {}))
|
||||
local mode = 0
|
||||
if r == "r" then
|
||||
mode = bit.bor(mode, 4)
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ M.set_loading = function(bufnr, is_loading)
|
|||
return
|
||||
end
|
||||
local lines = { util.lpad("Loading", math.floor(width / 2) - 3), bar_iter() }
|
||||
util.render_centered_text(bufnr, lines)
|
||||
util.render_text(bufnr, lines)
|
||||
end)
|
||||
)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -387,22 +387,33 @@ M.process_actions = function(actions, cb)
|
|||
|
||||
local finished = false
|
||||
local progress = Progress.new()
|
||||
local function finish(...)
|
||||
if not finished then
|
||||
finished = true
|
||||
progress:close()
|
||||
cb(...)
|
||||
end
|
||||
end
|
||||
|
||||
-- Defer showing the progress to avoid flicker for fast operations
|
||||
vim.defer_fn(function()
|
||||
if not finished then
|
||||
progress:show()
|
||||
progress:show({
|
||||
-- TODO some actions are actually cancelable.
|
||||
-- We should stop them instead of stopping after the current action
|
||||
cancel = function()
|
||||
finish("Canceled")
|
||||
end,
|
||||
})
|
||||
end
|
||||
end, 100)
|
||||
|
||||
local function finish(...)
|
||||
finished = true
|
||||
progress:close()
|
||||
cb(...)
|
||||
end
|
||||
|
||||
local idx = 1
|
||||
local next_action
|
||||
next_action = function()
|
||||
if finished then
|
||||
return
|
||||
end
|
||||
if idx > #actions then
|
||||
finish()
|
||||
return
|
||||
|
|
@ -415,7 +426,10 @@ M.process_actions = function(actions, cb)
|
|||
return finish(adapter)
|
||||
end
|
||||
local callback = vim.schedule_wrap(function(err)
|
||||
if err then
|
||||
if finished then
|
||||
-- This can happen if the user canceled out of the progress window
|
||||
return
|
||||
elseif err then
|
||||
finish(err)
|
||||
else
|
||||
cache.perform_action(action)
|
||||
|
|
|
|||
|
|
@ -45,25 +45,11 @@ end
|
|||
---@param bufnr integer
|
||||
---@param lines string[]
|
||||
local function render_lines(winid, bufnr, lines)
|
||||
-- Finish setting the last line and highlights on the buffer
|
||||
local width = vim.api.nvim_win_get_width(winid)
|
||||
local height = vim.api.nvim_win_get_height(winid)
|
||||
while #lines < height do
|
||||
table.insert(lines, "")
|
||||
end
|
||||
local last_line = "[O]k [C]ancel"
|
||||
local padding = string.rep(" ", math.floor((width - last_line:len()) / 2))
|
||||
local p_len = padding:len()
|
||||
local padded_last_line = padding .. last_line
|
||||
lines[#lines] = padded_last_line
|
||||
vim.bo[bufnr].modifiable = true
|
||||
vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, lines)
|
||||
vim.bo[bufnr].modified = false
|
||||
vim.bo[bufnr].modifiable = false
|
||||
local ns = vim.api.nvim_create_namespace("Oil")
|
||||
vim.api.nvim_buf_clear_namespace(bufnr, ns, #lines - 1, #lines)
|
||||
vim.api.nvim_buf_add_highlight(bufnr, ns, "Special", #lines - 1, p_len, p_len + 3)
|
||||
vim.api.nvim_buf_add_highlight(bufnr, ns, "Special", #lines - 1, p_len + 8, p_len + 11)
|
||||
util.render_text(
|
||||
bufnr,
|
||||
lines,
|
||||
{ v_align = "top", h_align = "left", winid = winid, actions = { "[O]k", "[C]ancel" } }
|
||||
)
|
||||
end
|
||||
|
||||
---@param actions oil.Action[]
|
||||
|
|
@ -170,11 +156,9 @@ M.show = vim.schedule_wrap(function(actions, should_confirm, cb)
|
|||
end,
|
||||
})
|
||||
)
|
||||
vim.keymap.set("n", "q", cancel, { buffer = bufnr })
|
||||
vim.keymap.set("n", "C", cancel, { buffer = bufnr })
|
||||
vim.keymap.set("n", "c", cancel, { buffer = bufnr })
|
||||
vim.keymap.set("n", "<Esc>", cancel, { buffer = bufnr })
|
||||
vim.keymap.set("n", "<C-c>", cancel, { buffer = bufnr })
|
||||
for _, cancel_key in ipairs({ "q", "C", "c", "<C-c>", "<Esc>" }) do
|
||||
vim.keymap.set("n", cancel_key, cancel, { buffer = bufnr, nowait = true })
|
||||
end
|
||||
vim.keymap.set("n", "O", confirm, { buffer = bufnr })
|
||||
vim.keymap.set("n", "o", confirm, { buffer = bufnr })
|
||||
end)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,8 @@ function Progress.new()
|
|||
local bufnr = vim.api.nvim_create_buf(false, true)
|
||||
vim.bo[bufnr].bufhidden = "wipe"
|
||||
return setmetatable({
|
||||
lines = { "", "", "" },
|
||||
lines = { "", "" },
|
||||
count = "",
|
||||
bufnr = bufnr,
|
||||
autocmds = {},
|
||||
}, {
|
||||
|
|
@ -19,17 +20,21 @@ function Progress.new()
|
|||
})
|
||||
end
|
||||
|
||||
function Progress:show()
|
||||
---@param opts nil|table
|
||||
--- cancel fun()
|
||||
function Progress:show(opts)
|
||||
opts = opts or {}
|
||||
if self.winid and vim.api.nvim_win_is_valid(self.winid) then
|
||||
return
|
||||
end
|
||||
self.cancel = opts.cancel
|
||||
local loading_iter = loading.get_bar_iter()
|
||||
self.timer = vim.loop.new_timer()
|
||||
self.timer:start(
|
||||
0,
|
||||
math.floor(1000 / FPS),
|
||||
vim.schedule_wrap(function()
|
||||
self.lines[2] = loading_iter()
|
||||
self.lines[2] = string.format("%s %s", self.count, loading_iter())
|
||||
self:_render()
|
||||
end)
|
||||
)
|
||||
|
|
@ -56,10 +61,13 @@ function Progress:show()
|
|||
end,
|
||||
})
|
||||
)
|
||||
local cancel = self.cancel or function() end
|
||||
vim.keymap.set("n", "c", cancel, { buffer = self.bufnr, nowait = true })
|
||||
vim.keymap.set("n", "C", cancel, { buffer = self.bufnr, nowait = true })
|
||||
end
|
||||
|
||||
function Progress:_render()
|
||||
util.render_centered_text(self.bufnr, self.lines)
|
||||
util.render_text(self.bufnr, self.lines, { winid = self.winid, actions = { "[C]ancel" } })
|
||||
end
|
||||
|
||||
function Progress:_reposition()
|
||||
|
|
@ -93,7 +101,7 @@ function Progress:set_action(action, idx, total)
|
|||
change_line = adapter.render_action(action)
|
||||
end
|
||||
self.lines[1] = change_line
|
||||
self.lines[3] = string.format("[%d/%d]", idx, total)
|
||||
self.count = string.format("%d/%d", idx, total)
|
||||
self:_reposition()
|
||||
self:_render()
|
||||
end
|
||||
|
|
|
|||
|
|
@ -428,40 +428,104 @@ M.get_adapter_for_action = function(action)
|
|||
return adapter
|
||||
end
|
||||
|
||||
---@param str string
|
||||
---@param align "left"|"right"|"center"
|
||||
---@param width integer
|
||||
---@return string
|
||||
---@return integer
|
||||
M.h_align = function(str, align, width)
|
||||
if align == "center" then
|
||||
local padding = math.floor((width - vim.api.nvim_strwidth(str)) / 2)
|
||||
return string.rep(" ", padding) .. str, padding
|
||||
elseif align == "right" then
|
||||
local padding = width - vim.api.nvim_strwidth(str)
|
||||
return string.rep(" ", padding) .. str, padding
|
||||
else
|
||||
return str, 0
|
||||
end
|
||||
end
|
||||
|
||||
---@param bufnr integer
|
||||
---@param text string|string[]
|
||||
M.render_centered_text = function(bufnr, text)
|
||||
---@param opts nil|table
|
||||
--- h_align nil|"left"|"right"|"center"
|
||||
--- v_align nil|"top"|"bottom"|"center"
|
||||
--- actions nil|string[]
|
||||
--- winid nil|integer
|
||||
M.render_text = function(bufnr, text, opts)
|
||||
opts = vim.tbl_deep_extend("keep", opts or {}, {
|
||||
h_align = "center",
|
||||
v_align = "center",
|
||||
})
|
||||
if not vim.api.nvim_buf_is_valid(bufnr) then
|
||||
return
|
||||
end
|
||||
if type(text) == "string" then
|
||||
text = { text }
|
||||
end
|
||||
local winid
|
||||
for _, win in ipairs(vim.api.nvim_list_wins()) do
|
||||
if vim.api.nvim_win_get_buf(win) == bufnr then
|
||||
winid = win
|
||||
break
|
||||
end
|
||||
end
|
||||
local height = 40
|
||||
local width = 30
|
||||
if winid then
|
||||
height = vim.api.nvim_win_get_height(winid)
|
||||
width = vim.api.nvim_win_get_width(winid)
|
||||
|
||||
-- If no winid passed in, find the first win that displays this buffer
|
||||
if not opts.winid then
|
||||
for _, winid in ipairs(vim.api.nvim_list_wins()) do
|
||||
if vim.api.nvim_win_is_valid(winid) and vim.api.nvim_win_get_buf(winid) == bufnr then
|
||||
opts.winid = winid
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
if opts.winid then
|
||||
height = vim.api.nvim_win_get_height(opts.winid)
|
||||
width = vim.api.nvim_win_get_width(opts.winid)
|
||||
end
|
||||
local lines = {}
|
||||
for _ = 1, (height / 2) - (#text / 2) do
|
||||
table.insert(lines, "")
|
||||
|
||||
-- Add vertical spacing for vertical alignment
|
||||
if opts.v_align == "center" then
|
||||
for _ = 1, (height / 2) - (#text / 2) do
|
||||
table.insert(lines, "")
|
||||
end
|
||||
elseif opts.v_align == "bottom" then
|
||||
local num_lines = height
|
||||
if opts.actions then
|
||||
num_lines = num_lines - 2
|
||||
end
|
||||
while #lines + #text < num_lines do
|
||||
table.insert(lines, "")
|
||||
end
|
||||
end
|
||||
|
||||
-- Add the lines of text
|
||||
for _, line in ipairs(text) do
|
||||
line = string.rep(" ", (width - vim.api.nvim_strwidth(line)) / 2) .. line
|
||||
line = M.h_align(line, opts.h_align, width)
|
||||
table.insert(lines, line)
|
||||
end
|
||||
vim.api.nvim_buf_set_option(bufnr, "modifiable", true)
|
||||
|
||||
-- Render the actions (if any) at the bottom
|
||||
local highlights = {}
|
||||
if opts.actions then
|
||||
while #lines < height - 1 do
|
||||
table.insert(lines, "")
|
||||
end
|
||||
local last_line, padding = M.h_align(table.concat(opts.actions, " "), "center", width)
|
||||
local col = padding
|
||||
for _, action in ipairs(opts.actions) do
|
||||
table.insert(highlights, { "Special", #lines, col, col + 3 })
|
||||
col = padding + action:len() + 4
|
||||
end
|
||||
table.insert(lines, last_line)
|
||||
end
|
||||
|
||||
vim.bo[bufnr].modifiable = true
|
||||
pcall(vim.api.nvim_buf_set_lines, bufnr, 0, -1, false, lines)
|
||||
vim.api.nvim_buf_set_option(bufnr, "modifiable", false)
|
||||
vim.bo[bufnr].modifiable = false
|
||||
vim.bo[bufnr].modified = false
|
||||
local ns = vim.api.nvim_create_namespace("Oil")
|
||||
vim.api.nvim_buf_clear_namespace(bufnr, ns, 0, -1)
|
||||
for _, hl in ipairs(highlights) do
|
||||
vim.api.nvim_buf_add_highlight(bufnr, ns, unpack(hl))
|
||||
end
|
||||
end
|
||||
|
||||
---Run a function in the context of a full-editor window
|
||||
|
|
|
|||
|
|
@ -532,7 +532,7 @@ M.render_buffer_async = function(bufnr, opts, callback)
|
|||
if not preserve_undo then
|
||||
vim.bo[bufnr].undolevels = vim.api.nvim_get_option("undolevels")
|
||||
end
|
||||
util.render_centered_text(bufnr, { "Error: " .. message })
|
||||
util.render_text(bufnr, { "Error: " .. message })
|
||||
if callback then
|
||||
callback(message)
|
||||
else
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue