[vim/vim] Add first class support for json format (Issue #11426)

50 views
Skip to first unread message

Prabir Shrestha

unread,
Oct 22, 2022, 6:09:40 PM10/22/22
to vim/vim, Subscribed

JSON is a common format that is used when coding backend apis. Would be good if vim had first class support for formatting JSON so that we don't have to use external tool or website.


Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/11426@github.com>

Gary Johnson

unread,
Oct 22, 2022, 6:25:00 PM10/22/22
to reply+ACY5DGG5MWBKZMIY5Q...@reply.github.com, vim...@googlegroups.com
On 2022-10-22, Prabir Shrestha wrote:
> JSON is a common format that is used when coding backend apis. Would be good if
> vim had first class support for formatting JSON so that we don't have to use
> external tool or website.

I don't use JSON a lot. What sort of formatting do you want that
the existing json.vim or jsonc.vim indent plugin doesn't provide?

Regards,
Gary

vim-dev ML

unread,
Oct 22, 2022, 6:25:20 PM10/22/22
to vim/vim, vim-dev ML, Your activity

On 2022-10-22, Prabir Shrestha wrote:
> JSON is a common format that is used when coding backend apis. Would be good if
> vim had first class support for formatting JSON so that we don't have to use
> external tool or website.

I don't use JSON a lot. What sort of formatting do you want that
the existing json.vim or jsonc.vim indent plugin doesn't provide?

Regards,
Gary


Reply to this email directly, view it on GitHub.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/11426/1287934119@github.com>

Prabir Shrestha

unread,
Oct 22, 2022, 10:09:08 PM10/22/22
to vim/vim, vim-dev ML, Comment

I have a json http response and need to format so I can inspect it. It could contain sensitive (customer) data and would like to avoid using random external tools to inspect it. Inspecting minified JSON is hard.

I'm looking for an equivalent for this :%!python -m json.tool by :JsonFormat and JSON.stringify() by json_format() but without me install python (it is pain to use in Windows).

In Javascript this is what one could do.

var obj = { 'name': 'prabir' };
JSON.stringify(obj, null, 4);    // Indented 4 spaces
JSON.stringify(obj, null, "\t"); // Indented with tab


Reply to this email directly, view it on GitHub.

You are receiving this because you commented.Message ID: <vim/vim/issues/11426/1287978465@github.com>

ben.k...@gmail.com

unread,
Oct 24, 2022, 4:34:18 PM10/24/22
to vim_dev
Perhaps you can install jq? Then `:%!jq .` should do it.

Christian Brabandt

unread,
Nov 3, 2022, 5:22:56 AM11/3/22
to vim/vim, vim-dev ML, Comment

can't you filter your buffer through e.g. jq ?


Reply to this email directly, view it on GitHub.

You are receiving this because you commented.Message ID: <vim/vim/issues/11426/1301829951@github.com>

Bram Moolenaar

unread,
Nov 4, 2022, 6:59:49 PM11/4/22
to vim/vim, vim-dev ML, Comment


> JSON is a common format that is used when coding backend apis. Would
> be good if vim had first class support for formatting JSON so that we
> don't have to use external tool or website.

Vim provides plugins for indenting, but formatting (splitting lines at
specific places) is mainly limited to text. Not only because formatting
is much more work, also because there are many more different ways
formatting can be done (illustrated by the many options we already have
just for plain text).

I'm not against including a few plugins for formatting, but I also don't
want to make a grand collection of language formatters. It's more
something users with specific interest would find the right formatter
when they need it. Json should be generic enough to justify including a
formatter for, perhaps there are one or two other generic languages.
But not much more.

Something like "jq" is a binary, that makes it less attractive to
include with Vim. Could include a plugin that has some mechanism to
find "jq" on a local machine or give hints on how to install it.
If someone wants to create that.

--
hundred-and-one symptoms of being an internet addict:
23. You can't call your mother... she doesn't have VOIP

/// Bram Moolenaar -- ***@***.*** -- http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///


Reply to this email directly, view it on GitHub.

You are receiving this because you commented.Message ID: <vim/vim/issues/11426/1304322845@github.com>

Maxim Kim

unread,
Nov 5, 2022, 8:53:01 AM11/5/22
to vim/vim, vim-dev ML, Comment

Here is proof of concept:

https://asciinema.org/a/OIpGQplEKpjF9xbaxNZB5Bayn

def JSONFormat(line1: number, line2: number)
    var json_src = getline(line1, line2)->join()
    var json = []
    var indent_lvl = 0
    var indent_base = matchstr(getline(line1), '^\s*')
    var indent = &expandtab ? repeat(' ', &shiftwidth) : "\t"
    var json_line = indent_base
    var state = ""
    for char in json_src
        if state == ""
            if char =~ '{\|\['
                json_line ..= char
                json->add(json_line)
                indent_lvl += 1
                json_line = indent_base .. repeat(indent, indent_lvl)
            elseif char =~ '}\|\]'
                json->add(json_line)
                indent_lvl -= 1
                json_line = indent_base .. repeat(indent, indent_lvl)
                json_line ..= char
            elseif char == ':'
                json_line ..= char .. ' '
            elseif char == '"'
                json_line ..= char
                state = 'ATTR'
            elseif char == ','
                json_line ..= char
                json->add(json_line)
                json_line = indent_base .. repeat(indent, indent_lvl)
            elseif char !~ '\s'
                json_line ..= char
            endif
        elseif state == "ATTR"
            json_line ..= char
            if char == '"'
                state = ""
            endif
        else
            json_line ..= char
        endif
    endfor
    if !empty(json_line)
        json->add(json_line)
    endif
    exe $":{line1},{line2}d"
    if line('$') == 1
        setline(line1, json[0])
        append(line1, json[1 : ])
    else
        append(line1 - 1, json)
    endif
enddef
command! -range=% JSONFormat JSONFormat(<line1>, <line2>)


Reply to this email directly, view it on GitHub.

You are receiving this because you commented.Message ID: <vim/vim/issues/11426/1304541265@github.com>

Maxim Kim

unread,
Nov 5, 2022, 9:15:12 AM11/5/22
to vim/vim, vim-dev ML, Comment

Hmm, I have tried to make it work with 'formatexpr' but failed :(

This is in after/json.vim

import autoload 'json.vim'
setl formatexpr=json.FormatExpr()

In autoload/json.vim I have

vim9script
export def FormatExpr()
    Format(v:lnum, v:lnum + v:count)
enddef

export def Format(line1: number, line2: number)
.... as in previous message

And it formats it into garbage.


Reply to this email directly, view it on GitHub.

You are receiving this because you commented.Message ID: <vim/vim/issues/11426/1304544992@github.com>

Maxim Kim

unread,
Nov 5, 2022, 9:24:56 AM11/5/22
to vim/vim, vim-dev ML, Comment

Oh, formatexpr can't speak vim9script!

setl formatexpr=json#FormatExpr()

Works!

@brammool I can create a PR if needed.


Reply to this email directly, view it on GitHub.

You are receiving this because you commented.Message ID: <vim/vim/issues/11426/1304546422@github.com>

Maxim Kim

unread,
Nov 5, 2022, 9:40:54 AM11/5/22
to vim/vim, vim-dev ML, Comment

This is the latest thing I have that works with gq in normal mode.
Unfortunately I couldn't make it work for a {visual}gq.

vim9script

# in after/json.vim
# setl formatexpr=json#FormatExpr()

export def FormatExpr(): number
    Format(v:lnum, v:lnum + v:count - 1)
    return 0
enddef


export def Format(line1: number, line2: number)
    var json_src = getline(line1, line2)->join()
    var json = []
    var indent_lvl = 0
    var indent_base = matchstr(getline(line1), '^\s*')
    var indent = &expandtab ? repeat(' ', &shiftwidth) : "\t"
    var json_line = indent_base
    var state = ""
    for char in json_src
        if state == ""
            if char =~ '{\|\['
                json_line ..= char
                json->add(json_line)
                indent_lvl += 1
                json_line = indent_base .. repeat(indent, indent_lvl)
            elseif char =~ '}\|\]'
                json->add(json_line)
                indent_lvl -= 1
                json_line = indent_base .. repeat(indent, indent_lvl)
                json_line ..= char
            elseif char == ':'
                json_line ..= char .. ' '
            elseif char == '"'
                json_line ..= char
                state = 'ATTR'
            elseif char == ','
                json_line ..= char
                json->add(json_line)
                json_line = indent_base .. repeat(indent, indent_lvl)
            elseif char !~ '\s'
                json_line ..= char
            endif
        elseif state == "ATTR"
            json_line ..= char
            if char == '"'
                state = ""
            endif
        else
            json_line ..= char
        endif
    endfor
    if json_line !~ '^\s*$'
        json->add(json_line)
    endif
    exe $":{line1},{line2}d"
    if line('$') == 1
        setline(line1, json[0])
        append(line1, json[1 : ])
    else
        append(line1 - 1, json)
    endif
enddef


Reply to this email directly, view it on GitHub.

You are receiving this because you commented.Message ID: <vim/vim/issues/11426/1304548854@github.com>

Bram Moolenaar

unread,
Nov 5, 2022, 11:35:19 AM11/5/22
to vim...@googlegroups.com, Maxim Kim

> Oh, `formatexpr` can't speak vim9script!
>
> ```
> setl formatexpr=json#FormatExpr()
> ```
>
> Works!
>
> @brammool I can create a PR if needed.

It would be good to review, have others make comments.
A PR should work for that.

I suppose including the script under autoload/dist works, then those who
want to use it can set 'formatexpr' as you mentioned, with a filetype
autocmd. If it works really well we could do it in the json filetype
plugin. I suppose we would somehow need to vote about that.

--
Anyone who is capable of getting themselves made President should on no
account be allowed to do the job.
-- Douglas Adams, "The Hitchhiker's Guide to the Galaxy"

/// Bram Moolenaar -- Br...@Moolenaar.net -- http://www.Moolenaar.net \\\

Maxim Kim

unread,
Nov 5, 2022, 12:49:54 PM11/5/22
to vim_dev
> It would be good to review, have others make comments.
> A PR should work for that.


Hopefully other people will try it and improve if needed.

* It doesn't handle escapes of \" and I don't know if json allows it actually
* {Visual}gq doesn't work and I am not sure how formatexpr should look like

суббота, 5 ноября 2022 г. в 20:35:19 UTC+5, Bram Moolenaar:

Maxim Kim

unread,
Nov 5, 2022, 1:00:29 PM11/5/22
to vim_dev
Ok, for visual mode I had to redefine `gq`

vim9script

import autoload 'dist/json.vim'
setl formatexpr=json.FormatExpr()
xnoremap <buffer> gq <scriptcmd>json.Format(line('v'), line('.'))<CR>



суббота, 5 ноября 2022 г. в 21:49:54 UTC+5, Maxim Kim:

Christian Brabandt

unread,
Dec 8, 2022, 4:39:06 PM12/8/22
to vim/vim, vim-dev ML, Comment

let me close this in favor of #11506


Reply to this email directly, view it on GitHub.

You are receiving this because you commented.Message ID: <vim/vim/issues/11426/1343403214@github.com>

Christian Brabandt

unread,
Dec 8, 2022, 4:39:07 PM12/8/22
to vim/vim, vim-dev ML, Comment

Closed #11426 as completed.


Reply to this email directly, view it on GitHub.

You are receiving this because you commented.Message ID: <vim/vim/issue/11426/issue_event/7993209406@github.com>

Reply all
Reply to author
Forward
0 new messages