jq is a very powerful command-line tool designed to manipulate JSON data. One of its great features is that it automatically formats JSON output for better readability:

$ echo '{"is_jq_awesome": true}' | jq
{
  "is_jq_awesome": true
}

But in Vim?

Can we utilize this inside of Vim? Of course!

In Vim, there’s a feature called filter commands that enables us to use external applications to modify our buffers. Filter commands take a range, which is a set of contiguous lines, and a command that processes these lines. This feature is exactly what we need for our purpose.

Whole buffer

:%!jq

Here we pass the whole buffer range (%) to jq:

Selected range

It even works with visual selection!

:'<,'>!jq

Here we pass instead pass the range of the visual selection ('<,'>) to jq:

Minified JSON

You can also pass --compact-output to get a minified JSON structure back:

:%!jq --compact-output

Mappings

Let’s add some mappings. I use the abbreviations fj for “format JSON” and fcj for “format compact JSON”, but feel free to choose any abbreviations that works best for you.

Vim

" Whole buffer
nnoremap <silent> <Leader>fj <Cmd>%!jq<CR>
nnoremap <silent> <Leader>fcj <Cmd>%!jq --compact-output<CR>

" Visual selection
vnoremap <silent> <Leader>fj :'<,'>!jq<CR>
vnoremap <silent> <Leader>fcj :'<,'>!jq --compact-output<CR>

Neovim using Lua

local opts = { noremap = true, silent = true }

-- Whole buffer
vim.keymap.set("n", "<Leader>fj", "<Cmd>%!jq<CR>", opts)
vim.keymap.set("n", "<Leader>fcj", "<Cmd>%!jq --compact-output<CR>", opts)

-- Visual selection
vim.keymap.set("v", "<Leader>fj", ":'<,'>!jq<CR>", opts)
vim.keymap.set("v", "<Leader>fcj", ":'<,'>!jq --compact-output<CR>", opts)

Resources

  • Vim help docs: :h range, :h filter
  • jq

Hacker News Discuss on Hacker News