diff --git a/.gitignore b/.gitignore index 9335c31..c10bbf6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ *.pyc -*.todo \ No newline at end of file +*.todo +/.idea diff --git a/Context.sublime-menu b/Context.sublime-menu index c85987f..f672ded 100644 --- a/Context.sublime-menu +++ b/Context.sublime-menu @@ -108,115 +108,56 @@ "command": "convert_sha1" }, { - "caption": "-" - }, - { - "caption": "Convert Unixtime <-> Datetime", - "command": "convert_time_format" - }, - { - "caption": "Insert Current Datetime", - "command": "insert_timestamp" - }, - { - "caption": "-" + "caption": "Calculate SHA224", + "command": "convert_sha224" }, { - "args": { - "length": "6" - }, - "caption": "Generate Password (6 char)", - "command": "generate_password" + "caption": "Calculate SHA256", + "command": "convert_sha256" }, { - "args": { - "length": "8" - }, - "caption": "Generate Password (8 char)", - "command": "generate_password" + "caption": "Calculate SHA384", + "command": "convert_sha384" }, { - "args": { - "length": "12" - }, - "caption": "Generate Password (12 char)", - "command": "generate_password" + "caption": "Calculate SHA512", + "command": "convert_sha512" }, { - "args": { - "length": "16" - }, - "caption": "Generate Password (16 char)", - "command": "generate_password" - }, - { - "args": { - "length": "32" - }, - "caption": "Generate Password (32 char)", - "command": "generate_password" + "caption": "-" }, { - "args": { - "length": "40" - }, - "caption": "Generate Password (40 char)", - "command": "generate_password" + "caption": "Pretify JSON String", + "command": "string_utilities_decode_json" }, { - "args": { - "length": "64" - }, - "caption": "Generate Password (64 char)", - "command": "generate_password" + "caption": "JSON Escape", + "command": "json_escape" }, { - "args": { - "length": "6" - }, - "caption": "Generate Password with spec symbols (6 char)", - "command": "generate_password_spec_symbols" + "caption": "JSON Unescape", + "command": "json_unescape" }, { - "args": { - "length": "8" - }, - "caption": "Generate Password with spec symbols (8 char)", - "command": "generate_password_spec_symbols" + "caption": "-" }, { - "args": { - "length": "12" - }, - "caption": "Generate Password with spec symbols (12 char)", - "command": "generate_password_spec_symbols" + "caption": "Convert Unixtime <-> Datetime", + "command": "convert_time_format" }, { - "args": { - "length": "16" - }, - "caption": "Generate Password with spec symbols (16 char)", - "command": "generate_password_spec_symbols" + "caption": "Insert Current Datetime", + "command": "insert_timestamp" }, { - "args": { - "length": "32" - }, - "caption": "Generate Password with spec symbols (32 char)", - "command": "generate_password_spec_symbols" + "caption": "-" }, { - "args": { - "length": "40" - }, - "caption": "Generate Password with spec symbols (40 char)", - "command": "generate_password_spec_symbols" + "caption": "Generate Password", + "command": "generate_password" }, { - "args": { - "length": "64" - }, - "caption": "Generate Password with spec symbols (64 char)", + "caption": "Generate Password with spec symbols", "command": "generate_password_spec_symbols" }, { @@ -240,13 +181,6 @@ { "caption": "-" }, - { - "caption": "Pretify JSON String", - "command": "string_utilities_decode_json" - }, - { - "caption": "-" - }, { "caption": "Convert PHP Object to Array", "command": "php_object_to_array" diff --git a/Default.sublime-commands b/Default.sublime-commands index 02ccf69..f466bac 100644 --- a/Default.sublime-commands +++ b/Default.sublime-commands @@ -116,101 +116,11 @@ "command": "insert_timestamp" }, { - "args": { - "length": "6" - }, - "caption": "String Utilities: Insert Password (6 char)", + "caption": "String Utilities: Insert Password", "command": "generate_password" }, { - "args": { - "length": "8" - }, - "caption": "String Utilities: Insert Password (8 char)", - "command": "generate_password" - }, - { - "args": { - "length": "12" - }, - "caption": "String Utilities: Insert Password (12 char)", - "command": "generate_password" - }, - { - "args": { - "length": "16" - }, - "caption": "String Utilities: Insert Password (16 char)", - "command": "generate_password" - }, - { - "args": { - "length": "32" - }, - "caption": "String Utilities: Insert Password (32 char)", - "command": "generate_password" - }, - { - "args": { - "length": "40" - }, - "caption": "String Utilities: Insert Password (40 char)", - "command": "generate_password" - }, - { - "args": { - "length": "64" - }, - "caption": "String Utilities: Insert Password (64 char)", - "command": "generate_password" - }, - { - "args": { - "length": "6" - }, - "caption": "String Utilities: Insert Password with spec symbols (6 char)", - "command": "generate_password_spec_symbols" - }, - { - "args": { - "length": "8" - }, - "caption": "String Utilities: Insert Password with spec symbols (8 char)", - "command": "generate_password_spec_symbols" - }, - { - "args": { - "length": "12" - }, - "caption": "String Utilities: Insert Password with spec symbols (12 char)", - "command": "generate_password_spec_symbols" - }, - { - "args": { - "length": "16" - }, - "caption": "String Utilities: Insert Password with spec symbols (16 char)", - "command": "generate_password_spec_symbols" - }, - { - "args": { - "length": "32" - }, - "caption": "String Utilities: Insert Password with spec symbols (32 char)", - "command": "generate_password_spec_symbols" - }, - { - "args": { - "length": "40" - }, - "caption": "String Utilities: Insert Password with spec symbols (40 char)", - "command": "generate_password_spec_symbols" - }, - { - "args": { - "length": "64" - }, - "caption": "String Utilities: Insert Password with spec symbols (64 char)", + "caption": "String Utilities: Insert Password with spec symbols", "command": "generate_password_spec_symbols" }, { @@ -229,6 +139,14 @@ "caption": "String Utilities: Decode JSON", "command": "string_utilities_decode_json" }, + { + "caption": "String Utilities: JSON Escape", + "command": "json_escape" + }, + { + "caption": "String Utilities: JSON Unescape", + "command": "json_unescape" + }, { "caption": "String Utilities: PHP object to array", "command": "php_object_to_array" diff --git a/stringutilities.py b/stringutilities.py index 5b2a3d1..89254e3 100644 --- a/stringutilities.py +++ b/stringutilities.py @@ -206,6 +206,47 @@ def run(self, edit): self.view.replace(edit, region, text) +class StringEncode(sublime_plugin.TextCommand): + def run(self, edit, **kwargs): + regions = self.view.sel() + + if kwargs.get('source') == 'clipboard': + del kwargs['source'] + text = sublime.get_clipboard() + replacement = self.encode(text, **kwargs) + for region in regions: + if region.empty(): + self.view.insert(edit, region.begin(), replacement) + else: + self.view.replace(edit, region, replacement) + return + + elif 'source' in kwargs: + sublime.status_message('Unsupported source {0!r}'.format(kwargs['source'])) + return + + if any(map(lambda region: region.empty(), regions)): + regions = [sublime.Region(0, self.view.size())] + for region in regions: + text = self.view.substr(region) + replacement = self.encode(text, **kwargs) + self.view.replace(edit, region, replacement) + + +class JsonEscapeCommand(StringEncode): + def encode(self, text): + return json.dumps(text)[1:-1] + + +class JsonUnescapeCommand(StringEncode): + def encode(self, text): + if text[:1] == "'" and text[-1:] == "'": + return self.encode(text[1:-1]) + if text[:1] != '"' and text[-1:] != '"': + return self.encode('"' + text + '"') + return json.loads(text) + + class ConvertToBase64Command(sublime_plugin.TextCommand): #Encode string with base64 def run(self, edit): @@ -436,22 +477,33 @@ class InsertTimestampCommand(sublime_plugin.TextCommand): #This will allow you to insert timestamp to current position def run(self, edit): for region in self.view.sel(): - self.view.insert(edit, region.begin(), datetime.now().strftime("%Y-%m-%d %H:%M")) + self.view.insert(edit, region.begin(), datetime.now().strftime("%Y-%m-%d %H:%M:%S")) class GeneratePasswordCommand(sublime_plugin.TextCommand): chars = "23456789abcdefghijkmnpqrstuvwxyzABCDEFGHKMNPQRSTUVWXYZ" - def run(self, edit, length=16): - length = int(length) - self.view.insert(edit, self.view.sel()[0].begin(), ''.join(sample(self.chars, length))) + def run(self, edit): + self.view.window().show_input_panel("Enter Length(int≤54)", "", self.on_change, None, None) + + def on_change(self, length): + if length: + length = int(length) + text = ''.join(sample(self.chars, length)) + self.view.run_command("insert", {"characters": text}) + class GeneratePasswordSpecSymbolsCommand(sublime_plugin.TextCommand): chars = "0123456789abcdefghijkmnpqrstuvwxyzABCDEFGHKMNPQRSTUVWXYZ%*)?@#$~" - def run(self, edit, length=16): - length = int(length) - self.view.insert(edit, self.view.sel()[0].begin(), ''.join(sample(self.chars, length))) + def run(self, edit): + self.view.window().show_input_panel("Enter Length(int≤64)", "", self.on_change, None, None) + + def on_change(self, length): + if length: + length = int(length) + text = ''.join(sample(self.chars, length)) + self.view.run_command("insert", {"characters": text}) class DecodeHeidiSqlCommand(sublime_plugin.TextCommand): # Requires .strip('\x00') on output otherwise sublimetext adds a 'NUL' control chracter @@ -470,7 +522,7 @@ def decodeHeidi(self, hex_in): class StringUtilitiesExtIpCommand(sublime_plugin.TextCommand): def run(self, edit): - url = "http://api.long.ge/sublimetext/ip.php" + url = "https://myip.ipip.net/" request = urllib.request.Request(url) response = urllib.request.urlopen(request) for region in self.view.sel(): @@ -484,10 +536,12 @@ def enc(self): class StringUtilitiesIntIpCommand(sublime_plugin.TextCommand): def run(self, edit): - s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - s.connect(('google.com', 0)) - int_ip = s.getsockname()[0] - s.close() + try: + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.connect(('8.8.8.8', 80)) + int_ip = s.getsockname()[0] + finally: + s.close() for region in self.view.sel(): self.view.insert(edit, region.begin(), int_ip) @@ -503,28 +557,73 @@ class StringUtilitiesDecodeJsonCommand(sublime_plugin.TextCommand): i = 0 def run(self, edit): - for region in self.view.sel(): - self.output = "" - if not region.empty(): - text = self.view.substr(region).encode(self.enc()) + + try: + self.view.erase_regions('json_errors') + self.view.erase_status('json_errors') + for region in self.view.sel(): + self.output = "" + if region.empty(): + selection = sublime.Region(0, self.view.size()) + else: + selection = region + + text = self.view.substr(selection).encode(self.enc()) text = str(text, 'utf8') data = json.loads(text, encoding='utf8') output = json.dumps(data, indent=4, sort_keys=True) - self.view.replace(edit, region, output) + self.view.replace(edit, selection, output) + + #self.recursivePrint(data) + + #print(self.output) + + #pp = pprint.PrettyPrinter(indent=4, width=1) + #data = pp.pformat(data) + #data = self.output + #data = data.replace('{ ', '{') + #data = data.replace('{', '\n {\n') + + #self.view.replace(edit, region, self.output) + except Exception: + exc = sys.exc_info()[1] + sublime.status_message(str(exc)) + for region in self.view.sel(): + if region.empty(): + self.highlight_error(str(exc)) + else: + startrow, startcol = self.view.rowcol(region.begin()) + self.highlight_error(str(exc), lineBegin=startrow) + + def highlight_error(self, message, lineBegin=0): + + self.view.erase_regions('json_errors') + self.view.erase_status('json_errors') + json_error_matcher = re.compile(r"line (\d+)") + m = json_error_matcher.search(message) + if m: + line = int(m.group(1)) + lineBegin - 1 - #self.recursivePrint(data) + # 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 -= 1 - #print(self.output) + if "control character '\\n'" in message: + 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 - #pp = pprint.PrettyPrinter(indent=4, width=1) - #data = pp.pformat(data) - #data = self.output - #data = data.replace('{ ', '{') - #data = data.replace('{', '\n {\n') + regions = [self.view.full_line(self.view.text_point(line, 0)), ] - #self.view.replace(edit, region, self.output) + self.view.add_regions('json_errors', regions, 'invalid', 'dot', + sublime.DRAW_OUTLINED) + self.view.show(regions[0]) + self.view.set_status('json_errors', message) def enc(self): if self.view.encoding() == 'Undefined':