← Back to posts

How to Make a Code Snapshot Plugin in Neovim

Back in the dark days when I used VS Code ;) I loved the CodeSnap extension. It was a super simple plugin that could take your highlighted code and quickly turn it into a nice looking image. Moving to Neovim, I missed this feature. Then I saw the Charm.sh folks created a super cool new CLI tool called Freeze

So instead of continuing to feeling sad about missing CodeSnap, I thought I could throw together a few lines of Lua and make my own. Hopefully seeing how simple it is to do something like this can give you your own inspiration to make your own little extensions for Neovim.

-- I always like to prefix my commands with JR so I can easily find them
vim.api.nvim_create_user_command("JRFreeze", function()
	-- snag the file type from the buffer
	local file_type = vim.bo.filetype

	-- get the text from the visual selection as a table
	local text = vim.fn.getline(vim.fn.getpos("'<")[2], vim.fn.getpos("'>")[2])

	-- join it together into one string
	local full_text = table.concat(text, "\n")

	-- write the file to /tmp/freeze...probably could find a better place to put this so it's
	-- cross platform, but it works for me ¯\_(ツ)_/¯
	local file = io.open("/tmp/freeze", "w")
	if file == nil then
		print("could not open file")
		return
	end
	file:write(full_text)
	file:close()

	-- call the freeze command with the file type we grabbed earlier
	vim.fn.system("freeze /tmp/freeze -l" .. file_type .. " -o /tmp/freeze.png")

	--  This is the tricky bit. Use apple script to copy the image to the clipboard
	vim.fn.system("osascript -e 'set the clipboard to (read (POSIX file \"/tmp/freeze.png\") as TIFF picture)'")

	-- notify the user that the image has been copied to the clipboard
	vim.notify("Image copied to clipboard", vim.log.levels.INFO)
end, {
	-- make sure the command is only available in visual mode
	range = true,
})