0

I'm trying to implement a simple autocommand, which deletes a buffer when it's hidden, with a condition that the file hasn't been modified in the last N seconds. I have the following code in ~/.vim/autoload/tools.vim:

function tools#TimeSinceModified(file)
  return localtime() - getftime(a:file)
endfunction

let s:delete_buf_after_s = 1800

function tools#DeleteBuffer(bufnr)
  if !&modified && tools#TimeSinceModified(bufname(a:bufnr)) > s:delete_buf_after_s
    execute 'bdelete' a:bufnr
  endif
endfunction

Then, in my .vimrc, I have this autocommand:

autocmd BufHidden * call tools#DeleteBuffer(expand("<abuf>"))

This doesn't work, however. The buffer isn't deleted, and the editor prompts the following error whenever a buffer is being hidden:

Error detected while processing function tools#DeleteBuffer:
line    2:
E937: Attempt to delete a buffer that is in use

Is there some way of getting around this error? How can I get this functionality to work?

7
  • Did you read the documentation for :bdelete? If you mean to force close the buffer even if it has changes since it was last saved then just add ! after :bdelete.
    – B Layer
    Mar 20, 2021 at 10:27
  • @BLayer Yes, I did read the documentation for :bdelete. I think in this case the command without ! should be sufficient since we're checking that the modified flag is 0, so there shouldn't be any unsaved changes. I also tried bdelete! instead of bdelete in the function, but I still get the same error. Mar 20, 2021 at 13:02
  • 1
    I wonder if the fact that tis is during the bufhidden autocommand is the issue. Maybe try using a short timer to run the bdelete?
    – D. Ben Knoble
    Mar 20, 2021 at 13:07
  • @D.BenKnoble That might be the problem. I currently have hidden option set, so this is triggered everytime a buffer is hidden. But do you know if there is any some other way of achieving the similar functionality I described before? Maybe setting nohidden and setting the bufhidden option for buffers? Mar 20, 2021 at 15:42
  • I would try starting a timer, either in the function or in the autocommand. Honestly, though, i wouldn’t worry about deleting buffers this way unless there’s some particular reason to.
    – D. Ben Knoble
    Mar 20, 2021 at 15:58

1 Answer 1

0

I would use a timer to avoid messing with the buffer during the BufHidden event; something like

function tools#DeleteBuffer(bufnr)
  if !&modified && tools#TimeSinceModified(bufname(a:bufnr)) > s:delete_buf_after_s
    call timer_start(100, {_ -> execute('bdelete '.a:bufnr)})
  endif 
endfunction

We have to use the execute() function here because a lambda-body is an expr1 (:help lambda), and that also means we have to do our own string concatenation.

A cleaner solution would be to start the timer in the autocommand (which makes the function stand on its own, to me):

autocmd BufHidden * call timer_start(100, {_ -> tools#DeleteBuffer(expand("<abuf>"))}

But I worry about the expand("<abuf>") not working inside the lambda at that point, and I don't have a workaround yet.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.