Describe the issue

I use a vim plugin that when use Vim to open a ipynb (python notebook) file, will call system function to use jupytext create corresponding python file to enable use like, YCM to help coding. This plugin set a autocmd BufUnload for the python file buffer to delete the python file when I quit Vim .

The bug is if the current buffer in current window is not the python file when quit Vim, the python file still there after quit Vim.

To Reproduce

I turn the plugin to a minimal version just vimscript.

  1. Copy file test_unload.vim to ~/.vim/plugin (content of test_unload.vim will post below) .
  2. touch tt.ipynb && vim tt.ipynb
  3. :e tt.c
  4. :q

After above steps, their should no tt.py file on disk, but have on tt.py.

Contents of test_unload.vim

if exists("loaded_test")

function! s:read_from_ipynb()  "{{{
  if expand("<afile>:e") != "ipynb"
    echo "Not an ipynb file."
  let l:filename = expand("%:p")
  let l:py_file = fnamemodify(l:filename, ":r") . ".py"
  " create python file
  call system('sleep 1;echo 123 > ' . l:py_file)
  " open the py file, wipe the ipynb file
  let l:bufnr = bufnr("%")
  execute "edit " . l:py_file
  execute "bwipeout" . l:bufnr
  set filetype=python
  execute "autocmd ipynb BufUnload <buffer> call s:cleanup()"
  let b:ipynb_file = l:filename
endfunction  "}}}

function! s:cleanup()  "{{{
  if !exists("b:ipynb_file")
    echo "Not a ipynb py file."
  call delete(expand("<afile>:p"))
endfunction  "}}}

augroup ipynb
  autocmd BufReadPost *.ipynb call s:read_from_ipynb()
augroup END

let loaded_test = 1

What's in vimrc:

hmanx ~ » cat .vimrc            
set hidden
hmanx ~ »

Expected behavior

tt.py deleted by autocmd BufUnload when quit Vim.


  • Vim version: 8.2.1989-2
  • OS: Manjaro Linux
  • Terminal: Konsole

Additional context

I found the autocmd BufUnload did triggered when quit Vim, but it returned before delete tt.py as the condition !exists("b:ipynb_file") is true.

Thanks in advance!


As you can see in :help BufUnload:

NOTE: When this autocommand is executed, the current buffer % may be different from the buffer being unloaded <afile>.

So you should use getbufvar() to access the contents of that variable for the buffer being unloaded.

if getbufvar(+expand("<abuf>"), "ipynb_file") != ""

(Using expand("<afile>") instead of +expand("<abuf>") also works.)

This depends on the variable having contents that are different from an empty string, so it's not exactly equivalent to an exists() check. If you want to check for the variable existing exactly, then pass a sentinel value (such as v:none) as the third optional argument to getbufvar() and check for it.

if getbufvar(+expand("<abuf>"), "ipynb_file", v:none) != v:none
  • You probably want to replace "<abuf>" with +expand('<abuf>'). You need expand() for Vim to expand the special characters <abuf> into a string containing a buffer number, and you need + to cast the string into a number; this matters because getbufvar() parses its first argument just like bufname(), and the latter handles a string like a pattern, which is here undesirable. – user938271 Dec 10 '20 at 19:51
  • @user938271 Hmmm, that's odd, because I tested that (in the exact situation described above) and it seemed to work correctly for me. – filbranden Dec 10 '20 at 20:08
  • 1
    After running this shell command, the output of :mess is empty. Which means that when BufUnload was fired by :bd 2, :echom was not run, and the getbufvar() condition unexpectedly failed. OTOH, after running this other shell command, the output of :mess contains test. Which means that when BufUnload was fired by :bd 2, :echom was run, and the getbufvar() condition succeeded. The only difference between the 2 commands is +expand(). – user938271 Dec 10 '20 at 20:33
  • Thanks @user938271, I'll definitely take a closer look! I want to set this scenario up again, to see why it seemed to work for me first time I tested it... Your feedback is much appreciated! – filbranden Dec 10 '20 at 21:34
  • 1
    Thanks a lot for all your discussions and @filbranden 's great answer! – roachsinai Dec 12 '20 at 7:39

The current buffer and file is behind <afile>, not %

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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