146

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?

1

10 Answers 10

219

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 .
11
  • 1
    :%!jq works just as well for me. Dec 27, 2019 at 22:38
  • 5
    Hm... only works with the added . for me. I wonder why. Apr 15, 2020 at 23:02
  • 1
    on MacOS, I need the . as well
    – Thomas
    Jun 14, 2020 at 18:53
  • 3
    On MacOS after installing jq with brew install jq I could also just type :%!jq without a dot at the end
    – olik79
    Apr 20, 2021 at 19:01
  • 2
    @Alexandre % stands for a range equal to 1,$ (the entire file) and ! filters the range of line to the external program jq.
    – SebMa
    Apr 11 at 21:11
91

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

:%!python -m json.tool

6
  • 1
    Do you memorize that and type it every time or do you use some kind of alias?
    – asedsami
    Dec 13, 2019 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, 2019 at 7: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. Feb 5, 2020 at 3:01
  • 4
    Python 3.9 has introduced the option --no-ensure-ascii.
    – Hotschke
    May 27, 2021 at 6:55
  • 1
    Useful if you are on a cloud environment and don't have permissions to install jq
    – Anurag A S
    Jul 20, 2022 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()
2
  • 1
    Welcome to Vi and Vim! Nice first answer; it's interesting that you consider the sorting aspect!
    – D. Ben Knoble
    Nov 19, 2019 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, 2019 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)))"'
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>
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.

0

Another solution is to use coc-format-json.

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
1
  • 3
    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 May 3, 2021 at 7: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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.