From 5e7bcbc3ab0cae84289ef0309ff997ac15f8bec7 Mon Sep 17 00:00:00 2001 From: Mikhail Veltishchev Date: Thu, 4 Jul 2013 13:05:41 +0400 Subject: [PATCH 1/5] First attempt to fix issue #16 (Unversioned files) Implemented for git only. --- icons/unknown.png | Bin 0 -> 185 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100755 icons/unknown.png diff --git a/icons/unknown.png b/icons/unknown.png new file mode 100755 index 0000000000000000000000000000000000000000..4f94ca04f0efbbba5f46b3ada7f24ca856ea1121 GIT binary patch literal 185 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|*pj^6U4S$Y z{B+)352QE?JR*x37`TN&n2}-D90{Nxdx@v7EBjq`W-b=R=f!QxKp{&{7sn8b)5!@E zpBe Date: Thu, 4 Jul 2013 13:07:53 +0400 Subject: [PATCH 2/5] First attempt to fix #16 (Show not tracked files) For git only. --- .gitignore | 5 +++- gutter_handlers.py | 70 ++++++++++++++++++++++++++++++++++++---------- vcs_gutter.py | 14 ++++++++-- view_collection.py | 13 +++++++++ 4 files changed, 84 insertions(+), 18 deletions(-) diff --git a/.gitignore b/.gitignore index 6301be49..2be7ed60 100644 --- a/.gitignore +++ b/.gitignore @@ -32,4 +32,7 @@ nosetests.xml # Mr Developer .mr.developer.cfg .project -.pydevproject \ No newline at end of file +.pydevproject + +# Special file for testing ignored files +testfile-for-gitignore diff --git a/gutter_handlers.py b/gutter_handlers.py index 6d2bca4c..1ff2b3a5 100644 --- a/gutter_handlers.py +++ b/gutter_handlers.py @@ -46,7 +46,7 @@ def update_buf_file(self): except UnicodeError: # Fallback to utf8-encoding contents = self.view.substr(region).encode('utf-8') - + contents = contents.replace('\r\n', '\n') contents = contents.replace('\r', '\n') f = open(self.buf_temp_file.name, 'w') @@ -66,16 +66,30 @@ 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: + # XY file-name + 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('\r\n', '\n') - contents = contents.replace('\r', '\n') - f = open(self.vcs_temp_file.name, 'w') - f.write(contents) - f.close() - ViewCollection.update_vcs_time(self.view) - except Exception: + if status == 'M': + contents, errors = self.run_command(args) + contents = contents.replace('\r\n', '\n') + contents = contents.replace('\r', '\n') + # TODO: remove copy-and-paste here + f = open(self.vcs_temp_file.name, 'w') + f.write(contents) + f.close() + ViewCollection.update_vcs_time(self.view) + except Exception as e: + # print e pass def process_diff(self, diff_str): @@ -108,9 +122,12 @@ 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 ([], [], []) + if ViewCollection.vcs_status(self.view) == 'U': + # use special region 'unknown' + 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: @@ -121,19 +138,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): @@ -150,6 +168,28 @@ def get_diff_args(self): ] return args + def get_status_args(self): + args = [ + 'git', + '--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): diff --git a/vcs_gutter.py b/vcs_gutter.py index 0a3c1bf0..b5c61aa1 100644 --- a/vcs_gutter.py +++ b/vcs_gutter.py @@ -11,7 +11,7 @@ def run(self): # and it throws an error because self.view is None. # I have only been able to reproduce this in the following scenario: # you clicked on FileA in the sidebar (FileA is not previously open) - # + # # not to open it but to preview it. While previewing it you press # ctrl+` to open a console. With the console selected and the # unopened FileA preview showing in the window you click on another @@ -23,16 +23,18 @@ def run(self): # Wow that was a really long explanation. return self.clear_all() - inserted, modified, deleted = ViewCollection.diff(self.view) + inserted, modified, deleted, unknown = ViewCollection.diff(self.view) self.lines_removed(deleted) self.lines_added(inserted) self.lines_modified(modified) + self.lines_unknown(unknown) def clear_all(self): self.view.erase_regions('vcs_gutter_deleted_top') self.view.erase_regions('vcs_gutter_deleted_bottom') self.view.erase_regions('vcs_gutter_inserted') self.view.erase_regions('vcs_gutter_changed') + self.view.erase_regions('vcs_gutter_unknown') def lines_to_regions(self, lines): regions = [] @@ -68,6 +70,14 @@ def lines_added(self, lines): icon = '../VCS Gutter/icons/inserted' self.view.add_regions('vcs_gutter_inserted', regions, scope, icon) + def lines_unknown(self, lines): + regions = self.lines_to_regions(lines) + scope = 'markup.changed' + icon = '../VCS Gutter/icons/unknown' + self.view.add_regions('vcs_gutter_unknown', regions, scope, icon) + + + def lines_modified(self, lines): regions = self.lines_to_regions(lines) scope = 'markup.changed' diff --git a/view_collection.py b/view_collection.py index 888da263..c63fa90b 100644 --- a/view_collection.py +++ b/view_collection.py @@ -9,6 +9,7 @@ class ViewCollection: views = {} vcs_times = {} + vcs_statuses = {} vcs_files = {} buf_files = {} @@ -57,11 +58,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) From 4851d1ae03cef4df3e0819e5383e69d3fa6c8d39 Mon Sep 17 00:00:00 2001 From: Mikhail Veltishchev Date: Thu, 4 Jul 2013 14:01:40 +0400 Subject: [PATCH 3/5] Issue #16: Added hg support --- gutter_handlers.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/gutter_handlers.py b/gutter_handlers.py index f7d4f915..6b3423f6 100644 --- a/gutter_handlers.py +++ b/gutter_handlers.py @@ -219,6 +219,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', + 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): From f758013cd54a3b1fd85d6536e515e399e76d71c4 Mon Sep 17 00:00:00 2001 From: Mikhail Veltishchev Date: Thu, 4 Jul 2013 16:24:39 +0400 Subject: [PATCH 4/5] SVN support for #16. --- gutter_handlers.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/gutter_handlers.py b/gutter_handlers.py index 6b3423f6..2fe190d2 100644 --- a/gutter_handlers.py +++ b/gutter_handlers.py @@ -84,7 +84,6 @@ def update_vcs_file(self): status_args = self.get_status_args() status = None try: - # XY file-name contents, errors = self.run_command(status_args) status = self.process_status_line(contents) ViewCollection.update_vcs_status(self.view, status) @@ -257,3 +256,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 From 11d94b32779e1bffc482a000481b1311225c7773 Mon Sep 17 00:00:00 2001 From: Mikhail Veltishchev Date: Thu, 4 Jul 2013 21:14:39 +0400 Subject: [PATCH 5/5] Fixed #15. --- gutter_handlers.py | 40 +++++++++++++++++++++++++--------------- icons/ignored.png | Bin 0 -> 192 bytes icons/unknown.png | Bin 185 -> 206 bytes vcs_gutter.py | 6 ++++-- 4 files changed, 29 insertions(+), 17 deletions(-) create mode 100755 icons/ignored.png diff --git a/gutter_handlers.py b/gutter_handlers.py index 2fe190d2..f3bfd47c 100644 --- a/gutter_handlers.py +++ b/gutter_handlers.py @@ -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) @@ -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() @@ -95,12 +105,8 @@ def update_vcs_file(self): try: if status == 'M': contents, errors = self.run_command(args) - contents = contents.replace(b'\r\n', b'\n') - contents = contents.replace(b'\r', b'\n') - # TODO: remove copy-and-paste here - f = open(self.vcs_temp_file.name, 'wb') - f.write(contents) - f.close() + 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) @@ -135,12 +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 - if ViewCollection.vcs_status(self.view) == 'U': + status = ViewCollection.vcs_status(self.view) + if status == 'U': # use special region 'unknown' - return ([], [], [], inserted) - return (inserted, modified, deleted, []) + 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: @@ -230,7 +240,7 @@ def get_status_args(self): '--ignored', '--color', 'never', - self.vcs_path, + os.path.join(self.vcs_tree, self.vcs_path), ] return args diff --git a/icons/ignored.png b/icons/ignored.png new file mode 100755 index 0000000000000000000000000000000000000000..eed3c3eda8ae0775c912062b22685315c3a8aab4 GIT binary patch literal 192 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}Y)RhkEzopr0L48uK>z>% literal 0 HcmV?d00001 diff --git a/icons/unknown.png b/icons/unknown.png index 4f94ca04f0efbbba5f46b3ada7f24ca856ea1121..7ccda2be936f27e2514938834fe509c87c9a0ded 100755 GIT binary patch delta 152 zcmdnVc#cuAGr-TCmrII^fq{Y7)59eQNGpIa2OE$quB!SnQPDn+MUaP$o#ku>P{_~I z#W5t}@Y_p{d<+5t&KD&M|7%}A#-*5e=umxi6t6MEkGbz^db^H*qGa8FW`+hPu4U>!vk$uY0!?P{boFyt=akR{04o+U Ac>n+a delta 131 zcmX@dxRX(_Gr-TCmrII^fq{Y7)59eQNDF{42OE%-|NK93qN05yGZ%~E^WrvTppd1f zi(`nz>Er~7PYr_8kNgLM#TqFoDJr)@O3waY$S^xfZOu8Qqh?7l&8NQ|TsSlHgW80| d2dujo8TxbeAH1->_6TSQgQu&X%Q~loCICy5FM9w0 diff --git a/vcs_gutter.py b/vcs_gutter.py index b02d5168..df3c605e 100644 --- a/vcs_gutter.py +++ b/vcs_gutter.py @@ -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() @@ -31,11 +32,12 @@ def run(self): sublime.set_timeout(self.run, 1) return self.clear_all() - inserted, modified, deleted, unknown = 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: