nvim-tree.lua icon indicating copy to clipboard operation
nvim-tree.lua copied to clipboard

How to customize buffer delete when delete file?

Open weilbith opened this issue 5 years ago • 6 comments

Hey :wave: Thanks for your cool plugin. I recognized that if I delete a file where an associated buffer is still shown in an open window, this window gets closed. I guess that is by the default behavior of how NeoVim deletes buffers. Therefore I use the plugin sayonara. How can I make this also used when deleting files? Thanks for your help!

weilbith avatar Dec 07 '20 00:12 weilbith

are you asking to keep the buffers open ?

kyazdani42 avatar Dec 07 '20 18:12 kyazdani42

i do close the windows when a file is removed because it causes issues with the nvim instance when saving the file

kyazdani42 avatar Dec 07 '20 18:12 kyazdani42

are you asking to keep the buffers open ?

No, but the windows. I think the default behavior of Vim on removing buffers is stupid, so I changed it. Would be cool to be able to stick to it here was well.

So let's take an example. I have one "main" window open and aside this plugin. I have a couple of buffers loaded. Now I delete the file in Lua Tree that has an associated buffer currently displayed in the main window. As result this closes the main window and I end up with just the Lua Tree. If I would have enabled to close Vim if Lua Tree is the last window, this would even close Vim at all. Instead I would like to keep my window layout (maybe a couple more), the buffer for the deleted file gets removed, but the window remains and the next buffer in the list gets displayed. I would not expect you to implement this. Therefore other minimal plugins (as the linked one) exist. But it would be great if you allow the user to somehow intersect here to customize it.

weilbith avatar Dec 07 '20 20:12 weilbith

i think it would be possible. I do not have much time lately to work on opensource projects, so if you want to give it a shot ,go for it :). There might be one line to remove. Basically i prefer deleting the windows because it throws errors everywhere when editing the buffer.

kyazdani42 avatar Dec 09 '20 18:12 kyazdani42

We can use a custom action to do something like this:

        { key = "d", action = "sayonara_remove", action_cb = sayonara_remove, },
local function sayonara_remove(node)
  -- foreach window containing the buffer for node.absolute_path
    vim.cmd "wincmd 1111"
    vim.cmd ":Sayonara!"
  -- endfor
  require("nvim-tree.actions.remove-file").fn(node)
end

You'll need to write that window iterator yourself. It would be great if Sayonara accepted a bufnr as an argument ;)

Thanks for letting me know about Sayonara... deleting/wiping buffers has always been horrible in vim.

alex-courtis avatar Apr 03 '22 03:04 alex-courtis

I've been using something like this in my neovim config instead of sayonara and others, not directly related to nvim-tree but just to show it's easy to fix default neovim functionality by roughly 40 lines of code. I think it would be easy to implement this inside nvim-tree but sadly I don't have time to do it right now. But basically it tries to find an alternative buffer to show for that window before removing it with :bdelete, so window can remain in place.

-- Remove current buffer without losing window layout.
api.nvim_set_keymap.map(
  'n',
  '\\q',
  "<Cmd>lua require('kutsan/mappings/normal/bufremove').bufremove({ force = false })<CR>",
  { silent = true, noremap = true, }
)
api.nvim_set_keymap.map(
  'n',
  '\\Q',
  "<Cmd>lua require('kutsan/mappings/normal/bufremove').bufremove({ force = true })<CR>",
  { silent = true, noremap = true, }
)
local api = vim.api
local fn = vim.fn
local cmd = vim.cmd

local function bufremove(opts)
  local target_buf_id = api.nvim_get_current_buf()

  -- Do nothing if buffer is in modified state.
  if not opts.force and api.nvim_buf_get_option(target_buf_id, 'modified') then
    return false
  end

  -- Hide target buffer from all windows.
  vim.tbl_map(function(win_id)
    win_id = win_id or 0

    local current_buf_id = api.nvim_win_get_buf(win_id)

    api.nvim_win_call(win_id, function()
      -- Try using alternate buffer
      local alt_buf_id = fn.bufnr('#')
      if alt_buf_id ~= current_buf_id and fn.buflisted(alt_buf_id) == 1 then
        api.nvim_win_set_buf(win_id, alt_buf_id)
        return
      end

      -- Try using previous buffer
      cmd('bprevious')
      if current_buf_id ~= api.nvim_win_get_buf(win_id) then
        return
      end

      -- Create new listed scratch buffer
      local new_buf = api.nvim_create_buf(true, true)
      api.nvim_win_set_buf(win_id, new_buf)
    end)

    return true
  end, fn.win_findbuf(target_buf_id))

  cmd(string.format('bdelete%s %d', opts.force and '!' or '', target_buf_id))
end

return { bufremove = bufremove }

kutsan avatar Apr 03 '22 12:04 kutsan

It sounds like you have a great solution there @kutsan

Any chance you could write up your RECIPE on the wiki?

It might also be worth checking out https://github.com/qpkorr/vim-bufkill

alex-courtis avatar Oct 23 '22 04:10 alex-courtis