Compare commits
34 Commits
Author | SHA1 | Date |
---|---|---|
|
6575bb8b94 | |
|
67e80064a9 | |
|
8434a7ad29 | |
![]() |
1eb32df515 | |
![]() |
1c3f4c5fd9 | |
![]() |
382534afc7 | |
![]() |
f7800eb48b | |
![]() |
37464164b3 | |
![]() |
eef27b88ab | |
![]() |
b65d96083b | |
![]() |
f844dfd85e | |
![]() |
e18eb18805 | |
![]() |
afa8b64f46 | |
![]() |
c93e8381bd | |
![]() |
cb1355a50d | |
![]() |
768519907e | |
![]() |
af5a6708d3 | |
![]() |
4bcdd31b6b | |
![]() |
02465c175e | |
![]() |
dd60a4fbef | |
![]() |
a6e18b1cff | |
![]() |
aaaa457475 | |
![]() |
e2cd83ef1a | |
![]() |
be7dad59f3 | |
![]() |
e17e458890 | |
![]() |
6c09f26b85 | |
![]() |
6516ce7070 | |
![]() |
34c27bcd80 | |
![]() |
d98ffee537 | |
![]() |
34dfb524ac | |
![]() |
adebca18e6 | |
![]() |
6cffc27ce5 | |
![]() |
8d86d63169 | |
![]() |
90251f52f6 |
|
@ -12,4 +12,4 @@
|
|||
// { "key": "selector", "operator": "equal", "operand": "source.json" }
|
||||
// ]
|
||||
// }
|
||||
]
|
||||
]
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
"caption": "Pretty JSON: Format JSON",
|
||||
"command": "pretty_json"
|
||||
},
|
||||
{
|
||||
"caption": "Pretty JSON: Format JSON Lines",
|
||||
"command": "pretty_json_lines"
|
||||
},
|
||||
{
|
||||
"caption": "Pretty JSON: Format and Sort JSON",
|
||||
"command": "pretty_json_and_sort"
|
||||
|
@ -24,12 +28,12 @@
|
|||
"command": "pretty_json_validate"
|
||||
},
|
||||
{
|
||||
"caption": "Preferences: Pretty JSON Settings",
|
||||
"command": "edit_settings",
|
||||
"args":
|
||||
{
|
||||
"base_file": "${packages}/Pretty JSON/Pretty JSON.sublime-settings",
|
||||
"default": "{\n\t$0\n}\n"
|
||||
}
|
||||
},
|
||||
"caption": "Preferences: Pretty JSON Settings",
|
||||
"command": "edit_settings"
|
||||
}
|
||||
]
|
|
@ -1,25 +1,29 @@
|
|||
[
|
||||
{
|
||||
"id": "preferences",
|
||||
"children": [
|
||||
{
|
||||
"id": "package-settings",
|
||||
"children": [
|
||||
{
|
||||
"caption": "Pretty JSON",
|
||||
"children": [
|
||||
{
|
||||
"caption": "Settings",
|
||||
"command": "edit_settings",
|
||||
"args":
|
||||
{
|
||||
"base_file": "${packages}/Pretty JSON/Pretty JSON.sublime-settings",
|
||||
"default": "{\n\t$0\n}\n",
|
||||
}
|
||||
},
|
||||
{
|
||||
"caption": "-"
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
"children": [
|
||||
{
|
||||
"caption": "Pretty JSON",
|
||||
"children": [
|
||||
{
|
||||
"args":
|
||||
{
|
||||
"base_file": "${packages}/Pretty JSON/Pretty JSON.sublime-settings",
|
||||
"default": "{\n\t$0\n}\n"
|
||||
},
|
||||
"caption": "Settings",
|
||||
"command": "edit_settings"
|
||||
},
|
||||
{
|
||||
"caption": "-"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"id": "package-settings"
|
||||
}
|
||||
],
|
||||
"id": "preferences"
|
||||
}
|
||||
]
|
|
@ -2,13 +2,15 @@
|
|||
"use_entire_file_if_no_selection": true,
|
||||
"indent": 4,
|
||||
"sort_keys": false,
|
||||
"ensure_ascii": true,
|
||||
"ensure_ascii": false,
|
||||
"abort_format_on_duplicate_key": {},
|
||||
"set_syntax_on_format": true,
|
||||
"line_separator": ",",
|
||||
"value_separator": ": ",
|
||||
"keep_arrays_single_line": false,
|
||||
"max_arrays_line_length": 120,
|
||||
"pretty_on_save": true,
|
||||
"validate_on_save": true,
|
||||
"pretty_on_save": false,
|
||||
"validate_on_save": false,
|
||||
"brace_newline": true,
|
||||
"bracket_newline": true,
|
||||
// Default: False
|
||||
|
@ -18,10 +20,10 @@
|
|||
// Example: /usr/bin/local/jq
|
||||
"jq_binary": "jq",
|
||||
"jq_errors": false,
|
||||
"as_json":[
|
||||
"as_json": [
|
||||
"Packages/JSON/JSON.sublime-syntax",
|
||||
"Packages/PackageDev/Package/Sublime Text Commands/Sublime Text Commands.sublime-syntax",
|
||||
"Packages/PackageDev/Package/Sublime Text Settings/Sublime Text Settings.sublime-syntax",
|
||||
"Packages/PackageDev/Package/Sublime Text Menu/Sublime Text Menu.sublime-syntax"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
409
PrettyJson.py
409
PrettyJson.py
|
@ -1,8 +1,10 @@
|
|||
import decimal
|
||||
import os
|
||||
import functools
|
||||
import re
|
||||
import subprocess
|
||||
import shutil
|
||||
import webbrowser
|
||||
from xml.etree import ElementTree as et
|
||||
|
||||
import sublime
|
||||
|
@ -15,39 +17,22 @@ from .lib.simplejson import OrderedDict
|
|||
PREVIOUS_CONTENT = [str(), str()]
|
||||
PREVIOUS_QUERY_LEN = int()
|
||||
|
||||
s = {}
|
||||
|
||||
xml_syntax = 'Packages/XML/XML.sublime-syntax'
|
||||
json_syntax = 'Packages/JSON/JSON.sublime-syntax'
|
||||
|
||||
jq_exists = bool()
|
||||
jq_init = bool()
|
||||
jq_path = str()
|
||||
xml_syntax = "Packages/XML/XML.sublime-syntax"
|
||||
json_syntax = "Packages/JSON/JSON.sublime-syntax"
|
||||
|
||||
|
||||
def check_jq():
|
||||
global jq_init, jq_exists, jq_path
|
||||
|
||||
if jq_init:
|
||||
return
|
||||
|
||||
jq_init = True
|
||||
jq_test = s.get('jq_binary', 'jq')
|
||||
try:
|
||||
jq_path = shutil.which(jq_test)
|
||||
jq_exists = True
|
||||
except OSError as ex:
|
||||
sublime.message_dialog(f'[Error]: {ex}')
|
||||
jq_exists = False
|
||||
def get_jq_path():
|
||||
settings = sublime.load_settings("Pretty JSON.sublime-settings")
|
||||
return shutil.which(settings.get("jq_binary", "jq"))
|
||||
|
||||
|
||||
class PrettyJsonBaseCommand:
|
||||
phantom_set = sublime.PhantomSet
|
||||
phantoms = list()
|
||||
force_sorting = False
|
||||
json_char_matcher = re.compile(r'char (\d+)')
|
||||
brace_newline = re.compile(r'^((\s*)".*?":)\s*([{])', re.MULTILINE)
|
||||
bracket_newline = re.compile(r'^((\s*)".*?":)\s*([\[])', re.MULTILINE)
|
||||
json_char_matcher = re.compile(r"char (\d+)")
|
||||
brace_newline = re.compile(r'^(^([ \t]*)(\"[^\"]*\"):)\s*([{])', re.MULTILINE)
|
||||
bracket_newline = re.compile(r'^(^([ \t]*)(\"[^\"]*\"):)\s*([\[])', re.MULTILINE)
|
||||
|
||||
@staticmethod
|
||||
def json_loads(selection: str, object_pairs_hook=OrderedDict):
|
||||
|
@ -56,21 +41,23 @@ class PrettyJsonBaseCommand:
|
|||
)
|
||||
|
||||
@staticmethod
|
||||
def json_dumps(obj, minified: bool = False) -> str:
|
||||
sort_keys = s.get('sort_keys', False)
|
||||
if PrettyJsonBaseCommand.force_sorting:
|
||||
def json_dumps(obj, minified: bool = False, force_sorting: bool = False) -> str:
|
||||
settings = sublime.load_settings("Pretty JSON.sublime-settings")
|
||||
|
||||
sort_keys = settings.get("sort_keys", False)
|
||||
if force_sorting:
|
||||
sort_keys = True
|
||||
|
||||
line_separator = s.get('line_separator', ',')
|
||||
value_separator = s.get('value_separator', ': ')
|
||||
line_separator = settings.get("line_separator", ",")
|
||||
value_separator = settings.get("value_separator", ": ")
|
||||
if minified:
|
||||
line_separator = line_separator.strip()
|
||||
value_separator = value_separator.strip()
|
||||
|
||||
output_json = json.dumps(
|
||||
obj,
|
||||
indent=None if minified else s.get('indent', 2),
|
||||
ensure_ascii=s.get('ensure_ascii', False),
|
||||
indent=None if minified else settings.get("indent", 2),
|
||||
ensure_ascii=settings.get("ensure_ascii", False),
|
||||
sort_keys=sort_keys,
|
||||
separators=(line_separator, value_separator),
|
||||
use_decimal=True,
|
||||
|
@ -78,23 +65,40 @@ class PrettyJsonBaseCommand:
|
|||
if minified:
|
||||
return output_json
|
||||
|
||||
if s.get('keep_arrays_single_line', False):
|
||||
matches = re.findall(r'(\[[^\[\]]+?\])', output_json)
|
||||
if settings.get("keep_arrays_single_line", False):
|
||||
matches = re.findall(r"(\[[^\[\]]+?\])", output_json)
|
||||
matches.sort(key=len, reverse=True)
|
||||
join_separator = line_separator.ljust(2)
|
||||
for m in matches:
|
||||
content = m[1:-1].strip()
|
||||
items = [a.strip() for a in content.split(os.linesep)]
|
||||
items = [item[:-1] if item[-1] == ',' else item for item in items]
|
||||
replacement = f'[{join_separator.join(items)}]'
|
||||
if len(replacement) <= s.get('max_arrays_line_length', 120):
|
||||
items = [item[:-1] if item[-1] == "," else item for item in items]
|
||||
replacement = "["
|
||||
for index, item in enumerate(items):
|
||||
if item in ('{', '}') or item.endswith("{") or item.startswith("}"):
|
||||
replacement = replacement + item
|
||||
if item == '}':
|
||||
if index != len(items)-1 and items[index+1] != "}":
|
||||
replacement = replacement + ','
|
||||
else:
|
||||
replacement = replacement + item
|
||||
if index != len(items)-1:
|
||||
if items[index+1] != '}':
|
||||
replacement = replacement + ','
|
||||
replacement = replacement + ']'
|
||||
|
||||
if len(replacement) <= settings.get("max_arrays_line_length", 120):
|
||||
output_json = output_json.replace(m, replacement, 1)
|
||||
|
||||
elif s.get('bracket_newline', True):
|
||||
output_json = PrettyJsonBaseCommand.bracket_newline.sub(r'\1\n\2\3', output_json)
|
||||
elif settings.get("bracket_newline", True):
|
||||
output_json = PrettyJsonBaseCommand.bracket_newline.sub(
|
||||
r"\1\n\2\4", output_json
|
||||
)
|
||||
|
||||
if s.get('brace_newline', True):
|
||||
output_json = PrettyJsonBaseCommand.brace_newline.sub(r'\1\n\2\3', output_json)
|
||||
if settings.get("brace_newline", True):
|
||||
output_json = PrettyJsonBaseCommand.brace_newline.sub(
|
||||
r"\1\n\2\4", output_json
|
||||
)
|
||||
|
||||
return output_json
|
||||
|
||||
|
@ -102,45 +106,48 @@ class PrettyJsonBaseCommand:
|
|||
def get_selection_from_region(
|
||||
region: sublime.Region, regions_length: int, view: sublime.View
|
||||
):
|
||||
settings = sublime.load_settings("Pretty JSON.sublime-settings")
|
||||
entire_file = False
|
||||
if region.empty() and regions_length > 1:
|
||||
return None, None
|
||||
elif region.empty() and s.get('use_entire_file_if_no_selection', True):
|
||||
elif region.empty() and settings.get("use_entire_file_if_no_selection", True):
|
||||
region = sublime.Region(0, view.size())
|
||||
entire_file = True
|
||||
|
||||
return region, entire_file
|
||||
|
||||
def reindent(self, text: str, selection: sublime.Region):
|
||||
settings = sublime.load_settings("Pretty JSON.sublime-settings")
|
||||
current_line = self.view.line(selection.begin())
|
||||
text_before_sel = sublime.Region(current_line.begin(), selection.begin())
|
||||
indent_space = ''
|
||||
indent_space = ""
|
||||
|
||||
reindent_mode = s.get('reindent_block', False)
|
||||
if reindent_mode == 'start':
|
||||
reindent_mode = settings.get("reindent_block", False)
|
||||
if reindent_mode == "start":
|
||||
space_number = text_before_sel.size()
|
||||
indent_space = ' ' * space_number
|
||||
elif reindent_mode == 'minimal':
|
||||
indent_space = re.search(r'^\s*', self.view.substr(text_before_sel)).group(0)
|
||||
indent_space = " " * space_number
|
||||
elif reindent_mode == "minimal":
|
||||
indent_space = re.search(r"^\s*", self.view.substr(text_before_sel)).group(
|
||||
0
|
||||
)
|
||||
|
||||
lines = text.split('\n')
|
||||
lines = text.split("\n")
|
||||
|
||||
i = 1
|
||||
while i < len(lines):
|
||||
lines[i] = f'{indent_space}{lines[i]}'
|
||||
lines[i] = f"{indent_space}{lines[i]}"
|
||||
i += 1
|
||||
|
||||
return '\n'.join(lines)
|
||||
return "\n".join(lines)
|
||||
|
||||
def show_exception(self, region: sublime.Region = None, msg=str()):
|
||||
sublime.message_dialog(f'[Error]: {msg}')
|
||||
if region is None:
|
||||
sublime.message_dialog(f'[Error]: {msg}')
|
||||
def show_exception(self, region: sublime.Region = None, msg=""):
|
||||
if region is None or region.empty():
|
||||
sublime.message_dialog(f"[Error]: {msg}")
|
||||
return
|
||||
self.highlight_error(region=region, message=f'{msg}')
|
||||
self.highlight_error(region=region, message=f"{msg}")
|
||||
|
||||
def highlight_error(self, region: sublime.Region, message: str):
|
||||
self.phantom_set = sublime.PhantomSet(self.view, 'json_errors')
|
||||
self.phantom_set = sublime.PhantomSet(self.view, "json_errors")
|
||||
|
||||
char_match = self.json_char_matcher.search(message)
|
||||
if char_match:
|
||||
|
@ -154,21 +161,21 @@ class PrettyJsonBaseCommand:
|
|||
self.phantoms.append(
|
||||
sublime.Phantom(
|
||||
region,
|
||||
self.create_phantom_html(message, 'error'),
|
||||
self.create_phantom_html(message, "error"),
|
||||
sublime.LAYOUT_BELOW,
|
||||
self.navigation,
|
||||
)
|
||||
)
|
||||
self.phantom_set.update(self.phantoms)
|
||||
self.view.show(region)
|
||||
self.view.set_status('json_errors', message)
|
||||
sublime.status_message(f"json_errors\t{message}")
|
||||
|
||||
# Description: Taken from
|
||||
# Description: Taken from
|
||||
# - https://github.com/sublimelsp/LSP/blob/master/plugin/diagnostics.py
|
||||
# - Thanks to the LSP Team
|
||||
def create_phantom_html(self, content: str, severity: str) -> str:
|
||||
stylesheet = sublime.load_resource('Packages/Pretty JSON/phantom.css')
|
||||
return f'''<body id=inline-error>
|
||||
stylesheet = sublime.load_resource("Packages/Pretty JSON/phantom.css")
|
||||
return f"""<body id=inline-error>
|
||||
<style>{stylesheet}</style>
|
||||
<div class="{severity}-arrow"></div>
|
||||
<div class="{severity} container">
|
||||
|
@ -177,24 +184,35 @@ class PrettyJsonBaseCommand:
|
|||
</div>
|
||||
<div class="content">{content}</div>
|
||||
</div>
|
||||
</body>'''
|
||||
</body>"""
|
||||
|
||||
def navigation(self, href: str):
|
||||
self.clear_phantoms()
|
||||
|
||||
def clear_phantoms(self):
|
||||
if isinstance(self.phantom_set, type):
|
||||
self.phantom_set = sublime.PhantomSet(self.view, 'json_errors')
|
||||
self.phantom_set = sublime.PhantomSet(self.view, "json_errors")
|
||||
|
||||
self.phantoms = list()
|
||||
self.phantom_set.update(self.phantoms)
|
||||
|
||||
def syntax_to_json(self):
|
||||
syntax = os.path.splitext(os.path.basename(self.view.settings().get('syntax')))[0]
|
||||
as_json = [i.lower() for i in s.get('as_json', ['JSON'])]
|
||||
if syntax.lower() not in as_json:
|
||||
settings = sublime.load_settings("Pretty JSON.sublime-settings")
|
||||
syntax = os.path.splitext(os.path.basename(self.view.settings().get("syntax")))[
|
||||
0
|
||||
]
|
||||
as_json = [i.lower() for i in settings.get("as_json", ["JSON"])]
|
||||
if syntax.lower() not in as_json and settings.get("set_syntax_on_format", True):
|
||||
self.view.set_syntax_file(json_syntax)
|
||||
|
||||
def duplicate_key_hook(self, pairs):
|
||||
result = dict()
|
||||
for key, val in pairs:
|
||||
if key in result:
|
||||
raise KeyError(f"Duplicate key specified: {key}")
|
||||
result[key] = val
|
||||
return result
|
||||
|
||||
|
||||
class PrettyJsonValidate(PrettyJsonBaseCommand, sublime_plugin.TextCommand):
|
||||
def run(self, edit):
|
||||
|
@ -202,9 +220,8 @@ class PrettyJsonValidate(PrettyJsonBaseCommand, sublime_plugin.TextCommand):
|
|||
regions = self.view.sel()
|
||||
for region in regions:
|
||||
region, _ = self.get_selection_from_region(
|
||||
region=region,
|
||||
regions_length=len(region),
|
||||
view=self.view)
|
||||
region=region, regions_length=len(region), view=self.view
|
||||
)
|
||||
if region is None:
|
||||
continue
|
||||
|
||||
|
@ -214,66 +231,67 @@ class PrettyJsonValidate(PrettyJsonBaseCommand, sublime_plugin.TextCommand):
|
|||
self.show_exception(region=region, msg=ex)
|
||||
return
|
||||
|
||||
sublime.status_message('JSON Valid')
|
||||
|
||||
def duplicate_key_hook(self, pairs):
|
||||
result = dict()
|
||||
for key, val in pairs:
|
||||
if key in result:
|
||||
raise KeyError(f'Duplicate key specified: {key}')
|
||||
result[key] = val
|
||||
return result
|
||||
sublime.status_message("JSON Valid")
|
||||
|
||||
|
||||
class PrettyJsonCommand(PrettyJsonBaseCommand, sublime_plugin.TextCommand):
|
||||
'''
|
||||
"""
|
||||
Description: Pretty Print JSON
|
||||
'''
|
||||
"""
|
||||
|
||||
def run(self, edit):
|
||||
settings = sublime.load_settings("Pretty JSON.sublime-settings")
|
||||
|
||||
self.clear_phantoms()
|
||||
pos = self.view.viewport_position()
|
||||
regions = self.view.sel()
|
||||
for region in regions:
|
||||
region, entire_file = self.get_selection_from_region(
|
||||
region=region,
|
||||
regions_length=len(region),
|
||||
view=self.view)
|
||||
region=region, regions_length=len(region), view=self.view
|
||||
)
|
||||
if region is None:
|
||||
continue
|
||||
|
||||
selection_text = self.view.substr(region)
|
||||
try:
|
||||
obj = self.json_loads(selection_text)
|
||||
|
||||
json_text = self.json_dumps(obj=obj, minified=False)
|
||||
if not entire_file and s.get('reindent_block', False):
|
||||
obj = {}
|
||||
if settings.get("abort_format_on_duplicate_key", False):
|
||||
try:
|
||||
self.json_loads(selection_text, self.duplicate_key_hook)
|
||||
except Exception as ex:
|
||||
self.show_exception(region=region, msg=ex)
|
||||
return
|
||||
else:
|
||||
obj = self.json_loads(selection_text)
|
||||
json_text = self.json_dumps(obj=obj, minified=False, force_sorting=self.force_sorting)
|
||||
if not entire_file and settings.get("reindent_block", False):
|
||||
json_text = self.reindent(json_text, region)
|
||||
|
||||
self.view.replace(edit, region, json_text)
|
||||
|
||||
if entire_file:
|
||||
self.syntax_to_json()
|
||||
|
||||
except Exception as ex:
|
||||
try:
|
||||
count_single_quotes = re.findall(
|
||||
r'(\'[^\']+\'?)', selection_text
|
||||
)
|
||||
count_single_quotes = re.findall(r"(\'[^\']+\'?)", selection_text)
|
||||
amount_of_double_quotes = re.findall(
|
||||
r'(\"[^\"]+\"?)', selection_text
|
||||
r"(\"[^\"]+\"?)", selection_text
|
||||
)
|
||||
|
||||
if len(count_single_quotes) >= len(amount_of_double_quotes):
|
||||
modified_text = re.sub(
|
||||
r'(?:\'([^\']+)\'?)', r'"\1"', selection_text
|
||||
r"(?:\'([^\']+)\'?)", r'"\1"', selection_text
|
||||
)
|
||||
obj = self.json_loads(modified_text)
|
||||
json_text = self.json_dumps(obj=obj, minified=False)
|
||||
|
||||
if not entire_file and s.get('reindent_block', False):
|
||||
if not entire_file and settings.get("reindent_block", False):
|
||||
json_text = self.reindent(json_text, region)
|
||||
|
||||
pos = self.view.viewport_position()
|
||||
self.view.replace(edit, region, json_text)
|
||||
self.view.set_viewport_position(pos)
|
||||
|
||||
if entire_file:
|
||||
self.syntax_to_json()
|
||||
else:
|
||||
|
@ -282,10 +300,71 @@ class PrettyJsonCommand(PrettyJsonBaseCommand, sublime_plugin.TextCommand):
|
|||
self.show_exception(region=region, msg=ex)
|
||||
|
||||
|
||||
class PrettyJsonLinesCommand(PrettyJsonCommand, sublime_plugin.TextCommand):
|
||||
|
||||
"""
|
||||
Description: Pretty print json lines https://jsonlines.org
|
||||
"""
|
||||
|
||||
def run(self, edit):
|
||||
self.clear_phantoms()
|
||||
regions = self.view.sel()
|
||||
error_count = 0
|
||||
for region in regions:
|
||||
(selection, selected_entire_file,) = self.get_selection_from_region(
|
||||
region=region, regions_length=len(regions), view=self.view
|
||||
)
|
||||
if selection is None:
|
||||
continue
|
||||
|
||||
for jsonl in sorted(self.view.split_by_newlines(selection), reverse=True):
|
||||
if error_count > 2:
|
||||
self.show_exception(msg="Encountered to many errors. Aborting")
|
||||
return
|
||||
|
||||
if self.view.substr(jsonl).strip() == "":
|
||||
continue
|
||||
|
||||
if jsonl.empty() and len(jsonl) > 1:
|
||||
continue
|
||||
|
||||
selection_text = ""
|
||||
try:
|
||||
selection_text = self.view.substr(jsonl)
|
||||
obj = self.json_loads(selection_text)
|
||||
self.view.replace(edit, jsonl, self.json_dumps(obj))
|
||||
|
||||
if selected_entire_file:
|
||||
self.syntax_to_json()
|
||||
|
||||
except Exception:
|
||||
error_count += 1
|
||||
try:
|
||||
amount_of_single_quotes = re.findall(
|
||||
r"(\'[^\']+\'?)", selection_text
|
||||
)
|
||||
amount_of_double_quotes = re.findall(
|
||||
r"(\"[^\"]+\"?)", selection_text
|
||||
)
|
||||
|
||||
if len(amount_of_single_quotes) >= len(amount_of_double_quotes):
|
||||
selection_text_modified = re.sub(
|
||||
r"(?:\'([^\']+)\'?)", r'"\1"', selection_text
|
||||
)
|
||||
obj = self.json_loads(selection_text_modified)
|
||||
self.view.replace(edit, jsonl, self.json_dumps(obj))
|
||||
|
||||
if selected_entire_file:
|
||||
self.syntax_to_json()
|
||||
except Exception as ex:
|
||||
error_count += 1
|
||||
self.show_exception(msg=ex)
|
||||
|
||||
|
||||
class PrettyJsonAndSortCommand(PrettyJsonCommand, sublime_plugin.TextCommand):
|
||||
'''
|
||||
"""
|
||||
Description: Pretty print json with forced sorting
|
||||
'''
|
||||
"""
|
||||
|
||||
def run(self, edit):
|
||||
self.force_sorting = True
|
||||
|
@ -294,26 +373,23 @@ class PrettyJsonAndSortCommand(PrettyJsonCommand, sublime_plugin.TextCommand):
|
|||
|
||||
|
||||
class UnPrettyJsonCommand(PrettyJsonBaseCommand, sublime_plugin.TextCommand):
|
||||
'''
|
||||
"""
|
||||
Description: Compress/minify JSON - it makes json as one-liner
|
||||
'''
|
||||
"""
|
||||
|
||||
def run(self, edit):
|
||||
self.clear_phantoms()
|
||||
regions = self.view.sel()
|
||||
for region in regions:
|
||||
region, entire_file = self.get_selection_from_region(
|
||||
region=region,
|
||||
regions_length=len(region),
|
||||
view=self.view)
|
||||
region=region, regions_length=len(region), view=self.view
|
||||
)
|
||||
if region is None:
|
||||
continue
|
||||
|
||||
try:
|
||||
obj = self.json_loads(self.view.substr(region))
|
||||
self.view.replace(
|
||||
edit, region, self.json_dumps(obj=obj, minified=True)
|
||||
)
|
||||
self.view.replace(edit, region, self.json_dumps(obj=obj, minified=True))
|
||||
|
||||
if entire_file:
|
||||
self.syntax_to_json()
|
||||
|
@ -331,20 +407,21 @@ class JqInsertPrettyJsonCommand(sublime_plugin.TextCommand):
|
|||
|
||||
class JqPrettyJsonCommand(sublime_plugin.TextCommand):
|
||||
def run(self, edit):
|
||||
syntax_file = self.view.settings().get('syntax')
|
||||
syntax_file = self.view.settings().get("syntax")
|
||||
|
||||
total_region = sublime.Region(0, self.view.size())
|
||||
content = self.view.substr(total_region)
|
||||
|
||||
sublime.run_command('new_window')
|
||||
sublime.run_command("new_window")
|
||||
preview_window = sublime.active_window()
|
||||
preview_window.set_sidebar_visible(False)
|
||||
|
||||
preview_window.run_command(
|
||||
'set_layout',
|
||||
"set_layout",
|
||||
{
|
||||
'cols': [0.0, 0.5, 1.0],
|
||||
'rows': [0.0, 1.0],
|
||||
'cells': [[0, 0, 1, 1], [1, 0, 2, 1]],
|
||||
"cols": [0.0, 0.5, 1.0],
|
||||
"rows": [0.0, 1.0],
|
||||
"cells": [[0, 0, 1, 1], [1, 0, 2, 1]],
|
||||
},
|
||||
)
|
||||
|
||||
|
@ -352,13 +429,13 @@ class JqPrettyJsonCommand(sublime_plugin.TextCommand):
|
|||
preview_view = preview_window.new_file()
|
||||
preview_view.set_scratch(True)
|
||||
preview_view.set_read_only(True)
|
||||
preview_view.set_name('Preview')
|
||||
preview_view.set_name("Preview")
|
||||
preview_view.sel().clear()
|
||||
|
||||
preview_window.focus_group(0)
|
||||
|
||||
jq_view = preview_window.new_file()
|
||||
jq_view.run_command('jq_insert_pretty_json', {'string': content})
|
||||
jq_view.run_command("jq_insert_pretty_json", {"string": content})
|
||||
jq_view.set_read_only(True)
|
||||
jq_view.set_scratch(True)
|
||||
jq_view.sel().clear()
|
||||
|
@ -373,6 +450,8 @@ class JqQueryPrettyJson(sublime_plugin.WindowCommand):
|
|||
"""
|
||||
|
||||
def is_enabled(self):
|
||||
settings = sublime.load_settings("Pretty JSON.sublime-settings")
|
||||
|
||||
if not self.window:
|
||||
return
|
||||
|
||||
|
@ -380,41 +459,36 @@ class JqQueryPrettyJson(sublime_plugin.WindowCommand):
|
|||
if not view:
|
||||
return
|
||||
|
||||
as_json = s.get('as_json', ['JSON'])
|
||||
return any(
|
||||
syntax in view.settings().get('syntax', '') for syntax in as_json
|
||||
)
|
||||
as_json = settings.get("as_json", ["JSON"])
|
||||
return any(syntax in view.settings().get("syntax", "") for syntax in as_json)
|
||||
|
||||
def is_visible(self):
|
||||
if not self.window:
|
||||
return
|
||||
|
||||
view = self.window.active_view()
|
||||
if not view:
|
||||
return
|
||||
|
||||
as_json = s.get('as_json', ['JSON'])
|
||||
return any(
|
||||
syntax in view.settings().get('syntax', '') for syntax in as_json
|
||||
)
|
||||
return self.is_enabled()
|
||||
|
||||
def run(self):
|
||||
check_jq()
|
||||
if jq_exists:
|
||||
jq_path = get_jq_path()
|
||||
if jq_path:
|
||||
preview_view = self.window.active_view()
|
||||
preview_view.run_command('jq_pretty_json')
|
||||
preview_view.run_command("jq_pretty_json")
|
||||
sublime.active_window().show_input_panel(
|
||||
'Enter ./jq filter expression', '.', self.done, self.send_query, None,
|
||||
"Enter ./jq filter expression",
|
||||
".",
|
||||
self.done,
|
||||
functools.partial(self.send_query, jq_path),
|
||||
None,
|
||||
)
|
||||
else:
|
||||
sublime.status_message(
|
||||
'./jq tool is not available on your system. http://stedolan.github.io/jq'
|
||||
)
|
||||
if sublime.ok_cancel_dialog(
|
||||
"./jq tool is not available on your system. Do you want to open the jq website?",
|
||||
"Open JQ Website"
|
||||
):
|
||||
webbrowser.open("http://stedolan.github.io/jq")
|
||||
|
||||
|
||||
def get_content(self):
|
||||
""" returns content of active view or selected region """
|
||||
"""returns content of active view or selected region"""
|
||||
view = self.window.active_view()
|
||||
selection = ''
|
||||
selection = ""
|
||||
regions = view.sel()
|
||||
for region in regions:
|
||||
if region.empty() and len(regions) > 1:
|
||||
|
@ -425,8 +499,9 @@ class JqQueryPrettyJson(sublime_plugin.WindowCommand):
|
|||
selection = region
|
||||
return view.substr(selection)
|
||||
|
||||
def send_query(self, query: str):
|
||||
def send_query(self, jq_path: str, query: str):
|
||||
global PREVIOUS_CONTENT, PREVIOUS_QUERY_LEN
|
||||
settings = sublime.load_settings("Pretty JSON.sublime-settings")
|
||||
try:
|
||||
p = subprocess.Popen(
|
||||
[jq_path, query],
|
||||
|
@ -443,12 +518,12 @@ class JqQueryPrettyJson(sublime_plugin.WindowCommand):
|
|||
if not PREVIOUS_CONTENT[1]:
|
||||
PREVIOUS_CONTENT[1] = raw_json
|
||||
|
||||
out, err = p.communicate(bytes(raw_json, 'UTF-8'))
|
||||
output = out.decode('UTF-8').replace(os.linesep, '\n').strip()
|
||||
errors = err.decode('UTF-8').replace(os.linesep, '\n').strip()
|
||||
out, err = p.communicate(bytes(raw_json, "UTF-8"))
|
||||
output = out.decode("UTF-8").replace(os.linesep, "\n").strip()
|
||||
errors = err.decode("UTF-8").replace(os.linesep, "\n").strip()
|
||||
jq_view = sublime.active_window().active_view_in_group(1)
|
||||
|
||||
if output and output != 'null':
|
||||
if output and output != "null":
|
||||
if QUERY_LEN > PREVIOUS_QUERY_LEN:
|
||||
PREVIOUS_CONTENT[0] = PREVIOUS_CONTENT[1]
|
||||
PREVIOUS_CONTENT[1] = output
|
||||
|
@ -456,14 +531,14 @@ class JqQueryPrettyJson(sublime_plugin.WindowCommand):
|
|||
PREVIOUS_CONTENT[1] = PREVIOUS_CONTENT[0]
|
||||
PREVIOUS_CONTENT[0] = output
|
||||
PREVIOUS_QUERY_LEN = len(query)
|
||||
elif s.get('jq_errors', False) and errors:
|
||||
elif settings.get("jq_errors", False) and errors:
|
||||
output = errors
|
||||
else:
|
||||
if PREVIOUS_QUERY_LEN <= QUERY_LEN:
|
||||
output = PREVIOUS_CONTENT[1]
|
||||
else:
|
||||
output = PREVIOUS_CONTENT[0]
|
||||
jq_view.run_command('jq_insert_pretty_json', {'string': output})
|
||||
jq_view.run_command("jq_insert_pretty_json", {"string": output})
|
||||
|
||||
except OSError as ex:
|
||||
sublime.status_message(str(ex))
|
||||
|
@ -474,37 +549,38 @@ class JqQueryPrettyJson(sublime_plugin.WindowCommand):
|
|||
|
||||
|
||||
class JsonToXml(PrettyJsonBaseCommand, sublime_plugin.TextCommand):
|
||||
'''
|
||||
"""
|
||||
Description: converts Json to XML
|
||||
'''
|
||||
"""
|
||||
|
||||
def run(self, edit):
|
||||
settings = sublime.load_settings("Pretty JSON.sublime-settings")
|
||||
|
||||
self.clear_phantoms()
|
||||
regions = self.view.sel()
|
||||
for region in regions:
|
||||
region, entire_file = self.get_selection_from_region(
|
||||
region=region,
|
||||
regions_length=len(region),
|
||||
view=self.view)
|
||||
region=region, regions_length=len(region), view=self.view
|
||||
)
|
||||
if region is None:
|
||||
continue
|
||||
|
||||
try:
|
||||
h = json.loads(self.view.substr(region))
|
||||
root = et.Element('root')
|
||||
root = et.Element("root")
|
||||
root = self.traverse(root, h)
|
||||
|
||||
xml_string = '<?xml version=\'1.0\' encoding=\'UTF-8\' ?>\n'
|
||||
xml_string = "<?xml version='1.0' encoding='UTF-8' ?>\n"
|
||||
|
||||
rtn = et.tostring(root, 'utf-8')
|
||||
rtn = et.tostring(root, "utf-8")
|
||||
if type(rtn) is bytes:
|
||||
rtn = rtn.decode('utf-8')
|
||||
rtn = rtn.decode("utf-8")
|
||||
|
||||
xml_string += rtn
|
||||
if type(xml_string) is bytes:
|
||||
xml_string = xml_string.decode('utf-8')
|
||||
xml_string = xml_string.decode("utf-8")
|
||||
|
||||
if not entire_file and s.get('reindent_block', False):
|
||||
if not entire_file and settings.get("reindent_block", False):
|
||||
xml_string = self.reindent(xml_string, region)
|
||||
|
||||
self.view.replace(edit, region, xml_string)
|
||||
|
@ -516,18 +592,18 @@ class JsonToXml(PrettyJsonBaseCommand, sublime_plugin.TextCommand):
|
|||
self.show_exception(region=region, msg=ex)
|
||||
|
||||
def traverse(self, element, json_dict):
|
||||
''' recursive traverse through dict and build xml tree '''
|
||||
"""recursive traverse through dict and build xml tree"""
|
||||
if type(json_dict) is dict and json_dict.keys():
|
||||
for i in json_dict.keys():
|
||||
e = et.Element(i)
|
||||
element.append(self.traverse(e, json_dict[i]))
|
||||
elif type(json_dict) is list:
|
||||
e_items = et.Element('items')
|
||||
e_items = et.Element("items")
|
||||
for i in json_dict:
|
||||
e_items.append(self.traverse(et.Element('item'), i))
|
||||
e_items.append(self.traverse(et.Element("item"), i))
|
||||
element.append(e_items)
|
||||
else:
|
||||
element.set('value', str(json_dict))
|
||||
element.set("value", str(json_dict))
|
||||
|
||||
return element
|
||||
|
||||
|
@ -543,7 +619,7 @@ class PrettyJsonGotoSymbolCommand(PrettyJsonBaseCommand, sublime_plugin.TextComm
|
|||
content = self.view.substr(sublime.Region(0, self.view.size()))
|
||||
try:
|
||||
json_data = self.json_loads(content)
|
||||
self.generate_items(json_data, '')
|
||||
self.generate_items(json_data, "")
|
||||
sublime.active_window().show_quick_panel(self.items, self.goto)
|
||||
except Exception as ex:
|
||||
self.show_exception(region=None, msg=ex)
|
||||
|
@ -551,14 +627,14 @@ class PrettyJsonGotoSymbolCommand(PrettyJsonBaseCommand, sublime_plugin.TextComm
|
|||
def generate_items(self, json_data, root_key):
|
||||
if isinstance(json_data, OrderedDict):
|
||||
for key in json_data:
|
||||
new_key_name = f'{root_key}.{key}'
|
||||
new_key_name = f"{root_key}.{key}"
|
||||
self.items.append(f'"{new_key_name}"')
|
||||
self.goto_items.append(f'"{key}"')
|
||||
self.generate_items(json_data[key], new_key_name)
|
||||
elif isinstance(json_data, list):
|
||||
for index, item in enumerate(json_data):
|
||||
if isinstance(item, str):
|
||||
self.items.append(f'{root_key}.{item}')
|
||||
self.items.append(f"{root_key}.{item}")
|
||||
self.goto_items.append(f'"{item}"')
|
||||
|
||||
def goto(self, pos):
|
||||
|
@ -574,8 +650,8 @@ class PrettyJsonGotoSymbolCommand(PrettyJsonBaseCommand, sublime_plugin.TextComm
|
|||
regions = self.view.find_all(string_to_search, sublime.LITERAL)
|
||||
for i, r in enumerate(regions):
|
||||
line = self.view.substr(self.view.full_line(r))
|
||||
if ':' in line:
|
||||
split = line.split(':')
|
||||
if ":" in line:
|
||||
split = line.split(":")
|
||||
val = split[1].strip()
|
||||
if string_to_search in val:
|
||||
del regions[i]
|
||||
|
@ -584,8 +660,3 @@ class PrettyJsonGotoSymbolCommand(PrettyJsonBaseCommand, sublime_plugin.TextComm
|
|||
self.view.sel().clear()
|
||||
self.view.sel().add(region)
|
||||
self.view.show(region)
|
||||
|
||||
|
||||
def plugin_loaded():
|
||||
global s
|
||||
s = sublime.load_settings('Pretty JSON.sublime-settings')
|
||||
|
|
|
@ -6,15 +6,16 @@ from .PrettyJson import PrettyJsonBaseCommand
|
|||
s = sublime.load_settings("Pretty JSON.sublime-settings")
|
||||
|
||||
|
||||
class PrettyJsonLintListener(sublime_plugin.EventListener, PrettyJsonBaseCommand):
|
||||
def on_post_save(self, view):
|
||||
class PrettyJsonLintListener(sublime_plugin.ViewEventListener, PrettyJsonBaseCommand):
|
||||
def on_post_save(self):
|
||||
if not s.get("validate_on_save", True):
|
||||
return
|
||||
|
||||
as_json = s.get("as_json", ["JSON"])
|
||||
if any(syntax in view.settings().get("syntax") for syntax in as_json):
|
||||
view_syntax = self.view.settings().get("syntax")
|
||||
if any(syntax in view_syntax for syntax in as_json):
|
||||
self.clear_phantoms()
|
||||
json_content = view.substr(sublime.Region(0, view.size()))
|
||||
json_content = self.view.substr(sublime.Region(0, self.view.size()))
|
||||
try:
|
||||
self.json_loads(json_content)
|
||||
except Exception as ex:
|
||||
|
@ -27,5 +28,6 @@ class PrettyJsonAutoPrettyOnSaveListener(sublime_plugin.EventListener):
|
|||
return
|
||||
|
||||
as_json = s.get("as_json", ["JSON"])
|
||||
if any(syntax in view.settings().get("syntax") for syntax in as_json):
|
||||
view_syntax = view.settings().get("syntax")
|
||||
if any(syntax in view_syntax for syntax in as_json):
|
||||
view.run_command("pretty_json")
|
||||
|
|
88
README.md
88
README.md
|
@ -72,6 +72,11 @@ you can add a setting like this to your .sublime-keymap file
|
|||
{ "keys": [ "ctrl+alt+m" ], "command": "un_pretty_json" }
|
||||
```
|
||||
|
||||
#### List of commands that can be mapped to shortcuts
|
||||
- `pretty_json`
|
||||
- `un_pretty_json`
|
||||
- `pretty_json_goto_symbol`
|
||||
|
||||
### Convert JSON to XML
|
||||
|
||||
Using Command Palette <kbd>Ctrl+Shift+P</kbd> search for
|
||||
|
@ -93,81 +98,54 @@ You can find instructions of tool here:
|
|||
|
||||
http://stedolan.github.io/jq/
|
||||
|
||||
## Default configuration
|
||||
## Configuration
|
||||
|
||||
- `use_entire_file_if_no_selection`
|
||||
- Default: `true`
|
||||
Check all the available configuration keys and their default values by using the Command Palette <kbd>Ctrl+Shift+P</kbd> and searching for `Preferences: Pretty JSON Settings`. From there you can also configure your own values.
|
||||
|
||||
- `indent`
|
||||
- Default: `2`
|
||||
- Integer represents amount of spaces
|
||||
- `\t` will utilize a tab character
|
||||
Here's a run down of the existing parameters, their meaning, and how you can configure each of them:
|
||||
|
||||
- `sort_keys`
|
||||
- Default: `false`
|
||||
|
||||
- `ensure_ascii`
|
||||
- Default: `false`
|
||||
|
||||
- `line_separator`
|
||||
- ","
|
||||
|
||||
- `value_separator`
|
||||
- ": "
|
||||
- Value separator in config,
|
||||
so if you need to get rid of extra space you can remove it with this param
|
||||
|
||||
- `keep_arrays_single_line`
|
||||
- Default: `false`
|
||||
- If we need to re-structure arrays and make them single-line
|
||||
|
||||
- `max_arrays_line_length`
|
||||
- Default: `120`
|
||||
- If array for example '["a", "b", 123213, ....]'
|
||||
length will reach max it will be kept multi-line
|
||||
|
||||
- `pretty_on_save`
|
||||
- Default: `false`
|
||||
- Do we need to automatically Pretty JSON on save
|
||||
|
||||
- `validate_on_save`
|
||||
- Default: `true`
|
||||
- Do we need validate JSON files on each save
|
||||
|
||||
- `reindent_block`
|
||||
- Default: `false`
|
||||
- If we are formatting a selection, if we need to reindent the
|
||||
resulting block to follow the flow of the source document
|
||||
the posible values are 'minimal' and 'start'
|
||||
- `use_entire_file_if_no_selection`: boolean that indicates whether the entire file should be used when there is no text selected.
|
||||
- `indent`: integer that represents the number of spaces to be used. To use tab indentation, use `\t` instead.
|
||||
- `sort_keys`: boolean that indicates whether the JSON keys should be sorted alphabetically.
|
||||
- `ensure_ascii`: boolean that indicaes whether it should validate that all characters are ASCII characters.
|
||||
- `line_separator`: string that represents the separator that will be used between lines. Usually this shouldn't be modified, to make sure the resulting JSON is valid.
|
||||
- `value_separator`: string that represents the separator that will be used between JSON keys and values. If you need to get rid of extra space after the collon, you can configure that using this parameter.
|
||||
- `keep_arrays_single_line`: boolean that indicates whether we need to re-structure arrays and make them single-line.
|
||||
- `max_arrays_line_length`: integer that determines the max length of single-line values. When the line exceeds this max length, it will be formatted in a multi-line fashion.
|
||||
- `pretty_on_save`: boolean that indicates whether JSON files should be automatically prettified on each file save.
|
||||
- `validate_on_save`: boolean that indicates whether JSON files should be automatically validated on each file save.
|
||||
- `brace_newline`: boolean that indicates whether there should be a newline after braces.
|
||||
- `bracket_newline`: boolean that indicates whether there should be a newline after brackets. `true` here means the resulting JSON will look like the Allman indentation style, while `false` will result in an OTBS indentation style.
|
||||
- `reindent_block`: if we are formatting a selection, if we need to reindent the resulting block to follow the flow of the source document the posible values are `minimal` and `start`.
|
||||
|
||||
using `minimal`, the resulting json lines are indented as much
|
||||
spaces as the line where the selection starts. e.g
|
||||
Using `minimal` the resulting json lines are indented as much spaces as theline where the selection starts. E.g.:
|
||||
|
||||
```yaml
|
||||
yaml_container:
|
||||
yaml_key: { "json": "value" }
|
||||
yaml_key: { "json": "value" }
|
||||
```
|
||||
|
||||
gets formatted as:
|
||||
|
||||
|
||||
Gets formatted as:
|
||||
|
||||
```yaml
|
||||
yaml_container:
|
||||
yaml_key: {
|
||||
"json": "value"
|
||||
}
|
||||
```
|
||||
|
||||
using `start`, the resulting json lines are indented a number
|
||||
of spaces equal to the column number of the start of the selection
|
||||
|
||||
with `start` the previous example gets formatted as:
|
||||
|
||||
|
||||
Using `start`, the resulting json lines are indented a number of spaces equal to the column number of the start of the selection.
|
||||
With `start` the previous example gets formatted as:
|
||||
|
||||
```yaml
|
||||
yaml_container:
|
||||
yaml_key: {
|
||||
"json": "value"
|
||||
}
|
||||
```
|
||||
|
||||
Use `false` if you wouldn't like the formatter to reindent the block at all.
|
||||
- `jq_binary`: path to the jq binary, e.g. `/usr/bin/local/jq`.
|
||||
|
||||
## Using tabs for indentation
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
http://172.20.32.208:8000/api/pms/nexusSecurity/initAllRoleAndPrivilege
|
||||
http://172.20.32.208:8000/api/system/ldapUser/initLdapUser
|
||||
http://172.20.32.208:8000/api/pms/pmsEnterprise/resetTeamUser
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
# 下载 unzip RPM 包
|
||||
wget http://mirror.centos.org/centos/7/os/x86_64/Packages/unzip-6.0-21.el7.x86_64.rpm
|
||||
|
||||
# 安装(推荐使用 yum/dnf)
|
||||
sudo yum localinstall unzip-6.0-21.el7.x86_64.rpm
|
||||
|
||||
# 验证安装
|
||||
unzip -v
|
||||
|
||||
|
||||
tar -xzvf git.tar.gz -C /usr/local/
|
||||
mv /usr/local/git-* /usr/local/git
|
||||
echo 'export PATH=/usr/local/git/bin:$PATH' >> ~/.bashrc
|
||||
source ~/.bashrc
|
Binary file not shown.
|
@ -33,4 +33,4 @@ html.dark div.toolbar {
|
|||
}
|
||||
html.light div.toolbar {
|
||||
background-color: #ffffff18;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
[tool.black]
|
||||
skip_string_normalization: True
|
Loading…
Reference in New Issue