summaryrefslogtreecommitdiffstats
path: root/runtime/autoload/dist/json.vim
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--runtime/autoload/dist/json.vim182
1 files changed, 182 insertions, 0 deletions
diff --git a/runtime/autoload/dist/json.vim b/runtime/autoload/dist/json.vim
new file mode 100644
index 0000000..9faa88a
--- /dev/null
+++ b/runtime/autoload/dist/json.vim
@@ -0,0 +1,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