How to Make Neovim Open PDF and Images External Viewers

Configuring neovim with Lua.

After some serious attempts to equip my terminal emulator with the ability rendering images, I’ve given up on it. My experience is that in 2024, it’s still not quite a practical endeavor, at least on my machine with all the CLI tools that I’m using, specifically tmux and neovim. There are a handful of image protocols out there made for this purpose, but each comes with enough caveats, or limitations on what terminal/multiplexer/scrolling capabilities that it can work with.

Still, there is the need to display images and PDFs while I’m working, and using neovim as my main editor, I find it tedious to have to open a preview of a file in another pane by typing out its full path, when there is a perfectly functional fuzzy search capability right there in the editor. It’s also annoying when I accidentally select a binary file and neovim shows me gibberish.

As a workaround, I set up some auto-commands that trigger external previewers for these files:

-- Open binary files
vim.api.nvim_create_autocmd("BufReadCmd", {
  pattern = "*.pdf",
  callback = function()
    local filename = vim.fn.shellescape(vim.api.nvim_buf_get_name(0))
    vim.cmd("silent !mupdf " .. filename .. " &")
    vim.cmd("let tobedeleted = bufnr('%') | b# | exe \"bd! \" . tobedeleted")
  end
})

vim.api.nvim_create_autocmd("BufReadCmd", {
  pattern = { "*.png", "*.jpg", "*.jpeg", "*.gif", "*.webp" },
  callback = function()
    local filename = vim.fn.shellescape(vim.api.nvim_buf_get_name(0))
    vim.cmd("silent !eyestalk " .. filename .. " &")
    vim.cmd("let tobedeleted = bufnr('%') | b# | exe \"bd! \" . tobedeleted")
  end
})

The snippet is predominantly based on this Stack Exchange post.

Some explanations ##

Further work ##

The next step is to find or make a fast, general purpose file viewer, so I can open all binary files—or any file that’s not suitable for text-based editing—in the same app. At the moment, mupdf is the fastest simple PDF viewer I’ve found, at least the fastest among the packages in my system repo.