A Neovim plugin for displaying images inline in iTerm2 using the Inline Images Protocol.
- Display images directly in Neovim using iTerm2's inline image protocol
- Opens images in a dedicated tab for clean viewing
- Opens images in a floating popup with Snacks
- Automatic tab cleanup with
qor<Esc>key bindings - Popup sizing from PNG, GIF, JPEG, and WebP headers without external tools
- Works with local files and URLs (via curl)
- Debug logging support
- Neovim 0.5+
- iTerm2 (macOS) with inline image support
base64command-line utility (usually pre-installed)curl(for URL support)- ImageMagick
identifyormagick(optional fallback for image dimensions outside PNG, GIF, JPEG, and WebP)
Using lazy.nvim
For file browser popup hotness:
return {
'vito-c/nvim-icat',
file_browser = {
enabled = true,
key = '<CR>',
},
config = function()
require('nvim-icat').setup()
end,
}Using packer.nvim
use {
'vito-c/nvim-icat',
config = function()
require('nvim-icat').setup()
end
}Using vim-plug
Plug 'vito-c/nvim-icat'
lua << EOF
require('nvim-icat').setup()
EOFrequire('nvim-icat').setup()require('nvim-icat').setup({
-- Custom path to imgcat.lua if needed
imgcat_path = '/path/to/imgcat.lua',
-- Map <CR> in oil.nvim and netrw to open image files in a popup.
-- Non-image entries still open with the file browser's normal action.
file_browser = {
enabled = true,
key = '<CR>',
},
}):IcatShow <path>- Display an image from the specified path:IcatShowPop <path>- Display an image in a floating popup:IcatTty- Show TTY diagnostics for image rendering
bin/icat-popup opens an image popup in an already-running Neovim instance:
bin/icat-popup --server "$NVIM_LISTEN_ADDRESS" ./image.pngIf NVIM_LISTEN_ADDRESS is set in the environment, you can omit --server:
bin/icat-popup ./image.pngThe script sends a remote expression to Neovim and lets the running plugin handle TTY selection. It does not render the image from the shell process.
IcatShowPop sizes the popup from image metadata when possible. It first reads
small file headers directly in Lua for PNG, GIF, JPEG, and WebP, which works
without extra tools and is useful over SSH. If the header reader cannot determine
the dimensions, it falls back to sips, then ImageMagick's identify or
magick identify, and finally to an editor-size fallback.
By default, setup() maps <CR> in oil.nvim and netrw buffers. Pressing <CR> on an image file opens the image popup; pressing <CR> on a directory or non-image file keeps the browser's normal open behavior.
require('nvim-icat').setup({
file_browser = {
enabled = true,
key = '<CR>',
},
})To disable the file browser mapping:
require('nvim-icat').setup({
file_browser = {
enabled = false,
},
})-- Show an image
require('nvim-icat').show_image('/path/to/image.png')
-- Show an image with custom options
require('nvim-icat').show_image('/path/to/image.png', {
width = '80', -- Width in character cells
height = '40' -- Height in character cells
})q- Close the image viewer<Esc>- Close the image viewer
The image tab will also auto-close when you switch to another tab.
-- Display an image
:IcatShow ~/Pictures/photo.jpg
-- From Lua
:lua require('nvim-icat').show_image(vim.fn.expand('~/Pictures/photo.jpg'))This plugin uses iTerm2's proprietary inline images protocol to display images directly in the terminal. The imgcat.lua script handles the low-level communication with iTerm2, while the Neovim plugin (nvim-icat.lua) provides a user-friendly interface.
When you display an image:
- A new tab is created with image metadata
- The imgcat script encodes the image to base64
- The encoded image is sent to iTerm2 using escape sequences
- iTerm2 renders the image inline in the terminal
To enable debug logging, set the environment variable before starting Neovim:
export IMGCAT_DEBUG=1
nvimDebug logs will be written to:
debug.txt- imgcat script logsdebug-plugin.txt- plugin logs
All formats supported by iTerm2:
- PNG
- JPEG/JPG
- GIF
- BMP
- WebP
- And more
- Only works in iTerm2 on macOS
- Image display may not work in tmux (depending on configuration)
- Images are not persistent after closing Neovim
- Verify you're using iTerm2
- Check that inline images are enabled in iTerm2 preferences
- Run
:IcatTtyto check the render-time and startup TTY values - Enable debug logging to see what's happening
- Ensure the image file exists and is readable
- Install ImageMagick if popup notifications show
image: ? x ? cellsfor a format outside PNG, GIF, JPEG, and WebP
Make sure you've called setup() in your Neovim configuration:
require('nvim-icat').setup()Contributions are welcome! Please feel free to submit issues or pull requests.
MIT
Based on the iTerm2 imgcat script, reimplemented in Lua for Neovim integration.