I have the following in my vimrc to open pdfs externally with xpdf.

function! OpenPdfExternally()
  silent execute "!xpdf " . shellescape(expand("%:p")) . " &>/dev/null &"
  edit # 
  bdelete #
  syntax on
  " let @# = g:saved_altfile
  " autocmd BufReadPre *.pdf let g:saved_altfile = expand('#')
autocmd BufRead *.pdf call OpenPdfExternally()

It works pretty well, but I would like to keep the alternate file that was set before opening the pdf and returning to the edited file.

I have tried the commented code, saving the alternative file before the pdf is read and then restoring it after the edited file is returned to, but no luck.

How can I keep the alternative file in this case?

  • There's :keepalt that can probably help... Though it might be tricky to put it all together. Wanna give it a try? If you find a solution that works, please post it as an answer.
    – filbranden
    Commented Apr 25, 2020 at 11:04
  • Tried it but couldnt get it to work. The help for keepalt mentilns that it might not work in functions.
    – Andreas
    Commented Apr 25, 2020 at 12:30

1 Answer 1


This worked for me, but I'd say it's pretty hacky. I tested it somewhat, but it might be quite fragile.

function! OpenPdfExternally()
  let saved_curfile = bufnr('#')
  silent execute "!echo ".shellescape(expand("%:p"), 1)." >>~/xpdf.log"
  if bufexists(g:saved_altfile)
    execute "buf" g:saved_altfile
    bwipeout #
    execute "buf" saved_curfile
    execute "buf" saved_curfile
    bwipeout #
  syntax on
augroup openpdf
  au BufRead *.pdf call OpenPdfExternally()
  au BufEnter * let g:saved_altfile = bufnr('#')
augroup END

The problem saving the alternate file is that by the time we're processing events for the *.pdf file, that's too late, since by then % will be the buffer with the PDF and # will be our previous current buffer... Our previous alternate buffer is gone.

To work around that, I added a BufEnter event to always keep saving the last alternate buffer, so we can query it from our function triggered by the BufRead on *.pdf.

In order to restore the alternate file, we actually jump back to it first, then we cleanup the *.pdf buffer, then we jump to the buffer that's supposed to be the current buffer again. Since we just previously jumped to the alternate file, that file will once again be the alternate buffer.

I'm using bwipeout instead of bdelete. That makes a difference in case there's no alternate file, in which case bdelete will still leave the *.pdf file as the alternate file, even if that buffer is unlisted.

BTW, I'm tracking buffer numbers and not really filenames. I think it's generally easier that way.

While this worked to some extent, I still think it's pretty hacky and I can think of quite a few scenarios in which this might just start misbehaving.

I think it would be much better if you could avoid this being triggered by an :e document.pdf command and used a separate command for this purpose. Having said that, I don't really know your whole use case, so I can't tell why you need this particular sequence.

(I wonder whether a solution using BufReadCmd would be possible, since it allows you to hijack reading the *.pdf file, but I think at the time it's invoked it already created a buffer for the file too. So not sure whether it can solve this problem in a more elegant way, but maybe it's worth taking a closer look.)

  • 1
    I wonder whether a solution using BufReadCmd would be possible No, it saves us from actual reading file by Vim, but it doesn't help to preserve altbuf either. used a separate command for this purpose And here is the right point. :edit is not a proper tool here.
    – Matt
    Commented Apr 26, 2020 at 8:01

Your Answer

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

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