mirror of
https://github.com/vim/vim
synced 2025-05-02 14:27:44 +02:00
Signed-off-by: Maxim Kim <habamax@gmail.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
182 lines
5.5 KiB
VimL
182 lines
5.5 KiB
VimL
vim9script
|
|
|
|
# Maintainer: Maxim Kim <habamax@gmail.com>
|
|
# Last update: 2023-12-10
|
|
#
|
|
# Set of functions to format/beautify JSON data structures.
|
|
#
|
|
# Could be used to reformat a minified json in a buffer (put it into ~/.vim/ftplugin/json.vim):
|
|
# import autoload 'dist/json.vim'
|
|
# setl formatexpr=json.FormatExpr()
|
|
#
|
|
# Or to get a formatted string out of vim's dict/list/string:
|
|
# vim9script
|
|
# import autoload 'dist/json.vim'
|
|
# echo json.Format({
|
|
# "widget": { "debug": "on", "window": { "title": "Sample \"Konfabulator\" Widget",
|
|
# "name": "main_window", "width": 500, "height": 500
|
|
# },
|
|
# "image": { "src": "Images/Sun.png", "name": "sun1", "hOffset": 250,
|
|
# "vOffset": 250, "alignment": "center" },
|
|
# "text": { "data": "Click Here", "size": 36, "style": "bold", "name": "text1",
|
|
# "hOffset": 250, "vOffset": 100, "alignment": "center",
|
|
# "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;" } }
|
|
# })
|
|
#
|
|
# Should output:
|
|
# {
|
|
# "widget": {
|
|
# "debug": "on",
|
|
# "window": {
|
|
# "title": "Sample \"Konfabulator\" Widget",
|
|
# "name": "main_window",
|
|
# "width": 500,
|
|
# "height": 500
|
|
# },
|
|
# "image": {
|
|
# "src": "Images/Sun.png",
|
|
# "name": "sun1",
|
|
# "hOffset": 250,
|
|
# "vOffset": 250,
|
|
# "alignment": "center"
|
|
# },
|
|
# "text": {
|
|
# "data": "Click Here",
|
|
# "size": 36,
|
|
# "style": "bold",
|
|
# "name": "text1",
|
|
# "hOffset": 250,
|
|
# "vOffset": 100,
|
|
# "alignment": "center",
|
|
# "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
|
|
# }
|
|
# }
|
|
# }
|
|
#
|
|
# NOTE: order of `key: value` pairs is not kept.
|
|
#
|
|
# You can also use a JSON string instead of vim's dict/list to maintain order:
|
|
# echo json.Format('{"hello": 1, "world": 2}')
|
|
# {
|
|
# "hello": 1,
|
|
# "world": 2
|
|
# }
|
|
|
|
|
|
# To be able to reformat with `gq` add following to `~/.vim/ftplugin/json.vim`:
|
|
# import autoload 'dist/json.vim'
|
|
# setl formatexpr=json.FormatExpr()
|
|
export def FormatExpr(): number
|
|
FormatRange(v:lnum, v:lnum + v:count - 1)
|
|
return 0
|
|
enddef
|
|
|
|
|
|
# import autoload 'dist/json.vim'
|
|
# command -range=% JSONFormat json.FormatRange(<line1>, <line2>)
|
|
export def FormatRange(line1: number, line2: number)
|
|
var indent_base = matchstr(getline(line1), '^\s*')
|
|
var indent = &expandtab ? repeat(' ', &shiftwidth) : "\t"
|
|
|
|
var [l1, l2] = line1 > line2 ? [line2, line1] : [line1, line2]
|
|
|
|
var json_src = getline(l1, l2)->join()
|
|
var json_fmt = Format(json_src, {use_tabs: !&et, indent: &sw, indent_base: indent_base})->split("\n")
|
|
|
|
exe $":{l1},{l2}d"
|
|
|
|
if line('$') == 1 && getline(1) == ''
|
|
setline(l1, json_fmt[0])
|
|
append(l1, json_fmt[1 : ])
|
|
else
|
|
append(l1 - 1, json_fmt)
|
|
endif
|
|
enddef
|
|
|
|
|
|
# Format JSON string or dict/list as JSON
|
|
# import autoload 'dist/json.vim'
|
|
# echo json.Format('{"hello": "world"}', {use_tabs: false, indent: 2, indent_base: 0})
|
|
|
|
# {
|
|
# "hello": "world"
|
|
# }
|
|
|
|
# echo json.Format({'hello': 'world'}, {use_tabs: false, indent: 2, indent_base: 0})
|
|
# {
|
|
# "hello": "world"
|
|
# }
|
|
#
|
|
# Note, when `obj` is dict, order of the `key: value` pairs might be different:
|
|
# echo json.Format({'hello': 1, 'world': 2})
|
|
# {
|
|
# "world": 2,
|
|
# "hello": 1
|
|
# }
|
|
export def Format(obj: any, params: dict<any> = {}): string
|
|
var obj_str = ''
|
|
if type(obj) == v:t_string
|
|
obj_str = obj
|
|
else
|
|
obj_str = json_encode(obj)
|
|
endif
|
|
|
|
var indent_lvl = 0
|
|
var indent_base = get(params, "indent_base", "")
|
|
var indent = get(params, "use_tabs", false) ? "\t" : repeat(' ', get(params, "indent", 2))
|
|
var json_line = indent_base
|
|
var json = ""
|
|
var state = ""
|
|
for char in obj_str
|
|
if state == ""
|
|
if char =~ '[{\[]'
|
|
json_line ..= char
|
|
json ..= json_line .. "\n"
|
|
indent_lvl += 1
|
|
json_line = indent_base .. repeat(indent, indent_lvl)
|
|
elseif char =~ '[}\]]'
|
|
if json_line !~ '^\s*$'
|
|
json ..= json_line .. "\n"
|
|
indent_lvl -= 1
|
|
if indent_lvl < 0
|
|
json_line = strpart(indent_base, -indent_lvl * len(indent))
|
|
else
|
|
json_line = indent_base .. repeat(indent, indent_lvl)
|
|
endif
|
|
elseif json =~ '[{\[]\n$'
|
|
json = json[ : -2]
|
|
json_line = substitute(json_line, '^\s*', '', '')
|
|
indent_lvl -= 1
|
|
endif
|
|
json_line ..= char
|
|
elseif char == ':'
|
|
json_line ..= char .. ' '
|
|
elseif char == '"'
|
|
json_line ..= char
|
|
state = 'QUOTE'
|
|
elseif char == ','
|
|
json_line ..= char
|
|
json ..= json_line .. "\n"
|
|
json_line = indent_base .. repeat(indent, indent_lvl)
|
|
elseif char !~ '\s'
|
|
json_line ..= char
|
|
endif
|
|
elseif state == "QUOTE"
|
|
json_line ..= char
|
|
if char == '\'
|
|
state = "ESCAPE"
|
|
elseif char == '"'
|
|
state = ""
|
|
endif
|
|
elseif state == "ESCAPE"
|
|
state = "QUOTE"
|
|
json_line ..= char
|
|
else
|
|
json_line ..= char
|
|
endif
|
|
endfor
|
|
if json_line !~ '^\s*$'
|
|
json ..= json_line .. "\n"
|
|
endif
|
|
return json
|
|
enddef
|