Fast image preview for Neovim with a launcher-first approach.
ViewIm is designed for people who want practical image preview workflows without running a full inline image rendering engine inside Neovim.
ViewImis launcher-first: resolve source -> validate -> open via terminal/native runner.- It keeps dependencies and operational complexity low.
- It focuses on explorer and cursor workflows, not full document-wide inline rendering.
- You use
nvim-tree,oil, orneo-treeand want quick preview. - You want markdown/html image preview at cursor with a simple command/keymap.
- You want remote URL previews with guardrails.
- You prefer low dependency footprint and straightforward debugging.
- Explorer integrations (
nvim-tree,oil,neo-tree) + buffer fallback. :ViewImageAtCursorfor markdown/html image sources:![alt][id]with[id]: ...<img src="...">single-line and multi-line
- Nearest-source fallback near cursor (bounded local scan).
- Remote previews via
curl(timeout,max_bytes,cache_dir,require_https). - Runtime controls: enable/disable/toggle/status.
- Optional explorer auto-preview and markdown auto-preview (both off by default).
- Placement controls (
weztermsplit options, ghostty tmux split options). - Experimental internal render mode for kitty with safe fallback.
- Security-focused boundaries (control-char path rejection, URL scheme restrictions).
- Neovim >= 0.9
- One terminal backend:
- kitty
- wezterm
- ghostty
- Optional:
curlfor remote URL previewstmuxforghostty.mode = "tmux"
{
"kogungor/viewim",
opts = {
keymap = "<leader>p",
cursor_keymap = "<leader>wi",
},
}Or keep explicit config = function() require("viewim").setup({...}) end if you prefer.
require("viewim").setup({
quiet_warnings = false,
keymap = "<leader>p", -- explorer preview
cursor_keymap = "<leader>wi", -- markdown/html at-cursor preview
preview_placement = {
direction = "bottom", -- right|left|top|bottom (global preference)
},
kitty = {
listen_on = "unix:/tmp/kitty-viewim.sock",
launch_type = "window", -- os-window | tab | window
},
markdown_auto_preview = {
enabled = false,
debounce_ms = 220,
},
remote = {
enabled = true,
timeout_ms = 10000,
max_bytes = 10485760,
cache_dir = vim.fn.stdpath("cache") .. "/viewim/remote",
require_https = false,
},
search = {
enabled = true,
preferred_picker = "auto", -- auto|telescope|snacks|builtin
max_results = 500,
include_hidden = false,
selection_preview = true,
selection_preview_debounce_ms = 120,
space_action = "large_preview", -- large_preview|preview
},
})preview_placement.directionis a shared preference; backend adapters apply it progressively.- For kitty, deterministic pane direction is limited by kitty launch behavior.
:ViewImage-> preview from context or explicit path/URL:ViewImage /path/to/file.png:ViewImage https://example.com/image.png:ViewImageAtCursor-> preview markdown/html image source under cursor:SearchImage [query]-> search project images and preview selected result:ViewImageEnable,:ViewImageDisable,:ViewImageToggle,:ViewImageStatus:checkhealth viewim
If you use kitty remote launch, set in kitty.conf:
allow_remote_control yes
listen_on unix:/tmp/kitty-viewim.sock
Then mirror in viewim:
require("viewim").setup({
kitty = {
listen_on = "unix:/tmp/kitty-viewim.sock",
launch_type = "window", -- os-window | tab | window
},
})- Vim help:
:help viewim(after helptags are generated by your plugin manager) - Vimdoc file:
doc/viewim.txt
For full option reference, troubleshooting, architecture, and all edge-case notes, use vimdoc.
Search picker backend is selected by search.preferred_picker with fallback order.
Search actions:
- selection change preview (backend-dependent, enabled by
search.selection_preview) <Space>action inside picker triggerssearch.space_action:SearchImagereports selected picker backend (for exampletelescope,snacks,builtin)
Backend behavior (current MVP):
telescope: supports selection-change preview and<Space>action.snacks: opens picker and selection confirm preview.builtin(vim.ui.select): selection confirm preview.
MIT