Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,6 @@ nosetests.xml
.mr.developer.cfg
.project
.pydevproject

# Special file for testing ignored files
testfile-for-gitignore
126 changes: 109 additions & 17 deletions gutter_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,18 @@ def _get_view_encoding(self):
encoding = encoding.replace(' ', '')
return encoding

@staticmethod
def _to_unix(contents):
contents = contents.replace(b'\r\n', b'\n')
contents = contents.replace(b'\r', b'\n')
return contents

@staticmethod
def _write(name, contents):
f = open(name, 'wb')
f.write(contents)
f.close()

def update_buf_file(self):
chars = self.view.size()
region = sublime.Region(0, chars)
Expand All @@ -63,10 +75,8 @@ def update_buf_file(self):
# Fallback to utf8-encoding
contents = self.view.substr(region).encode('utf-8')

contents = contents.replace(b'\r\n', b'\n')
f = open(self.buf_temp_file.name, 'wb')
f.write(contents)
f.close()
contents = VcsGutterHandler._to_unix(contents)
VcsGutterHandler._write(self.buf_temp_file.name, contents)

def total_lines(self):
chars = self.view.size()
Expand All @@ -81,15 +91,23 @@ def update_vcs_file(self):
# between updates for performance
if ViewCollection.vcs_time(self.view) > 5:
open(self.vcs_temp_file.name, 'w').close()
status_args = self.get_status_args()
status = None
try:
contents, errors = self.run_command(status_args)
status = self.process_status_line(contents)
ViewCollection.update_vcs_status(self.view, status)
except Exception as e:
# print e
pass

args = self.get_diff_args()
try:
contents = self.run_command(args)
contents = contents.replace(b'\r\n', b'\n')
contents = contents.replace(b'\r', b'\n')
f = open(self.vcs_temp_file.name, 'wb')
f.write(contents)
f.close()
ViewCollection.update_vcs_time(self.view)
if status == 'M':
contents, errors = self.run_command(args)
contents = VcsGutterHandler._to_unix(contents)
VcsGutterHandler._write(self.vcs_temp_file.name, contents)
ViewCollection.update_vcs_time(self.view)
except Exception as e:
print ("Unable to write file for diff ", e)

Expand Down Expand Up @@ -123,9 +141,16 @@ def process_diff(self, diff_str):
# this means this file is either:
# - New and not being tracked *yet*
# - Or it is a *gitignored* file
return ([], [], [])
status = ViewCollection.vcs_status(self.view)
if status == 'U':
# use special region 'unknown'
return ([], [], [], inserted, [])
elif status == 'I':
# use special region 'ignored'
return ([], [], [], [], inserted)
return (inserted, modified, deleted, [], [])
else:
return (inserted, modified, deleted)
return (inserted, modified, deleted, [], [])

def diff(self):
if self.on_disk() and self.vcs_path:
Expand All @@ -136,19 +161,20 @@ def diff(self):
self.vcs_temp_file.name,
self.buf_temp_file.name,
]
results = self.run_command(args)
results, errors = self.run_command(args)
# print errors
return self.process_diff(results)
else:
return ([], [], [])
return ([], [], [], [])

def run_command(self, args):
startupinfo = None
if os.name == 'nt':
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
proc = subprocess.Popen(args, stdout=subprocess.PIPE,
proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
startupinfo=startupinfo)
return proc.stdout.read()
return proc.stdout.read(), proc.stderr.read()


class GitGutterHandler(VcsGutterHandler):
Expand All @@ -165,6 +191,28 @@ def get_diff_args(self):
]
return args

def get_status_args(self):
args = [
self.exc_path,
'--git-dir=' + self.vcs_dir,
'--work-tree=' + self.vcs_tree,
'status',
'--ignored',
'--porcelain',
self.vcs_path,
]
return args

def process_status_line(self, st):
st = st[0:2]
if st == '!!':
return 'I'
elif st == '??':
return 'U'
else:
return 'M'
# all other states we may consider as modified


class HgGutterHandler(VcsGutterHandler):
def get_vcs_helper(self):
Expand All @@ -180,6 +228,32 @@ def get_diff_args(self):
]
return args

def get_status_args(self):
args = [
self.exc_path,
'--repository',
self.vcs_tree,
'status',
'--added',
'--modified',
'--unknown',
'--ignored',
'--color',
'never',
os.path.join(self.vcs_tree, self.vcs_path),
]
return args

def process_status_line(self, st):
st = st[0:1]
if st == 'I':
return 'I'
elif st == '?':
return 'U'
else:
return 'M'
# all other states we may consider as modified


class SvnGutterHandler(VcsGutterHandler):
def get_vcs_helper(self):
Expand All @@ -192,3 +266,21 @@ def get_diff_args(self):
os.path.join(self.vcs_tree, self.vcs_path),
]
return args

def get_status_args(self):
args = [
self.exc_path,
'status',
os.path.join(self.vcs_tree, self.vcs_path),
]
return args

def process_status_line(self, st):
st = st[0:1]
if st == 'I':
return 'I'
elif st == '?':
return 'U'
else:
return 'M'
# all other states we may consider as modified
Binary file added icons/ignored.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added icons/unknown.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 5 additions & 2 deletions vcs_gutter.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ def plugin_loaded():

class VcsGutterCommand(sublime_plugin.WindowCommand):
region_names = ['deleted_top', 'deleted_bottom',
'deleted_dual', 'inserted', 'changed']
'deleted_dual', 'inserted', 'changed',
'unknown', 'ignored']

def run(self):
self.view = self.window.active_view()
Expand All @@ -31,10 +32,12 @@ def run(self):
sublime.set_timeout(self.run, 1)
return
self.clear_all()
inserted, modified, deleted = ViewCollection.diff(self.view)
inserted, modified, deleted, unknown, ignored = ViewCollection.diff(self.view)
self.lines_removed(deleted)
self.bind_icons('inserted', inserted)
self.bind_icons('changed', modified)
self.bind_icons('unknown', unknown)
self.bind_icons('ignored', ignored)

def clear_all(self):
for region_name in self.region_names:
Expand Down
13 changes: 13 additions & 0 deletions view_collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
class ViewCollection:
views = {}
vcs_times = {}
vcs_statuses = {}
vcs_files = {}
buf_files = {}

Expand Down Expand Up @@ -69,11 +70,23 @@ def vcs_time(view):
ViewCollection.vcs_times[key] = 0
return time.time() - ViewCollection.vcs_times[key]

@staticmethod
def vcs_status(view):
key = ViewCollection.get_key(view)
if not key in ViewCollection.vcs_statuses:
ViewCollection.vcs_statuses[key] = 'M'
return ViewCollection.vcs_statuses[key]

@staticmethod
def update_vcs_time(view):
key = ViewCollection.get_key(view)
ViewCollection.vcs_times[key] = time.time()

@staticmethod
def update_vcs_status(view, status):
key = ViewCollection.get_key(view)
ViewCollection.vcs_statuses[key] = status

@staticmethod
def vcs_tmp_file(view):
key = ViewCollection.get_key(view)
Expand Down