Skip to content

Commit

Permalink
feat: can cancel out of progress window
Browse files Browse the repository at this point in the history
  • Loading branch information
stevearc committed Mar 30, 2023
1 parent 9871ca9 commit 273c2ce
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 58 deletions.
6 changes: 3 additions & 3 deletions lua/oil/adapters/files/permissions.lua
Original file line number Diff line number Diff line change
@@ -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)
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion lua/oil/loading.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
30 changes: 22 additions & 8 deletions lua/oil/mutator/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand Down
32 changes: 8 additions & 24 deletions lua/oil/mutator/preview.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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[]
Expand Down Expand Up @@ -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)
Expand Down
18 changes: 13 additions & 5 deletions lua/oil/mutator/progress.lua
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,30 @@ 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 = {},
}, {
__index = Progress,
})
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)
)
Expand All @@ -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()
Expand Down Expand Up @@ -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
Expand Down
96 changes: 80 additions & 16 deletions lua/oil/util.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion lua/oil/view.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 273c2ce

Please sign in to comment.