| 
									
										
										
										
											2023-12-11 01:57:41 +11:00
										 |  |  | 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' | 
					
						
							| 
									
										
										
										
											2023-12-12 03:09:38 +11:00
										 |  |  | # echo json.Format('{"hello": "world"}', {use_tabs: false, indent: 2, indent_base: 0}) | 
					
						
							| 
									
										
										
										
											2023-12-11 01:57:41 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  | # { | 
					
						
							|  |  |  | #   "hello": "world" | 
					
						
							|  |  |  | # } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-12 03:09:38 +11:00
										 |  |  | # echo json.Format({'hello': 'world'}, {use_tabs: false, indent: 2, indent_base: 0}) | 
					
						
							| 
									
										
										
										
											2023-12-11 01:57:41 +11:00
										 |  |  | # { | 
					
						
							|  |  |  | #   "hello": "world" | 
					
						
							|  |  |  | # } | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Note, when `obj` is dict, order of the `key: value` pairs might be different: | 
					
						
							| 
									
										
										
										
											2023-12-12 03:09:38 +11:00
										 |  |  | # echo json.Format({'hello': 1, 'world': 2}) | 
					
						
							| 
									
										
										
										
											2023-12-11 01:57:41 +11:00
										 |  |  | # { | 
					
						
							|  |  |  | #   "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 |