diff --git a/lua/yazi.lua b/lua/yazi.lua index 09b11ba0..3adf0fcd 100644 --- a/lua/yazi.lua +++ b/lua/yazi.lua @@ -2,7 +2,7 @@ local window = require('yazi.window') local utils = require('yazi.utils') local vimfn = require('yazi.vimfn') local configModule = require('yazi.config') -local renaming = require('yazi.renaming') +local event_handling = require('yazi.event_handling') local M = {} @@ -28,7 +28,7 @@ function M.yazi(config, path) os.remove(config.chosen_file_path) local cmd = string.format( - 'yazi "%s" --local-events "rename" --chooser-file "%s" > %s', + 'yazi "%s" --local-events "rename,delete,trash" --chooser-file "%s" > %s', path, config.chosen_file_path, config.events_file_path @@ -73,8 +73,9 @@ function M.yazi(config, path) for _, event in ipairs(events) do if event.type == 'rename' then + ---@cast event YaziRenameEvent local rename_instructions = - renaming.get_buffers_that_need_renaming_after_yazi_exited( + event_handling.get_buffers_that_need_renaming_after_yazi_exited( event.data ) for _, instruction in ipairs(rename_instructions) do @@ -83,6 +84,13 @@ function M.yazi(config, path) instruction.path.filename ) end + elseif event.type == 'delete' then + ---@cast event YaziDeleteEvent + event_handling.process_delete_event(event) + elseif event.type == 'trash' then + -- selene: allow(if_same_then_else) + ---@cast event YaziTrashEvent + event_handling.process_delete_event(event) end end end, diff --git a/lua/yazi/renaming.lua b/lua/yazi/event_handling.lua similarity index 58% rename from lua/yazi/renaming.lua rename to lua/yazi/event_handling.lua index a8fe5e59..d6d08f4d 100644 --- a/lua/yazi/renaming.lua +++ b/lua/yazi/event_handling.lua @@ -1,19 +1,25 @@ -local RenameableBuffer = require('yazi.renameable_buffer') +local utils = require('yazi.utils') local M = {} +---@param event YaziDeleteEvent | YaziTrashEvent +function M.process_delete_event(event) + local open_buffers = utils.get_open_buffers() + + for _, buffer in ipairs(open_buffers) do + for _, url in ipairs(event.data.urls) do + if buffer:matches_exactly(url) or buffer:matches_parent(url) then + -- allow the user to cancel the deletion + vim.api.nvim_buf_delete(buffer.bufnr, { force = false }) + end + end + end +end + ---@param rename_event YaziEventDataRename ---@return RenameableBuffer[] "instructions for renaming the buffers (command pattern)" function M.get_buffers_that_need_renaming_after_yazi_exited(rename_event) - ---@type RenameableBuffer[] - local open_buffers = {} - for _, bufnr in ipairs(vim.api.nvim_list_bufs()) do - local path = vim.api.nvim_buf_get_name(bufnr) - if path ~= '' and path ~= nil then - local renameable_buffer = RenameableBuffer.new(bufnr, path) - open_buffers[#open_buffers + 1] = renameable_buffer - end - end + local open_buffers = utils.get_open_buffers() ---@type table local renamed_buffers = {} diff --git a/lua/yazi/types.lua b/lua/yazi/types.lua index f44df9ce..0a59b6ac 100644 --- a/lua/yazi/types.lua +++ b/lua/yazi/types.lua @@ -11,6 +11,8 @@ ---@field public yazi_opened? fun(preselected_path: string | nil): nil ---@field public yazi_closed_successfully? fun(chosen_file: string | nil): nil +---@alias YaziEvent YaziRenameEvent | YaziDeleteEvent | YaziTrashEvent + ---@class YaziRenameEvent ---@field public type "rename" ---@field public timestamp string @@ -20,3 +22,15 @@ ---@class YaziEventDataRename ---@field public from string ---@field public to string + +---@class YaziDeleteEvent +---@field public type "delete" +---@field public timestamp string +---@field public id string +---@field public data {urls: string[]} + +---@class YaziTrashEvent +---@field public type "trash" +---@field public timestamp string +---@field public id string +---@field public data {urls: string[]} diff --git a/lua/yazi/utils.lua b/lua/yazi/utils.lua index e6e4ddcb..cc476446 100644 --- a/lua/yazi/utils.lua +++ b/lua/yazi/utils.lua @@ -1,4 +1,5 @@ local fn = vim.fn +local RenameableBuffer = require('yazi.renameable_buffer') local M = {} @@ -44,6 +45,7 @@ function M.parse_events(events_file_lines) local parts = vim.split(line, ',') local type = parts[1] + -- selene: allow(if_same_then_else) if type == 'rename' then -- example of a rename event: @@ -60,6 +62,38 @@ function M.parse_events(events_file_lines) data = vim.fn.json_decode(data_string), } table.insert(events, event) + elseif type == 'delete' then + -- example of a delete event: + -- delete,1712766606832135,1712766606832135,{"urls":["/tmp/test-directory/test_2"]} + + local timestamp = parts[2] + local id = parts[3] + local data_string = table.concat(parts, ',', 4, #parts) + + ---@type YaziDeleteEvent + local event = { + type = type, + timestamp = timestamp, + id = id, + data = vim.fn.json_decode(data_string), + } + table.insert(events, event) + elseif type == 'trash' then + -- example of a trash event: + -- trash,1712766606832135,1712766606832135,{"urls":["/tmp/test-directory/test_2"]} + + local timestamp = parts[2] + local id = parts[3] + local data_string = table.concat(parts, ',', 4, #parts) + + ---@type YaziTrashEvent + local event = { + type = type, + timestamp = timestamp, + id = id, + data = vim.fn.json_decode(data_string), + } + table.insert(events, event) end end @@ -67,7 +101,7 @@ function M.parse_events(events_file_lines) end ---@param path string ----@return YaziRenameEvent[] +---@return YaziEvent[] function M.read_events_file(path) local success, events_file_lines = pcall(vim.fn.readfile, path) os.remove(path) @@ -85,4 +119,19 @@ function M.read_events_file(path) return events end +---@return RenameableBuffer[] +function M.get_open_buffers() + ---@type RenameableBuffer[] + local open_buffers = {} + for _, bufnr in ipairs(vim.api.nvim_list_bufs()) do + local path = vim.api.nvim_buf_get_name(bufnr) + if path ~= '' and path ~= nil then + local renameable_buffer = RenameableBuffer.new(bufnr, path) + open_buffers[#open_buffers + 1] = renameable_buffer + end + end + + return open_buffers +end + return M diff --git a/tests/yazi/delete_spec.lua b/tests/yazi/delete_spec.lua new file mode 100644 index 00000000..b60e7e4c --- /dev/null +++ b/tests/yazi/delete_spec.lua @@ -0,0 +1,59 @@ +local assert = require('luassert') +local event_handling = require('yazi.event_handling') + +describe('process_delete_event', function() + before_each(function() + -- clear all buffers + for _, buf in ipairs(vim.api.nvim_list_bufs()) do + vim.api.nvim_buf_delete(buf, { force = true }) + end + end) + + it('deletes a buffer that matches the delete event exactly', function() + local buffer = vim.fn.bufadd('/abc/def') + + ---@type YaziDeleteEvent + local event = { + type = 'delete', + timestamp = '1712766606832135', + id = '1712766606832135', + data = { urls = { '/abc/def' } }, + } + + event_handling.process_delete_event(event) + + assert.is_false(vim.api.nvim_buf_is_valid(buffer)) + end) + + it('deletes a buffer that matches the parent directory', function() + local buffer = vim.fn.bufadd('/abc/def') + + ---@type YaziDeleteEvent + local event = { + type = 'delete', + timestamp = '1712766606832135', + id = '1712766606832135', + data = { urls = { '/abc' } }, + } + + event_handling.process_delete_event(event) + + assert.is_false(vim.api.nvim_buf_is_valid(buffer)) + end) + + it("doesn't delete a buffer that doesn't match the delete event", function() + local buffer = vim.fn.bufadd('/abc/def') + + ---@type YaziDeleteEvent + local event = { + type = 'delete', + timestamp = '1712766606832135', + id = '1712766606832135', + data = { urls = { '/abc/ghi' } }, + } + + event_handling.process_delete_event(event) + + assert.is_true(vim.api.nvim_buf_is_valid(buffer)) + end) +end) diff --git a/tests/yazi/open_dir_spec.lua b/tests/yazi/open_dir_spec.lua index 2ec5d3d7..fe26767a 100644 --- a/tests/yazi/open_dir_spec.lua +++ b/tests/yazi/open_dir_spec.lua @@ -21,7 +21,7 @@ describe('when the user set open_for_directories = true', function() vim.api.nvim_command('edit /') assert.stub(api_mock.termopen).was_called_with( - 'yazi "/" --local-events "rename" --chooser-file "/tmp/yazi_filechosen" > /tmp/yazi.nvim.events.txt', + 'yazi "/" --local-events "rename,delete,trash" --chooser-file "/tmp/yazi_filechosen" > /tmp/yazi.nvim.events.txt', match.is_table() ) end) diff --git a/tests/yazi/read_events_spec.lua b/tests/yazi/read_events_spec.lua index bd3f3fef..6ba83944 100644 --- a/tests/yazi/read_events_spec.lua +++ b/tests/yazi/read_events_spec.lua @@ -22,4 +22,23 @@ describe('parsing yazi event file events', function() }, }) end) + + it('can parse delete events', function() + local data = { + 'delete,1712766606832135,1712766606832135,{"urls":["/tmp/test-directory/test_2"]}', + } + + local events = utils.parse_events(data) + + assert.are.same(events, { + { + type = 'delete', + timestamp = '1712766606832135', + id = '1712766606832135', + data = { + urls = { '/tmp/test-directory/test_2' }, + }, + }, + }) + end) end) diff --git a/tests/yazi/rename_spec.lua b/tests/yazi/rename_spec.lua index 1beba0f6..e57e6c51 100644 --- a/tests/yazi/rename_spec.lua +++ b/tests/yazi/rename_spec.lua @@ -1,5 +1,5 @@ local assert = require('luassert') -local renaming = require('yazi.renaming') +local event_handning = require('yazi.event_handling') describe('get_buffers_that_need_renaming_after_yazi_exited', function() before_each(function() @@ -21,7 +21,9 @@ describe('get_buffers_that_need_renaming_after_yazi_exited', function() vim.fn.bufadd('/my-tmp/file_A') local rename_instructions = - renaming.get_buffers_that_need_renaming_after_yazi_exited(rename_event) + event_handning.get_buffers_that_need_renaming_after_yazi_exited( + rename_event + ) assert.is_equal(vim.tbl_count(rename_instructions), 1) @@ -43,7 +45,9 @@ describe('get_buffers_that_need_renaming_after_yazi_exited', function() vim.fn.bufadd('/my-tmp/dir1/file') local rename_instructions = - renaming.get_buffers_that_need_renaming_after_yazi_exited(rename_event) + event_handning.get_buffers_that_need_renaming_after_yazi_exited( + rename_event + ) assert.is_equal(vim.tbl_count(rename_instructions), 1) local result = rename_instructions[1] @@ -62,7 +66,9 @@ describe('get_buffers_that_need_renaming_after_yazi_exited', function() vim.fn.bufadd('/my-tmp/dir1/file') local rename_instructions = - renaming.get_buffers_that_need_renaming_after_yazi_exited(rename_event) + event_handning.get_buffers_that_need_renaming_after_yazi_exited( + rename_event + ) assert.is_equal(vim.tbl_count(rename_instructions), 0) end) diff --git a/tests/yazi/trash_spec.lua b/tests/yazi/trash_spec.lua new file mode 100644 index 00000000..c570cc8b --- /dev/null +++ b/tests/yazi/trash_spec.lua @@ -0,0 +1,59 @@ +local assert = require('luassert') +local event_handling = require('yazi.event_handling') + +describe('process_trash_event', function() + before_each(function() + -- clear all buffers + for _, buf in ipairs(vim.api.nvim_list_bufs()) do + vim.api.nvim_buf_delete(buf, { force = true }) + end + end) + + it('deletes a buffer that matches the trash event exactly', function() + local buffer = vim.fn.bufadd('/abc/def') + + ---@type YaziTrashEvent + local event = { + type = 'trash', + timestamp = '1712766606832135', + id = '1712766606832135', + data = { urls = { '/abc/def' } }, + } + + event_handling.process_delete_event(event) + + assert.is_false(vim.api.nvim_buf_is_valid(buffer)) + end) + + it('deletes a buffer that matches the parent directory', function() + local buffer = vim.fn.bufadd('/abc/def') + + ---@type YaziTrashEvent + local event = { + type = 'trash', + timestamp = '1712766606832135', + id = '1712766606832135', + data = { urls = { '/abc' } }, + } + + event_handling.process_delete_event(event) + + assert.is_false(vim.api.nvim_buf_is_valid(buffer)) + end) + + it("doesn't delete a buffer that doesn't match the trash event", function() + local buffer = vim.fn.bufadd('/abc/def') + + ---@type YaziTrashEvent + local event = { + type = 'trash', + timestamp = '1712766606832135', + id = '1712766606832135', + data = { urls = { '/abc/ghi' } }, + } + + event_handling.process_delete_event(event) + + assert.is_true(vim.api.nvim_buf_is_valid(buffer)) + end) +end) diff --git a/tests/yazi/yazi_spec.lua b/tests/yazi/yazi_spec.lua index 00ea3281..c754f84f 100644 --- a/tests/yazi/yazi_spec.lua +++ b/tests/yazi/yazi_spec.lua @@ -17,7 +17,7 @@ describe('opening a file', function() plugin.yazi() assert.stub(api_mock.termopen).was_called_with( - 'yazi "/abc/test-file.txt" --local-events "rename" --chooser-file "/tmp/yazi_filechosen" > /tmp/yazi.nvim.events.txt', + 'yazi "/abc/test-file.txt" --local-events "rename,delete,trash" --chooser-file "/tmp/yazi_filechosen" > /tmp/yazi.nvim.events.txt', match.is_table() ) end) @@ -28,7 +28,7 @@ describe('opening a file', function() plugin.yazi() assert.stub(api_mock.termopen).was_called_with( - 'yazi "/tmp/" --local-events "rename" --chooser-file "/tmp/yazi_filechosen" > /tmp/yazi.nvim.events.txt', + 'yazi "/tmp/" --local-events "rename,delete,trash" --chooser-file "/tmp/yazi_filechosen" > /tmp/yazi.nvim.events.txt', match.is_table() ) end)