diff --git a/.no-sublime-package b/.no-sublime-package deleted file mode 100644 index e69de29..0000000 diff --git a/PrettyJson.py b/PrettyJson.py index 29ad6f5..210bff6 100644 --- a/PrettyJson.py +++ b/PrettyJson.py @@ -1,16 +1,18 @@ -import sublime -import sublime_plugin import decimal -import sys import os import re -from xml.etree import ElementTree +import subprocess +import sys from xml.dom import minidom +from xml.etree import ElementTree + +import sublime +import sublime_plugin try: - basestring + basestring except NameError: - basestring = str + basestring = str try: # python 3 / Sublime Text 3 @@ -26,14 +28,15 @@ SUBLIME_MAJOR_VERSION = int(sublime.version()) / 1000 jq_exits = False jq_init = False -import subprocess """ for OSX we need to manually add brew bin path so jq can be found """ -if sys.platform != 'win32' and '/usr/local/bin' not in os.environ['PATH']: - os.environ["PATH"] += os.pathsep + '/usr/local/bin' +if sys.platform != "win32" and "/usr/local/bin" not in os.environ["PATH"]: + os.environ["PATH"] += os.pathsep + "/usr/local/bin" """ defer jq presence check until the user tries to use it, include Package "Fix Mac Path" to resolve all homebrew issues (https://github.com/int3h/SublimeFixMacPath) """ + + def check_jq(): global jq_exits global jq_init @@ -42,10 +45,12 @@ def check_jq(): jq_init = True try: # checking if ./jq tool is available so we can use it - s = subprocess.Popen(["jq", "--version"], - stdin=subprocess.PIPE, - stderr=subprocess.PIPE, - stdout=subprocess.PIPE) + s = subprocess.Popen( + ["jq", "--version"], + stdin=subprocess.PIPE, + stderr=subprocess.PIPE, + stdout=subprocess.PIPE, + ) out, err = s.communicate() jq_exits = True except OSError: @@ -63,9 +68,9 @@ class PrettyJsonBaseCommand: @staticmethod def json_loads(selection): - return json.loads(selection, - object_pairs_hook=OrderedDict, - parse_float=decimal.Decimal) + return json.loads( + selection, object_pairs_hook=OrderedDict, parse_float=decimal.Decimal + ) @staticmethod def json_dumps(obj): @@ -77,12 +82,14 @@ class PrettyJsonBaseCommand: line_separator = s.get("line_separator", ",") value_separator = s.get("value_separator", ": ") - output_json = json.dumps(obj, - indent=s.get("indent", 2), - ensure_ascii=s.get("ensure_ascii", False), - sort_keys=sort_keys, - separators=(line_separator, value_separator), - use_decimal=True) + output_json = json.dumps( + obj, + indent=s.get("indent", 2), + ensure_ascii=s.get("ensure_ascii", False), + sort_keys=sort_keys, + separators=(line_separator, value_separator), + use_decimal=True, + ) # do we need try and shuffle things around ? post_process = s.get("keep_arrays_single_line", False) @@ -113,16 +120,18 @@ class PrettyJsonBaseCommand: if PrettyJsonBaseCommand.force_sorting: sort_keys = True - return json.dumps(obj, - ensure_ascii=s.get("ensure_ascii", False), - sort_keys=sort_keys, - separators=(line_separator.strip(), value_separator.strip()), - use_decimal=True) + return json.dumps( + obj, + ensure_ascii=s.get("ensure_ascii", False), + sort_keys=sort_keys, + separators=(line_separator.strip(), value_separator.strip()), + use_decimal=True, + ) def highlight_error(self, message): - self.view.erase_regions('json_errors') - self.view.erase_status('json_errors') + self.view.erase_regions("json_errors") + self.view.erase_status("json_errors") m = self.json_error_matcher.search(message) if m: @@ -130,22 +139,33 @@ class PrettyJsonBaseCommand: # sometime we need to highlight one line above if "','" in message and "delimiter" in message: - line_content = self.view.substr(self.view.full_line(self.view.text_point(line - 1, 0))) - if line_content.strip()[-1] != ',' and line_content.strip() != '{' and line_content.strip() != '}': + line_content = self.view.substr( + self.view.full_line(self.view.text_point(line - 1, 0)) + ) + if ( + line_content.strip()[-1] != "," + and line_content.strip() != "{" + and line_content.strip() != "}" + ): line -= 1 if "control character '\\n'" in message: - line_content = self.view.substr(self.view.full_line(self.view.text_point(line - 1, 0))) + line_content = self.view.substr( + self.view.full_line(self.view.text_point(line - 1, 0)) + ) quotes = re.findall(r"\"", line_content) if len(quotes) % 2 != 0 and len(quotes) != 0: line -= 1 - regions = [self.view.full_line(self.view.text_point(line, 0)), ] + regions = [ + self.view.full_line(self.view.text_point(line, 0)), + ] - self.view.add_regions('json_errors', regions, 'invalid', 'dot', - sublime.DRAW_OUTLINED) + self.view.add_regions( + "json_errors", regions, "invalid", "dot", sublime.DRAW_OUTLINED + ) self.view.show(regions[0]) - self.view.set_status('json_errors', message) + self.view.set_status("json_errors", message) def show_exception(self): exc = sys.exc_info()[1] @@ -154,23 +174,24 @@ class PrettyJsonBaseCommand: def change_syntax(self): """ Changes syntax to JSON if its in plain text """ - if "Plain text" in self.view.settings().get('syntax'): + if "Plain text" in self.view.settings().get("syntax"): self.view.set_syntax_file("Packages/JavaScript/JSON.tmLanguage") class PrettyJsonValidate(PrettyJsonBaseCommand, sublime_plugin.TextCommand): def run(self, edit): - self.view.erase_regions('json_errors') - for region in self.view.sel(): - # If no selection, use the entire file as the selection - if region.empty() and s.get("use_entire_file_if_no_selection", True): + self.view.erase_regions("json_errors") + regions = self.view.sel() + for region in regions: + if region.empty() and len(regions) > 1: + continue + elif region.empty() and s.get("use_entire_file_if_no_selection", True): selection = sublime.Region(0, self.view.size()) - selected_entire_file = True else: selection = region try: - obj = self.json_loads(self.view.substr(selection)) + self.json_loads(self.view.substr(selection)) sublime.message_dialog("JSON is Valid") except Exception: self.show_exception() @@ -180,14 +201,15 @@ class PrettyJsonValidate(PrettyJsonBaseCommand, sublime_plugin.TextCommand): class PrettyJsonCommand(PrettyJsonBaseCommand, sublime_plugin.TextCommand): """ Pretty Print JSON """ + def run(self, edit): - self.view.erase_regions('json_errors') - for region in self.view.sel(): - + self.view.erase_regions("json_errors") + regions = self.view.sel() + for region in regions: selected_entire_file = False - - # If no selection, use the entire file as the selection - if region.empty() and s.get("use_entire_file_if_no_selection", True): + if region.empty() and len(regions) > 1: + continue + elif region.empty() and s.get("use_entire_file_if_no_selection", True): selection = sublime.Region(0, self.view.size()) selected_entire_file = True else: @@ -202,23 +224,33 @@ class PrettyJsonCommand(PrettyJsonBaseCommand, sublime_plugin.TextCommand): self.change_syntax() except Exception: - amount_of_single_quotes = re.findall(r"(\'[^\']+\'?)", selection_text) - amount_of_double_quotes = re.findall(r"(\"[^\"]+\"?)", selection_text) + 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, selection, self.json_dumps(obj)) + 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, selection, self.json_dumps(obj)) - if selected_entire_file: - self.change_syntax() - else: + if selected_entire_file: + self.change_syntax() + else: + self.show_exception() + except: self.show_exception() class PrettyJsonAndSortCommand(PrettyJsonCommand, sublime_plugin.TextCommand): """ Pretty print json with forced sorting """ + def run(self, edit): PrettyJsonBaseCommand.force_sorting = True PrettyJsonCommand.run(self, edit) @@ -228,14 +260,15 @@ class PrettyJsonAndSortCommand(PrettyJsonCommand, sublime_plugin.TextCommand): class UnPrettyJsonCommand(PrettyJsonBaseCommand, sublime_plugin.TextCommand): """ Compress/minify JSON - it makes json as one-liner """ + def run(self, edit): - self.view.erase_regions('json_errors') - for region in self.view.sel(): - + self.view.erase_regions("json_errors") + regions = self.view.sel() + for region in regions: selected_entire_file = False - - # If no selection, use the entire file as the selection - if region.empty() and s.get("use_entire_file_if_no_selection", True): + if region.empty() and len(regions) > 1: + continue + elif region.empty() and s.get("use_entire_file_if_no_selection", True): selection = sublime.Region(0, self.view.size()) selected_entire_file = True else: @@ -256,13 +289,17 @@ class JqPrettyJson(sublime_plugin.WindowCommand): """ Allows work with ./jq """ + def run(self): check_jq() if jq_exits: - self.window.show_input_panel("Enter ./jq filter expression", ".", - self.done, None, None) + self.window.show_input_panel( + "Enter ./jq filter expression", ".", self.done, None, None + ) else: - sublime.status_message('./jq tool is not available on your system. http://stedolan.github.io/jq') + sublime.status_message( + "./jq tool is not available on your system. http://stedolan.github.io/jq" + ) def get_content(self): """ returns content of active view or selected region """ @@ -278,18 +315,20 @@ class JqPrettyJson(sublime_plugin.WindowCommand): def done(self, query): try: - p = subprocess.Popen(["jq", query], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - stdin=subprocess.PIPE) + p = subprocess.Popen( + ["jq", query], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + stdin=subprocess.PIPE, + ) raw_json = self.get_content() if SUBLIME_MAJOR_VERSION < 3: - if sys.platform != 'win32': + if sys.platform != "win32": out, err = p.communicate(bytes(raw_json)) else: - out, err = p.communicate(unicode(raw_json).encode('utf-8')) + out, err = p.communicate(unicode(raw_json).encode("utf-8")) else: out, err = p.communicate(bytes(raw_json, "utf-8")) output = out.decode("UTF-8").replace(os.linesep, "\n").strip() @@ -307,9 +346,10 @@ class JsonToXml(PrettyJsonBaseCommand, sublime_plugin.TextCommand): """ converts Json to XML """ + def run(self, edit): """ overwriting base class run function to remove intent """ - self.view.erase_regions('json_errors') + self.view.erase_regions("json_errors") for region in self.view.sel(): selected_entire_file = False @@ -341,7 +381,9 @@ class JsonToXml(PrettyJsonBaseCommand, sublime_plugin.TextCommand): # for some reason python 2.6 shipped with ST2 # does not have pyexpat if SUBLIME_MAJOR_VERSION >= 3: - xml_string = minidom.parseString(xml_string).toprettyxml(encoding="UTF-8") + xml_string = minidom.parseString(xml_string).toprettyxml( + encoding="UTF-8" + ) if type(xml_string) is bytes: xml_string = xml_string.decode("utf-8") @@ -356,14 +398,14 @@ class JsonToXml(PrettyJsonBaseCommand, sublime_plugin.TextCommand): def indent_for_26(self, elem, level=0): """ intent of ElementTree in case it's py26 without minidom/pyexpat """ - i = "\n" + level*" " + i = "\n" + level * " " if len(elem): if not elem.text or not elem.text.strip(): elem.text = i + " " if not elem.tail or not elem.tail.strip(): elem.tail = i for elem in elem: - self.indent_for_26(elem, level+1) + self.indent_for_26(elem, level + 1) if not elem.tail or not elem.tail.strip(): elem.tail = i else: @@ -377,12 +419,12 @@ class JsonToXml(PrettyJsonBaseCommand, sublime_plugin.TextCommand): e = ElementTree.Element(i) element.append(self.traverse(e, json_dict[i])) elif type(json_dict) is list: - e_items = ElementTree.Element('items') + e_items = ElementTree.Element("items") for i in json_dict: - e_items.append(self.traverse(ElementTree.Element('item'), i)) + e_items.append(self.traverse(ElementTree.Element("item"), i)) element.append(e_items) else: - element.set('value', str(json_dict)) + element.set("value", str(json_dict)) return element @@ -392,7 +434,7 @@ class JsonToXml(PrettyJsonBaseCommand, sublime_plugin.TextCommand): class JqPrettyJsonOut(sublime_plugin.TextCommand): - def run(self, edit, jq_output=''): + def run(self, edit, jq_output=""): self.view.insert(edit, 0, jq_output) @@ -405,7 +447,7 @@ class PrettyJsonGotoSymbolCommand(PrettyJsonBaseCommand, sublime_plugin.TextComm 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: self.show_exception() @@ -413,14 +455,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 = root_key + '.' + key - self.items.append('%s' % new_key_name) + new_key_name = root_key + "." + key + self.items.append("%s" % new_key_name) self.goto_items.append('"%s"' % 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, basestring): - self.items.append('%s' % root_key + '.' + item) + self.items.append("%s" % root_key + "." + item) self.goto_items.append('"%s"' % item) def goto(self, pos):