How to auto format JSON on save in Vim

JsonVimFormatLint

Json Problem Overview


To be honest go has spoiled me. With go I got used to having a strict formatting standard that is being enforced by my editor (vim) and is almost accepted and followed by everybody else on the team and around the world.

I wanted to format JSON files on save the same way.

Question: How to auto format/indent/lint json files on save in vim.

Json Solutions


Solution 1 - Json

In one command, try this:

execute '%!python -m json.tool' | w  

You could then add you own key binding to make it a simpler keystroke. Of course, for this to work, you need to have Python installed on your machine.

Solution 2 - Json

If you are keen on using external tool and you are doing some work with json, I would suggest using the jq:

https://stedolan.github.io/jq/

Then, you can execute :%!jq . inside vim which will replace the current buffer with the output of jq.

Solution 3 - Json

%!python -m json.tool

or

%!python -c "import json, sys, collections; print json.dumps(json.load(sys.stdin, object_pairs_hook=collections.OrderedDict), ensure_ascii=False, indent=4)"

you can add this to your vimrc:

com! FormatJSON %!python -m json.tool

than you can use :FormatJson format json files

Solution 4 - Json

Thanks mMontu and Jose B, this is what I ended up doing:

WARNING this will overwrite your buffer. So if you OPEN a json file that already has a syntax error, you will lose your whole file (or can lose it).

Add this line to your ~/.vimrc

" Ali: to indent json files on save
autocmd FileType json autocmd BufWritePre <buffer> %!python -m json.tool

you need to have python on your machine, of course.

EDIT: this next one should not overwrite your buffer if your json has error. Which makes it the correct answer, but since I don't have a good grasp of Vim script or shell for that matter, I present it as an experimental thing that you can try if you are feeling lucky. It may depend on your shell too. You are warned.

" Ali: to indent json files on save
autocmd FileType json autocmd BufWritePre <buffer> %!python -m json.tool 2>/dev/null || echo <buffer>

Solution 5 - Json

A search for JSON plugins on vim.org returned this:

jdaddy.vim : JSON manipulation and pretty printing

It has the following on description:

> gqaj "pretty prints" (wraps/indents/sorts keys/otherwise cleans up) > the JSON construct under the cursor.

If it does the formatting you are expecting then you could create an autocmd BufWritePre to format when saving.

Solution 6 - Json

Here is my solution. It doesn't exactly address the question part of "on save" but if you perform this action before save it will output errors you can then fix before save.

Also, it depends on only one external tool -- jq -- which has become the gold standard of unix shell JSON processing tools. And which you probably already have installed (macOS and Linux/Unix only; idk how this would behave in Windows)

Basically, it's just:

ggVG!jq '.'

That will highlight the entire JSON document then run it through jq which will just parse it for correctness, reformat it (e.g. fix any indents, etc), and spit the output back into the Vim editor.

If you want to parse only part of the document, you can highlight that part manually by pressing v or V and then run

!jq '.'

The benefit here is that you can fix subsections of your document this way.

Solution 7 - Json

Vim Autoformat

https://github.com/Chiel92/vim-autoformat

There is this Vim plugin which supports multiple auto format and indent schemes as well as extending with custom formatters per filetype.

https://github.com/Chiel92/vim-autoformat#default-formatprograms

Note:

You will need to have nodejs and js-beautify installed as vim-autoformat uses these as the default external tool.

npm install -g js-beautify

Solution 8 - Json

Another solution is to use coc-format-json.

Solution 9 - Json

I did some organizing (though some of it had nothing to do with vim) and to write the script by yourself on the neovim!

solution1: neovim

1-1: write the script by yourself

Neovim allows Python3 plugins to be defined by placing python files or packages in rplugin/python3/ in a runtimepath folder)

in my case

- init.vim
- rplugin/python3/[your_py_file_set].py
- rplugin/python3/fmt_file.py

The fmt_file.py as following

# rplugin/python3/fmt_file.py

import pynvim
import json


@pynvim.plugin
class Plugin:
    __slots__ = ('vim',)

    def __init__(self, vim):
        self.vim = vim

    @pynvim.command('FormatJson', nargs='*', range='')
    def format_json(self, args, rg):
        """
        USAGE::

            :FormatJson
        """
        try:
            buf = self.vim.current.buffer
            json_content: str = '\n'.join(buf[:])
            dict_content: dict = json.loads(json_content)
            new_content: str = json.dumps(dict_content, indent=4, sort_keys=True)
            buf[:] = new_content.split('\n')
        except Exception as e:
            self.vim.current.line = str(e)

afterwards run: :UpdateRemotePlugins from within Nvim once, to generate the necessary Vimscript to make your Plugin available. (and you best restart the neovim)

and then, you open the JSON file that one you want to format and typing: :FormatJson in the command. all done.


don't forget to tell vim where is your python

" init.vim

let g:python3_host_prog = '...\python.exe''

and pip install pynvim

1-2: use tool.py

where tool.py is located on the Lib/json/tool.py

:%!python -m json.tool

solution2: command line

If you already install the python, and you can open the command line:

python -m json.tool "test.json" >> "output.json"

solution3: python

I write a simple script for those things.

"""
USAGE::

    python fmt_file.py fmt-json "C:\test\test.json"
    python fmt_file.py fmt-json "C:\test\test.json"  --out_path="abc.json"
    python fmt_file.py fmt-json "test.json"  --out_path="abc.json"
"""

import click  # pip install click
from click.types import File
import json
from pathlib import Path


@click.group('json')
def gj():
    ...


@gj.command('fmt-json')
@click.argument('file_obj', type=click.File('r', encoding='utf-8'))
@click.option('--out_path', default=None, type=Path, help='output path')
def format_json(file_obj: File, out_path: Path):
    new_content = ''
    with file_obj as f:
        buf_list = [_ for _ in f]
        if buf_list:
            json_content: str = '\n'.join(buf_list)
            dict_content: dict = json.loads(json_content)
            new_content: str = json.dumps(dict_content, indent=4, sort_keys=True)

    if new_content:
        with open(out_path if out_path else Path('./temp.temp_temp.json'),
                  'w', encoding='utf-8') as f:
            f.write(new_content)


def main():
    for register_group in (gj,):
        register_group()


if __name__ == '__main__':
    main()

Solution 10 - Json

you can search for 'vim-json-line-format' plugin, Open a file in Normal mode, move your cursor on the json line, use <leader>pj to show formated json by print it, use <leader>wj could change the text to formatted json. Invalid json can not format!

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAliView Question on Stackoverflow
Solution 1 - JsonJose BView Answer on Stackoverflow
Solution 2 - JsonKyrView Answer on Stackoverflow
Solution 3 - JsonPegasusView Answer on Stackoverflow
Solution 4 - JsonAliView Answer on Stackoverflow
Solution 5 - JsonmMontuView Answer on Stackoverflow
Solution 6 - JsonJDSView Answer on Stackoverflow
Solution 7 - JsonJosh PeakView Answer on Stackoverflow
Solution 8 - JsonthoulihaView Answer on Stackoverflow
Solution 9 - JsonCarsonView Answer on Stackoverflow
Solution 10 - JsonzzuseView Answer on Stackoverflow