diff --git a/lua/oil/mutator/init.lua b/lua/oil/mutator/init.lua index 494420e..d57bb24 100644 --- a/lua/oil/mutator/init.lua +++ b/lua/oil/mutator/init.lua @@ -431,19 +431,24 @@ M.process_actions = function(actions, cb) next_action() end +local mutation_in_progress = false + ---@param confirm nil|boolean M.try_write_changes = function(confirm) + if mutation_in_progress then + error("Cannot perform mutation when already in progress") + return + end local current_buf = vim.api.nvim_get_current_buf() local was_modified = vim.bo.modified local buffers = view.get_all_buffers() local all_diffs = {} local all_errors = {} - local was_modifiable = {} + mutation_in_progress = true + -- Lock the buffer to prevent race conditions from the user modifying them during parsing + view.lock_buffers() for _, bufnr in ipairs(buffers) do - was_modifiable[bufnr] = vim.bo[bufnr].modifiable - -- Lock the buffer to prevent race conditions - vim.bo[bufnr].modifiable = false if vim.bo[bufnr].modified then local diffs, errors = parser.parse(bufnr) all_diffs[bufnr] = diffs @@ -453,13 +458,12 @@ M.try_write_changes = function(confirm) end end local function unlock() - for _, bufnr in ipairs(buffers) do - pcall(vim.api.nvim_buf_set_option, bufnr, "modifiable", was_modifiable[bufnr]) - end + view.unlock_buffers() -- The ":write" will set nomodified even if we cancel here, so we need to restore it if was_modified then vim.bo[current_buf].modified = true end + mutation_in_progress = false end local ns = vim.api.nvim_create_namespace("Oil") @@ -500,8 +504,10 @@ M.try_write_changes = function(confirm) M.process_actions( actions, vim.schedule_wrap(function(err) + view.unlock_buffers() if err then vim.notify(string.format("[oil] Error applying actions: %s", err), vim.log.levels.ERROR) + view.rerender_all_oil_buffers({ preserve_undo = false }) else local current_entry = oil.get_cursor_entry() if current_entry then @@ -513,6 +519,7 @@ M.try_write_changes = function(confirm) end view.rerender_all_oil_buffers({ preserve_undo = M.trash }) end + mutation_in_progress = false end) ) end) diff --git a/lua/oil/mutator/progress.lua b/lua/oil/mutator/progress.lua index 5acb1c6..6380ca7 100644 --- a/lua/oil/mutator/progress.lua +++ b/lua/oil/mutator/progress.lua @@ -69,7 +69,9 @@ function Progress:close() self.timer = nil end if self.winid then - vim.api.nvim_win_close(self.winid, true) + if vim.api.nvim_win_is_valid(self.winid) then + vim.api.nvim_win_close(self.winid, true) + end self.winid = nil end end diff --git a/lua/oil/view.lua b/lua/oil/view.lua index 86a4ca8..d2cd1a4 100644 --- a/lua/oil/view.lua +++ b/lua/oil/view.lua @@ -103,6 +103,30 @@ M.get_all_buffers = function() return vim.tbl_filter(vim.api.nvim_buf_is_loaded, vim.tbl_keys(session)) end +local buffers_locked = false +---Make all oil buffers nomodifiable +M.lock_buffers = function() + buffers_locked = true + for bufnr in pairs(session) do + if vim.api.nvim_buf_is_loaded(bufnr) then + vim.bo[bufnr].modifiable = false + end + end +end + +---Restore normal modifiable settings for oil buffers +M.unlock_buffers = function() + buffers_locked = false + for bufnr in pairs(session) do + if vim.api.nvim_buf_is_loaded(bufnr) then + local adapter = util.get_adapter(bufnr) + if adapter then + vim.bo[bufnr].modifiable = adapter.is_modifiable(bufnr) + end + end + end +end + ---@param opts table ---@note --- This DISCARDS ALL MODIFICATIONS a user has made to oil buffers @@ -350,7 +374,7 @@ local function render_buffer(bufnr, opts) }) local scheme = util.parse_url(bufname) local adapter = util.get_adapter(bufnr) - if not adapter then + if not scheme or not adapter then return false end local entries = cache.list_url(bufname) @@ -539,7 +563,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 - vim.bo[bufnr].modifiable = adapter.is_modifiable(bufnr) + vim.bo[bufnr].modifiable = not buffers_locked and adapter.is_modifiable(bufnr) if callback then callback() end