refactor: only gc oil buffers once all oil bufs are hidden

Previously we were gc-ing all hidden oil buffers 2 seconds after they
were hidden. I think this is a little too magical, and interferes with
some expected vim behavior (ctrl-o/i). If people want the old behavior,
we can expose the "GC hidden buffers" function via the API.

We're also changing the "rerender visible oil buffers" logic, because
previously that would delete hidden oil buffers. Now it simply marks
them as dirty, and they will be rerendered during the next BufEnter.
This commit is contained in:
Steven Arcangeli 2023-02-24 07:29:09 -08:00
parent f1131b5e90
commit 0b2a4ddde1
2 changed files with 45 additions and 17 deletions

View file

@ -511,7 +511,7 @@ M.try_write_changes = function(confirm)
vim.split(current_entry.name, "/")[1] vim.split(current_entry.name, "/")[1]
) )
end end
view.rerender_visible_and_cleanup({ preserve_undo = M.trash }) view.rerender_all_oil_buffers({ preserve_undo = M.trash })
end end
end) end)
) )

View file

@ -70,7 +70,7 @@ M.toggle_hidden = function()
vim.notify("Cannot toggle hidden files when you have unsaved changes", vim.log.levels.WARN) vim.notify("Cannot toggle hidden files when you have unsaved changes", vim.log.levels.WARN)
else else
config.view_options.show_hidden = not config.view_options.show_hidden config.view_options.show_hidden = not config.view_options.show_hidden
view.rerender_visible_and_cleanup({ refetch = false }) view.rerender_all_oil_buffers({ refetch = false })
end end
end end
@ -82,7 +82,7 @@ M.set_columns = function(cols)
else else
config.columns = cols config.columns = cols
-- TODO only refetch if we don't have all the necessary data for the columns -- TODO only refetch if we don't have all the necessary data for the columns
view.rerender_visible_and_cleanup({ refetch = true }) view.rerender_all_oil_buffers({ refetch = true })
end end
end end
@ -97,7 +97,7 @@ end
---@param opts table ---@param opts table
---@note ---@note
--- This DISCARDS ALL MODIFICATIONS a user has made to oil buffers --- This DISCARDS ALL MODIFICATIONS a user has made to oil buffers
M.rerender_visible_and_cleanup = function(opts) M.rerender_all_oil_buffers = function(opts)
local buffers = M.get_all_buffers() local buffers = M.get_all_buffers()
local hidden_buffers = {} local hidden_buffers = {}
for _, bufnr in ipairs(buffers) do for _, bufnr in ipairs(buffers) do
@ -110,7 +110,7 @@ M.rerender_visible_and_cleanup = function(opts)
end end
for _, bufnr in ipairs(buffers) do for _, bufnr in ipairs(buffers) do
if hidden_buffers[bufnr] then if hidden_buffers[bufnr] then
vim.api.nvim_buf_delete(bufnr, { force = true }) vim.b[bufnr].oil_dirty = opts
else else
M.render_buffer_async(bufnr, opts) M.render_buffer_async(bufnr, opts)
end end
@ -142,8 +142,12 @@ M.restore_win_options = function()
end end
end end
---Delete hidden oil buffers and if none remain, clear the cache ---Get a list of visible oil buffers and a list of hidden oil buffers
M.cleanup = function() ---@note
--- If any buffers are modified, return values are nil
---@return nil|integer[]
---@return nil|integer[]
local function get_visible_hidden_buffers()
local buffers = M.get_all_buffers() local buffers = M.get_all_buffers()
local hidden_buffers = {} local hidden_buffers = {}
for _, bufnr in ipairs(buffers) do for _, bufnr in ipairs(buffers) do
@ -157,18 +161,22 @@ M.cleanup = function()
hidden_buffers[vim.api.nvim_win_get_buf(winid)] = nil hidden_buffers[vim.api.nvim_win_get_buf(winid)] = nil
end end
end end
local visible_buffers = vim.tbl_filter(function(bufnr)
return not hidden_buffers[bufnr]
end, buffers)
return visible_buffers, vim.tbl_keys(hidden_buffers)
end
local any_remaining = false ---Delete unmodified, hidden oil buffers and if none remain, clear the cache
for _, bufnr in ipairs(buffers) do M.delete_hidden_buffers = function()
if hidden_buffers[bufnr] then local visible_buffers, hidden_buffers = get_visible_hidden_buffers()
vim.api.nvim_buf_delete(bufnr, { force = true }) if not visible_buffers or not hidden_buffers or not vim.tbl_isempty(visible_buffers) then
else return
any_remaining = true
end
end end
if not any_remaining then for _, bufnr in ipairs(hidden_buffers) do
cache.clear_everything() vim.api.nvim_buf_delete(bufnr, { force = true })
end end
cache.clear_everything()
end end
---@param bufnr integer ---@param bufnr integer
@ -198,7 +206,16 @@ M.initialize = function(bufnr)
nested = true, nested = true,
buffer = bufnr, buffer = bufnr,
callback = function() callback = function()
vim.defer_fn(M.cleanup, 2000) -- First wait a short time (10ms) for the buffer change to settle
vim.defer_fn(function()
local visible_buffers = get_visible_hidden_buffers()
-- Only kick off the 2-second timer if we don't have any visible oil buffers
if visible_buffers and vim.tbl_isempty(visible_buffers) then
vim.defer_fn(function()
M.delete_hidden_buffers()
end, 2000)
end
end, 10)
end, end,
}) })
vim.api.nvim_create_autocmd("BufDelete", { vim.api.nvim_create_autocmd("BufDelete", {
@ -210,6 +227,17 @@ M.initialize = function(bufnr)
session[bufnr] = nil session[bufnr] = nil
end, end,
}) })
vim.api.nvim_create_autocmd("BufEnter", {
group = "Oil",
buffer = bufnr,
callback = function(args)
local opts = vim.b[args.buf].oil_dirty
if opts then
vim.b[args.buf].oil_dirty = nil
M.render_buffer_async(args.buf, opts)
end
end,
})
local timer local timer
vim.api.nvim_create_autocmd("CursorMoved", { vim.api.nvim_create_autocmd("CursorMoved", {
desc = "Update oil preview window", desc = "Update oil preview window",