158

Given a file with a large JSON object all on one line like

{"versions":[{"count":2,"version":""},{"count":1,"version":"1.1.1"},{"count":14,"version":"2.9"},{...

How can I format this to be human readable in Vim?

Andy A.
  • 233
  • 1
  • 2
  • 11
ljs.dev
  • 2,677
  • 2
  • 11
  • 10

10 Answers10

239

Or you can install jq which is faster (written in C) from your package manager (e.g. sudo apt install jq in Ubuntu/Debian, sudo dnf install jq on Fedora/RHEL/CentOS) or from source and then in vim, type:

:%!jq .
filbranden
  • 28,785
  • 3
  • 26
  • 71
SebMa
  • 2,968
  • 2
  • 12
  • 15
96

This one-liner works well to format JSON in Vim into a human readable form:

:%!python -m json.tool

ljs.dev
  • 2,677
  • 2
  • 11
  • 10
  • 1
    Do you memorize that and type it every time or do you use some kind of alias? – asedsami Dec 13 '19 at 17:05
  • I tend to use the :%!jq . answer these days, as I do less with Python and tend to have jq installed on my systems for any JSON work in CLI. I also get notifications for this SO question quite often, so it helps me not to forget :P I prefer vim with minimal customization, no plugins, etc, which is another reason the jq solution is now my preferred. – ljs.dev Dec 14 '19 at 07:37
  • (updated accepted answer to reflect this) – ljs.dev Dec 14 '19 at 07:37
  • 8
    Just a warning that this will escape some characters into ASCII only. So if you want UTF8 encoding jq is the better option. – AndrewHarvey Feb 05 '20 at 03:01
  • 4
    Python 3.9 has introduced the option --no-ensure-ascii. – Hotschke May 27 '21 at 06:55
  • 1
    Useful if you are on a cloud environment and don't have permissions to install jq – Anurag A S Jul 20 '22 at 15:11
11

To format in a deterministic way, we need to sort the hash. None of the other answers did that for me, so I created my own:

function! FormatJson()
python << EOF
import vim
import json
try:
    buf = vim.current.buffer
    json_content = '\n'.join(buf[:])
    content = json.loads(json_content)
    sorted_content = json.dumps(content, indent=4, sort_keys=True)
    buf[:] = sorted_content.split('\n')
except Exception, e:
    print e
EOF
endfunction

Usage:

:call FormatJson()
D. Ben Knoble
  • 26,070
  • 3
  • 29
  • 65
Prajit Patil
  • 111
  • 1
  • 2
  • 1
    Welcome to [vi.se]! Nice first answer; it's interesting that you consider the sorting aspect! – D. Ben Knoble Nov 19 '19 at 15:26
  • 2
    About the sorting I'm pretty sure jq mentionned in SebMa answers has a --sort-keys option which would do the job. But it's cool to write your own implementation too :) – statox Nov 19 '19 at 16:23
5

I use this :Jsonf command. It's can format unicode.

command! Jsonf :execute '%!python -c "import json,sys,collections,re; sys.stdout.write(re.sub(r\"\\\u[0-9a-f]{4}\", lambda m:m.group().decode(\"unicode_escape\").encode(\"utf-8\"),json.dumps(json.load(sys.stdin, object_pairs_hook=collections.OrderedDict), indent=2)))"'
han xi
  • 51
  • 1
  • 1
1

If PHP is available, add the tool jf as a JSON Formatter by Composer:

$ composer global require codegear/json-formatter

Then Format current file:

:%!jf %

Or add a keymap in vimrc:

nnoremap <Leader>jf :%!jf %<CR>
Lei Fan
  • 11
  • 1
0

If nodejs and xargs are available on your system you can add the following command to your .vimrc

command! -range FormatJson <line1>,<line2>!xargs -0 -I {} node -e 'console.log(JSON.stringify({}, null, 2));'

After that you can visual select the JSON text in the buffer and run

:'<,'>FormatJson

to pretty print it. Works with Unicode too.

ka3ak
  • 261
  • 2
  • 10
0

Another solution is to use coc-format-json.

dessalines
  • 101
  • 1
0

I wanted to open jq with vim. However i didn't manage to find a way to do it in one command.

I wrote a shell script, and it worked for me (linux version : redhat 7.6):

# Don't miss the dot after jq
cat input.json | jq . > output.json
vim output.json
statox
  • 49,782
  • 19
  • 148
  • 225
  • 4
    You can use - to read from stdin: jq input.json . | vim - (maybe you need to reverse the input.json and . in that jq command). Another option would be to use -c or + to run a command when Vim opens: vim +':%!jq .' input.json – Martin Tournoij May 03 '21 at 07:41
0

Use ALE to help you with linting/formatting

  1. Install ALE into .vim/vimfiles/pack/*/opt/ale

  2. add the following line to your vimrc:

packadd ale
  1. create .vim/vimfiles/after/ftplugin/json.vim
if exists("b:my_ftplugin") | finish | endif
let b:my_ftplugin = 1
if !exists('g:loaded_ale') | finish | endif
" Pick from available fixers :help ale-fix
" E.g., use prettier if it is installed:
let b:ale_fixers = ['prettier']

If no fixers are available at your disposal, python is always an option:

if !executable('python') | finish | endif
let b:ale_fixers = [{ -> {'command': 'python -m json.tool --indent 2 -'}}]
  1. Run the following command to reformat the current vim buffer:
:ALEFix
0

Only usable for one (or few) files.

Set all values at a new line with substitute commands (they must fit your file!):

  • :%s/","/",\r"/g
  • :%s/null,"/null,\r"/g
  • :%s/(\d),"/\1,\r"/g
  • ... (there are },{, [{
{
"versions":[
{
"count":2,"version":""
},
{"count":1,
"version":"1.1.1"
},
{
"count":14,
"version":"2.9"
}]
}

Then go to the first { and type =%.

The JSON will be rudimentary formatted. Not perfect but readable.

Andy A.
  • 233
  • 1
  • 2
  • 11