From 5c0f9b24ba0b87b8e2a79a685ac4a95577961fff Mon Sep 17 00:00:00 2001 From: Mika Vilpas Date: Sat, 7 Dec 2024 09:12:14 +0200 Subject: [PATCH] feat: using folke/snacks.nvim can preserve window layouts on deletes Issue ===== When yazi deletes a file, yazi.nvim also closes that buffer. However, the default implementation in neovim is to also close the window/split if one is currently open. This is distracting and annoying for users (me). Solution ======== If the https://github.com/folke/snacks.nvim plugin is installed, yazi.nvim uses that to delete the buffer while preserving the window layout. If it's not installed, the old (annoying) behavior is used. In the future, snacks.nvim might come a required dependency for yazi.nvim. --- .../reading-events.cy.ts | 38 +++++++++++++++++-- .../cypress/support/tui-sandbox.ts | 3 ++ .../test-environment/.config/nvim/init.lua | 1 + .../event_handling/yazi_event_handling.lua | 2 +- lua/yazi/utils.lua | 11 ++++++ 5 files changed, 50 insertions(+), 5 deletions(-) diff --git a/integration-tests/cypress/e2e/using-ya-to-read-events/reading-events.cy.ts b/integration-tests/cypress/e2e/using-ya-to-read-events/reading-events.cy.ts index 0f20741e..24655cb2 100644 --- a/integration-tests/cypress/e2e/using-ya-to-read-events/reading-events.cy.ts +++ b/integration-tests/cypress/e2e/using-ya-to-read-events/reading-events.cy.ts @@ -34,16 +34,20 @@ describe("reading events", () => { it("can read 'trash' events and close an open buffer when its file was trashed", () => { // NOTE: trash means moving a file to the trash, not deleting it permanently - cy.startNeovim().then((dir) => { + cy.startNeovim({ + filename: { openInVerticalSplits: ["initial-file.txt", "file2.txt"] }, + }).then((dir) => { // the default file should already be open cy.contains(dir.contents["initial-file.txt"].name) cy.contains("If you see this text, Neovim is ready!") + cy.contains("Hello") // modify the buffer to make sure it works even if the buffer is modified cy.typeIntoTerminal("ccchanged{esc}") - // start yazi + // start yazi and wait for it to display contents cy.typeIntoTerminal("{upArrow}") + cy.contains("subdirectory" satisfies MyTestDirectoryFile) // start file deletion cy.typeIntoTerminal("d") @@ -59,22 +63,40 @@ describe("reading events", () => { // have closed the buffer cy.contains(dir.contents["initial-file.txt"].name).should("not.exist") cy.contains("If you see this text, Neovim is ready").should("not.exist") + + // make sure two windows are open. The test environment uses snacks.nvim + // which should make sure the window layout is preserved when closing + // the deleted buffer. The default in neovim is to also close the + // window. + cy.runExCommand({ command: `echo winnr("$")` }).then((result) => { + expect(result.value).to.match(/2/) + }) }) }) it("can read 'delete' events and close an open buffer when its file was deleted", () => { // NOTE: delete means permanently deleting a file (not moving it to the trash) - cy.startNeovim().then((dir) => { + cy.startNeovim({ + filename: { openInVerticalSplits: ["initial-file.txt", "file2.txt"] }, + }).then((dir) => { // the default file should already be open cy.contains(dir.contents["initial-file.txt"].name) cy.contains("If you see this text, Neovim is ready!") + cy.contains("Hello") + + // make sure If you see this text, Neovim is ready! is in the correct + // buffer so that we are editing the correct buffer in this test + cy.runExCommand({ command: "echo expand('%')" }).then((result) => { + expect(result.value).to.match(/initial-file.txt$/) + }) // modify the buffer to make sure it works even if the buffer is modified cy.typeIntoTerminal("ccchanged{esc}") - // start yazi + // start yazi and wait for it to display contents cy.typeIntoTerminal("{upArrow}") + cy.contains("subdirectory" satisfies MyTestDirectoryFile) // start file deletion cy.typeIntoTerminal("D") @@ -90,6 +112,14 @@ describe("reading events", () => { // have closed the buffer cy.get(dir.contents["initial-file.txt"].name).should("not.exist") cy.contains("If you see this text, Neovim is ready").should("not.exist") + + // make sure two windows are open. The test environment uses snacks.nvim + // which should make sure the window layout is preserved when closing + // the deleted buffer. The default in neovim is to also close the + // window. + cy.runExCommand({ command: `echo winnr("$")` }).then((result) => { + expect(result.value).to.match(/2/) + }) }) }) }) diff --git a/integration-tests/cypress/support/tui-sandbox.ts b/integration-tests/cypress/support/tui-sandbox.ts index efd46802..8eecc500 100644 --- a/integration-tests/cypress/support/tui-sandbox.ts +++ b/integration-tests/cypress/support/tui-sandbox.ts @@ -116,6 +116,9 @@ declare global { runLuaCode(input: LuaCodeClientInput): Chainable + /** Run an ex command in neovim. + * @example "echo expand('%:.')" current file, relative to the cwd + */ runExCommand(input: ExCommandClientInput): Chainable } } diff --git a/integration-tests/test-environment/.config/nvim/init.lua b/integration-tests/test-environment/.config/nvim/init.lua index e731c2d5..30251c46 100644 --- a/integration-tests/test-environment/.config/nvim/init.lua +++ b/integration-tests/test-environment/.config/nvim/init.lua @@ -77,6 +77,7 @@ local plugins = { { "nvim-telescope/telescope.nvim", lazy = true }, { "catppuccin/nvim", name = "catppuccin", priority = 1000 }, { "https://github.com/MagicDuck/grug-far.nvim", opts = {} }, + { "folke/snacks.nvim", opts = {} }, } require("lazy").setup({ spec = plugins }) diff --git a/lua/yazi/event_handling/yazi_event_handling.lua b/lua/yazi/event_handling/yazi_event_handling.lua index 0b7987c6..0d6ed890 100644 --- a/lua/yazi/event_handling/yazi_event_handling.lua +++ b/lua/yazi/event_handling/yazi_event_handling.lua @@ -33,7 +33,7 @@ function M.process_delete_event(event, remaining_events) deleted_buffers[#deleted_buffers + 1] = buffer vim.schedule(function() - vim.api.nvim_buf_delete(buffer.bufnr, { force = true }) + utils.bufdelete(buffer.bufnr) lsp_delete.file_deleted(buffer.path.filename) end) end diff --git a/lua/yazi/utils.lua b/lua/yazi/utils.lua index 4565a6ac..d0854b74 100644 --- a/lua/yazi/utils.lua +++ b/lua/yazi/utils.lua @@ -338,6 +338,17 @@ function M.is_buffer_open(path) return false end +function M.bufdelete(bufnr) + local ok, bufdelete = pcall(function() + return require("snacks.bufdelete") + end) + if ok then + return bufdelete.delete({ buf = bufnr, force = true }) + else + vim.api.nvim_buf_delete(bufnr, { force = true }) + end +end + ---@param instruction RenameableBuffer ---@return nil function M.rename_or_close_buffer(instruction)