1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
|
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
|