Skip to content

Instantly share code, notes, and snippets.

@theVDude
Created June 3, 2017 23:25
Show Gist options
  • Save theVDude/d428e4ceb71a7d9ed878ea149061ad82 to your computer and use it in GitHub Desktop.
Save theVDude/d428e4ceb71a7d9ed878ea149061ad82 to your computer and use it in GitHub Desktop.
# uncompyle6 version 2.9.8
# Python bytecode 2.6 (62161)
# Decompiled from: Python 3.6.0 (default, Jan 16 2017, 13:35:36)
# [GCC 6.3.1 20170109]
# Embedded file name: ./sublimerge/sublimerge_differ.py
# Compiled at: 2016-10-17 14:46:21
"""Copyright (c) Borys Forytarz. All rights reserved"""
import difflib
import re
import sublime
import time
import codecs
import os
import sys
import uuid
import platform
import codecs
import shutil
from hashlib import sha1
from webbrowser import open_new_tab as browser_open
from base64 import decodestring as bd
from base64 import decodestring as decode64
from base64 import encodestring as encode64
from .sublimerge_utils import SublimergeUtils, splitlines
from .sublimerge_messages import SublimergeMessages
from .sublimerge_settings import SublimergeSettings
from .version import version
from .sublimerge_debug import console_log
signature = 'aHR0cDovL3d3dy5zdWJsaW1lcmdlLmNvbS9idXkuaHRtbA'
verify = 'U3VibGltZXJnZS5zdWJsaW1lLWxpY2Vuc2U'
evaled = 'U3VibGltZXJnZQ0KDQpJdCBzZWVtcyB1bmxpY2Vuc2VkIGNvcHkgaXMgaW4gdXNlIGZvciBtb3JlIHRoYW4gOTAgZGF5cy4gSSBiZWxpZXZlIHRoYXQgaXQgaGVscHMgYSBsb3QgaW4geW91ciB3b3JrLiBEZXZlbG9wbWVudCBvZiB0aGlzIHBhY2thZ2UgYWxzbyBjb3N0cyBtZSBhIGxvdCBvZiBlZmZvcnQgYW5kIG15IHNwYXJlIHRpbWUuIFBsZWFzZSBiZSBmYWlyIGFuZCBsZWdhbCBhbmQgcHVyY2hhc2UgYSBsaWNlbnNlLiBUaGFuayB5b3UgaW4gYWR2YW5jZS4NCg0KQm9yeXMgRm9yeXRhcnogLSBhdXRob3I='
purc = 'UHVyY2hhc2Ugbm93'
utils = SublimergeUtils()
def fopen(path, mode):
try:
return open(path, mode)
except:
return codecs.open(path, mode)
def get_hunk_type(hunk1, hunk2):
if hunk1[1] == 0:
return '-'
elif hunk2[1] == 0:
return '+'
else:
return '.'
def prepare_text_for_diff(text):
if SublimergeSettings.get('ignore_crlf'):
text = re.sub('\r\n', '\n', text)
text = re.sub('\r', '\n', text)
if SublimergeSettings.get('ignore_whitespace'):
regexp = re.compile('(^[ \t\x0c\x0b]+)|([ \t\x0c\x0b]+$)', re.MULTILINE)
text = re.sub(regexp, '', text)
if SublimergeSettings.get('ignore_case'):
text = text.lower()
return text + '\nEOF'
class SublimergeDiffer():
zero_offset = 0
def __init__(self):
if int(sublime.version()) >= 3000:
self.zero_offset = self.diff_test()
def diff_test(self):
data = self.difference('a\nb\n\\c\n\\d', 'a\n\\c\n\\d', False)
if data['left'][0][0] != data['right'][0][0]:
return 1
return 0
def difference(self, text1, text2, separate_missing_blocks=False, callback=None, callback_done=None, their_crlf=False, mine_crlf=False):
if not isinstance(text1, list):
lines1 = splitlines(prepare_text_for_diff(utils.normalize_crlf(text1, their_crlf)))
else:
lines1 = text1
if not isinstance(text2, list):
lines2 = splitlines(prepare_text_for_diff(utils.normalize_crlf(text2, mine_crlf)))
else:
lines2 = text2
gen = difflib.unified_diff(lines1, lines2, n=0)
hunk_re = '^@@ \\-(\\d+),?(\\d*) \\+(\\d+),?(\\d*) @@'
data = {'left': [],'right': []}
def prepare(start_left, size_left, start_right, size_right):
end_left = size_left + start_left - 1
end_right = size_right + start_right - 1
type_left = type_right = '.'
if end_left < start_left:
type_left = '+'
type_right = '-'
elif end_right < start_right:
type_right = '+'
type_left = '-'
self.add(data['left'], [
start_left,
end_left,
0 if size_left > size_right else size_right - size_left,
type_left])
self.add(data['right'], [
start_right,
end_right,
0 if size_right > size_left else size_left - size_right,
type_right])
if callback is not None:
callback(data['left'][-1], data['right'][-1])
return
for line in gen:
hunks = re.finditer(hunk_re, line)
for hunk in hunks:
start_left = int(hunk.group(1))
start_right = int(hunk.group(3))
size_left = int(hunk.group(2) or 1)
size_right = int(hunk.group(4) or 1)
if size_left > 0:
size_left < size_right and separate_missing_blocks and prepare(start_left, size_left, start_right, size_left)
prepare(start_left + size_left - self.zero_offset, 0, start_right + size_left, size_right - size_left)
elif size_right > 0:
size_right < size_left and separate_missing_blocks and prepare(start_left, size_right, start_right, size_right)
prepare(start_left + size_right, size_left - size_right, start_right + size_right - self.zero_offset, 0)
else:
prepare(start_left, size_left, start_right, size_right)
if callback_done is not None:
callback_done()
return data
def add(self, collection, data):
if data[1] < data[0]:
data[1] = 0
if data[1] == 0:
data[0] += self.zero_offset
collection.append(data)
class SublimergeDiffer3():
changes = []
unmatched = []
def difference(self, their, base, mine, callback, callback_merged, callback_done, their_crlf=False, base_crlf=False, mine_crlf=False):
self.their_original = splitlines(utils.normalize_crlf(their))
self.mine_original = splitlines(utils.normalize_crlf(mine))
self.their_original.append('\n')
self.mine_original.append('\n')
self.their = splitlines(prepare_text_for_diff(utils.normalize_crlf(their, their_crlf)))
self.base = splitlines(prepare_text_for_diff(utils.normalize_crlf(base, base_crlf)))
self.mine = splitlines(prepare_text_for_diff(utils.normalize_crlf(mine, mine_crlf)))
self.callback = callback
self.callback_merged = callback_merged
self.changes = []
self.unmatched = {'their': [],'mine': []}
def hunk_line_set--- This code section failed: ---
188 0 LOAD_FAST 0 'hunk'
3 LOAD_CONST 1 1
6 BINARY_SUBSCR
7 LOAD_CONST 2 ''
10 COMPARE_OP 2 '=='
13 JUMP_IF_FALSE 54 'to 70'
16 POP_TOP
189 17 LOAD_GLOBAL 0 'set'
20 LOAD_GLOBAL 1 'range'
23 LOAD_FAST 0 'hunk'
26 LOAD_CONST 2 ''
29 BINARY_SUBSCR
30 LOAD_FAST 0 'hunk'
33 LOAD_CONST 2 ''
36 BINARY_SUBSCR
37 LOAD_CONST 1 1
40 BINARY_ADD
41 LOAD_FAST 1 'add_hunk_2'
44 JUMP_IF_TRUE 7 'to 54'
47 POP_TOP
48 LOAD_CONST 2 ''
51 JUMP_FORWARD 8 'to 62'
54_0 COME_FROM '44'
54 POP_TOP
55 LOAD_FAST 0 'hunk'
58 LOAD_CONST 3 2
61 BINARY_SUBSCR
62_0 COME_FROM '51'
62 BINARY_ADD
63 CALL_FUNCTION_2 2
66 CALL_FUNCTION_1 1
69 RETURN_END_IF
70 POP_TOP
191 71 LOAD_GLOBAL 0 'set'
74 LOAD_GLOBAL 1 'range'
77 LOAD_FAST 0 'hunk'
80 LOAD_CONST 2 ''
83 BINARY_SUBSCR
84 LOAD_FAST 0 'hunk'
87 LOAD_CONST 1 1
90 BINARY_SUBSCR
91 LOAD_CONST 1 1
94 BINARY_ADD
95 LOAD_FAST 1 'add_hunk_2'
98 JUMP_IF_TRUE 7 'to 108'
101 POP_TOP
102 LOAD_CONST 2 ''
105 JUMP_FORWARD 8 'to 116'
108_0 COME_FROM '98'
108 POP_TOP
109 LOAD_FAST 0 'hunk'
112 LOAD_CONST 3 2
115 BINARY_SUBSCR
116_0 COME_FROM '105'
116 BINARY_ADD
117 CALL_FUNCTION_2 2
120 CALL_FUNCTION_1 1
123 RETURN_VALUE
Parse error at or near `COME_FROM' instruction at offset 54_0
def hunk_line_range(hunk):
if hunk[1] == 0:
return (hunk[0], hunk[0] + 1)
else:
return (
hunk[0], hunk[1] + 1)
def add_their_base(base_hunk, their_hunk):
for change in self.changes:
if hunk_line_set(change['their']) & hunk_line_set(their_hunk):
change['base_their'] = base_hunk
def is_conflict(change):
return hunk_line_set(change['base_their'], True) & hunk_line_set(change['base_mine'], True) or hunk_line_set(change['their']) & hunk_line_set(change['mine'])
def add_mine_base(base_hunk, mine_hunk):
for change in self.changes:
if hunk_line_set(change['mine']) & hunk_line_set(mine_hunk):
change['base_mine'] = base_hunk
elif change['base_their'] is not None:
if is_conflict(change):
change['conflict'] = True
return
def verify_conflict(change):
their_insert = change['their'][1] == 0
mine_insert = change['mine'][1] == 0
if not their_insert:
text_their = not mine_insert and self.their[change['their'][0] - 1:change['their'][1]]
text_base = self.base[change['their'][0] - 1:change['their'][1]]
text_their == text_base and console_log('Resolving conflict using `mine` because `their` == `base`', text_their, text_base)
change['conflict'] = False
change['base_their'] = None
return
else:
text_mine = self.mine[change['mine'][0] - 1:change['mine'][1]]
text_base = self.base[change['mine'][0] - 1:change['mine'][1]]
if text_mine == text_base:
console_log('Resolving conflict using `their` because `mine` == `base`', text_mine, text_base)
change['conflict'] = False
change['base_mine'] = None
return
if SublimergeSettings.get('three_way_auto_resolve')['white_space_vs_non_white_space']:
if all((char in ('\r', '\n', '\t', ' ') for char in text_mine)):
console_log('Resolving conflict using `their` because `mine` contains only empty lines', text_mine, text_their)
change['base_mine'] = None
change['their'][3] = change['mine'][3] = '?'
return
else:
all((char in ('\r', '\n', '\t', ' ') for char in text_their)) and console_log('Resolving conflict using `mine` because `their` contains only empty lines', text_their, text_mine)
change['base_their'] = None
change['their'][3] = change['mine'][3] = '?'
return
elif their_insert and not mine_insert or not their_insert and mine_insert:
change['conflict'] = False
if their_insert:
change['base_mine'] = None
console_log('Resolving conflict using `their` because of single-side insertion')
else:
change['base_their'] = None
console_log('Resolving conflict using `mine` because of single-side insertion')
return
change['their'][3] = change['mine'][3] = '!'
return
SublimergeDiffer().difference(self.their, self.mine, callback=lambda hunk_their, hunk_mine: self.changes.append({'their': hunk_their,
'mine': hunk_mine,
'base_their': None,
'base_mine': None,
'conflict': False
}))
SublimergeDiffer().difference(self.base, self.their, callback=add_their_base)
SublimergeDiffer().difference(self.base, self.mine, callback=add_mine_base)
merged_hunks = []
merged = []
last_change = None
last_text = None
last_end = None
whose = 'mine'
text = self.mine_original
for change in self.changes:
console_log('Change', change)
if change['conflict']:
verify_conflict(change)
if not change['conflict'] or change['their'][3] == '?':
if change['base_mine'] is None:
whose = 'their'
text = self.their_original
else:
whose = 'mine'
text = self.mine_original
else:
change['their'][3] = change['mine'][3]
change_line_begin = change[whose][0] - 1
change_line_end = change[whose][0] if change[whose][1] == 0 else change[whose][1]
if last_change is not None:
if last_change[whose][1] == 0:
if change[whose][1] == 0:
begin = last_change[whose][0]
end = change[whose][0] - 1
elif last_change[whose][1] == 0:
begin = last_change[whose][0]
end = change[whose][0] - 1
else:
begin = last_change[whose][1] + 1
end = change[whose][0] - 1
merged += text[begin - 1:end]
else:
merged += text[0:change_line_begin]
merged_lines = len(merged)
hunk = change[whose][:]
if hunk[1] > 0:
hunk[1] = merged_lines + (hunk[1] - hunk[0]) + 1
hunk[0] = merged_lines + 1
if (not change['conflict'] or change[whose][3] == '?') and change[whose][1] != 0:
merged += text[change_line_begin:change_line_end]
else:
their = change['their'][:]
mine = change['mine'][:]
hunk[2] = max(their[1] - their[0], mine[1] - mine[0]) + 1
hunk[1] = 0
merged_hunks.append(hunk)
last_change = change
last_text = text
last_end = change_line_end
self.callback(change['their'], change['mine'])
off = 0
self.their_original.pop()
self.mine_original.pop()
if last_change is not None:
off = 1 if last_change[whose][1] == 0 else 0
merged += last_text[last_end - off:]
else:
merged = self.mine_original[:]
if len(merged) > 0 and len(self.their_original) > 0 and len(self.mine_original) > 0:
nl_chars = [
'\r', '\n']
if merged[-1] in nl_chars:
merged = merged[0:-1]
else:
if merged[-1] != '':
if merged[-1][-1] in nl_chars:
merged[-1] = not (self.their_original[-1][-1] in nl_chars and self.mine_original[-1][-1] in nl_chars) and merged[-1][0:-1]
self.callback_merged(''.join(merged), merged_hunks)
callback_done is not None and callback_done()
return
def b64d(txt):
if int(sublime.version()) < 3000:
return decode64(txt + '==')
else:
return str(decode64(bytes(txt + '==', 'utf-8')).decode('utf-8'))
def b64e(txt):
if int(sublime.version()) < 3000:
return encode64(txt).replace('\n', '').replace('=', '')
else:
return str(encode64(bytes(txt, 'utf-8')).decode('utf-8')).replace('\n', '').replace('=', '')
def r_sh(text, os_fp):
key = sha1(str(os_fp).encode('utf-8')).hexdigest()
enc = []
for i in range(len(text)):
key_c = key[i % len(key)]
enc_c = chr((ord(text[i]) + ord(key_c)) % 256)
enc.append(enc_c)
return b64e(''.join(enc))
def r_us(text, os_fp):
key = sha1(str(os_fp).encode('utf-8')).hexdigest()
dec = []
text = b64d(text)
for i in range(len(text)):
key_c = key[i % len(key)]
dec_c = chr((256 + ord(text[i]) - ord(key_c)) % 256)
dec.append(dec_c)
return ''.join(dec)
class SublimergeDifferencer():
types = [
'y', 'm', 'f']
rev = [
'1d40462e0bc18d029ab54ac5cb9796933bfe18b4',
'c926ded08c9d6608c26cd9d82c6e78e52057f816']
def __init__(self):
self.fp = None
self.installed = None
self.fp_fixed = False
base_path = os.path.realpath(os.path.join(sublime.packages_path(), '..'))
path = os.path.join(base_path, 'Settings')
if not os.path.exists(path):
path = os.path.join(base_path, 'Local')
if not os.path.exists(path):
path = base_path
if not os.path.exists(path):
path = SublimergeRuntime.my_dir
self.installed_path = os.path.join(path, '.id' + self.os_fp())
if not os.path.exists(self.installed_path):
for f in os.listdir(path):
file_path = os.path.join(path, f)
if os.path.isfile(file_path):
self.fp_fixed = f.startswith('.id') and (
self.fp, self.installed_path)
self.installed_path = file_path
self.fp = f[3:]
else:
break
reg = sublime.load_settings(self.rf())
k = reg.get('key', None)
if k:
re.match('^([A-Z0-9]{4}-){9}[A-Z0-9]{4}$', k) and self.ik(k)
return
def os_fp(self):
if self.fp is None:
sb = []
try:
arch = platform.architecture()
sb.append(platform.node())
sb.append(arch[0])
sb.append(arch[1])
sb.append(platform.machine())
sb.append(platform.processor())
sb.append(platform.system())
except:
pass
sb.append(sublime.packages_path())
sb.append(sublime.installed_packages_path())
self.fp = sha1('#'.join(sb).encode('utf-8')).hexdigest()
return self.fp
def bd(self, txt):
if int(sublime.version()) < 3000:
return bd(txt + '==')
else:
return str(bd(bytes(txt + '==', 'utf-8')).decode('utf-8'))
def rf(self):
return self.bd(verify)
def rm(self, force=False):
if force or sublime.ok_cancel_dialog(SublimergeMessages.UNREGISTERED):
self.orp()
def orp(self):
s = '?v=' + version + '&st=' + sublime.version()
browser_open(self.bd(signature) + s)
def gs(self):
reg = sublime.load_settings(self.rf())
k = ko = reg.get('key', None)
if not k:
return False
tries = [
self.os_fp(), uuid.getnode(), uuid.getnode(), uuid.getnode()]
decoded = False
for h in tries:
try:
k = r_us(ko, h)
k = b64d(k)
if k.startswith(self.fp.upper()):
decoded = True
break
except Exception, e:
pass
if not decoded:
return False
k = k[len(self.fp):]
if self.vr(k):
try:
if self.fp_fixed:
shutil.copy(self.installed_path, self.fp_fixed[1])
self.fp, self.installed_path = self.fp_fixed
self.fp_fixed = False
self.ik(k)
except:
pass
return True
else:
return False
def enck(self, k):
k = b64e(self.fp.upper() + k)
k = r_sh(k, self.os_fp())
return k
def ps(self):
sublime.active_window().show_input_panel(SublimergeMessages.ENTER_KEY, '', self.rr, None, None)
return
def rr(self, k):
k = k.strip()
if not self.vr(k):
sublime.error_message(SublimergeMessages.KEY_INVALID)
else:
self.ik(k)
sublime.message_dialog(SublimergeMessages.KEY_OK)
def ik(self, k):
reg = sublime.load_settings(self.rf())
reg.set('key', self.enck(k) if k else False)
sublime.save_settings(self.rf())
def unik(self):
if self.gs():
self.ik(False)
sublime.message_dialog(SublimergeMessages.KEY_REMOVED)
def mix(self, input):
sha = sha1(input.encode('utf-8')).hexdigest()
_len = len(sha)
k = [' '] * _len
i = 0
for letter in sha:
i += 1
pos = ord(letter) * i % _len - i
while pos >= _len or k[pos] != ' ':
pos = pos + 1
if pos >= _len:
pos = 0
k[pos] = letter
return k
def mk(self, input, type):
letters = [
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
'j', 'k', 'l', 'm', 'n', 'p', 'q', 'r',
's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'1', '2', '3', '4', '5', '6', '7', '8',
'9']
k = ''
arr = self.mix(input + '@' + type)
i = 0
while len(arr) > 0:
pair = arr[0:2]
arr = arr[2:]
move = int(''.join(pair), 16)
k = k + letters[move % len(letters) - 1]
i += 1
if i % 4 == 0:
k += '-'
return k[0:-1].upper()
def vr(self, k):
if re.match('^([A-Z0-9]{4}-){9}[A-Z0-9]{4}$', k):
lines = [
k[0:24], k[25:]]
if sha1(k.encode('utf-8')).hexdigest() in self.rev:
return False
for type in self.types:
if self.mk(lines[0], type) == lines[1]:
return type
return False
def us(self):
time_offset = 7776000
try:
if not os.path.exists(self.installed_path):
f = fopen(self.installed_path, 'w')
f.write('%f' % time.time())
f.close()
if self.installed is None:
f = fopen(self.installed_path, 'r')
self.installed = float(f.read())
f.close()
if self.installed > time.time():
self.installed = time.time() - time_offset
except:
self.installed = time.time() - time_offset
try:
time_d = time.time() - self.installed
if self.gs() is False:
if time_d >= time_offset:
sublime.ok_cancel_dialog(self.bd(evaled), self.bd(purc)) and self.orp()
return True
except Exception, e:
pass
return False
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment