diff --git a/.gitignore b/.gitignore index d2d6f360..2d06ecac 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,7 @@ nosetests.xml .mr.developer.cfg .project .pydevproject + +# Sublime Text +*.sublime-workspace +*.vcs-cache diff --git a/git_gutter.py b/git_gutter.py index 925df7d6..97690bcd 100644 --- a/git_gutter.py +++ b/git_gutter.py @@ -1,4 +1,4 @@ -from sublime_plugin import TextCommand +import sublime_plugin try: from .git_gutter_settings import settings @@ -10,7 +10,7 @@ from .git_gutter_jump_to_changes import GitGutterJumpToChanges from .git_gutter_popup import show_diff_popup from .git_gutter_show_diff import GitGutterShowDiff -except (ImportError, ValueError): +except ValueError: from git_gutter_settings import settings from git_gutter_handler import GitGutterHandler from git_gutter_compare import ( @@ -22,9 +22,10 @@ from git_gutter_show_diff import GitGutterShowDiff -class GitGutterCommand(TextCommand): +class GitGutterCommand(sublime_plugin.TextCommand): def __init__(self, *args, **kwargs): - TextCommand.__init__(self, *args, **kwargs) + """Initialize GitGutterCommand object.""" + sublime_plugin.TextCommand.__init__(self, *args, **kwargs) self.git_handler = GitGutterHandler(self.view) self.show_diff_handler = GitGutterShowDiff(self.git_handler) # Last enabled state for change detection @@ -51,12 +52,12 @@ def is_enabled(self, **kwargs): elif view.settings().get("repl"): valid = False # Don't handle binary files - elif view.encoding() in ('Hexadecimal'): + elif view.encoding() == 'Hexadecimal': valid = False else: # Validate work tree on certain events only validate = any(event in ('load', 'activated', 'post-save') - for event in kwargs.get('event_type', [])) + for event in kwargs.get('event_type', [])) # Don't handle files outside a repository if not self.git_handler.work_tree(validate): valid = False @@ -119,7 +120,7 @@ def _handle_subcommand(self, **kwargs): assert False, 'Unhandled sub command "%s"' % action -class GitGutterBaseCommand(TextCommand): +class GitGutterBaseCommand(sublime_plugin.TextCommand): def is_enabled(self, **kwargs): return self.view.settings().get('git_gutter_enabled', False) diff --git a/git_gutter_compare.py b/git_gutter_compare.py index a2fa4969..59bbcc2c 100644 --- a/git_gutter_compare.py +++ b/git_gutter_compare.py @@ -1,5 +1,4 @@ -from functools import partial - +import functools import sublime @@ -26,7 +25,7 @@ def item_to_commit(self, item): def _show_quick_panel(self, results): if results: self.git_handler.view.window().show_quick_panel( - results, partial(self._on_select, results)) + results, functools.partial(self._on_select, results)) def _on_select(self, results, selected): if 0 > selected < len(results): diff --git a/git_gutter_events.py b/git_gutter_events.py index d727f337..92fe8ce9 100644 --- a/git_gutter_events.py +++ b/git_gutter_events.py @@ -5,7 +5,7 @@ try: from .git_gutter_settings import settings -except (ImportError, ValueError): +except ValueError: from git_gutter_settings import settings try: diff --git a/git_gutter_handler.py b/git_gutter_handler.py index 2da2a8ef..ae52afe9 100644 --- a/git_gutter_handler.py +++ b/git_gutter_handler.py @@ -1,35 +1,34 @@ +import codecs import os.path -import subprocess import re -import codecs -import functools +import subprocess import tempfile import zipfile try: from io import BytesIO -except (ImportError, ValueError): +except ImportError: from cStringIO import StringIO as BytesIO +try: + from subprocess import TimeoutExpired + _HAVE_TIMEOUT = True +except ImportError: + class TimeoutExpired(Exception): + pass + _HAVE_TIMEOUT = False + import sublime try: from .git_gutter_settings import settings from .modules import path from .modules.promise import Promise -except (ImportError, ValueError): +except ValueError: from git_gutter_settings import settings from modules import path from modules.promise import Promise -try: - from subprocess import TimeoutExpired - _HAVE_TIMEOUT = True -except: - class TimeoutExpired(Exception): - pass - _HAVE_TIMEOUT = False - # The view class has a method called 'change_count()' _HAVE_VIEW_CHANGE_COUNT = hasattr(sublime.View, "change_count") @@ -293,7 +292,8 @@ def write_file(output): return self.git_compare_commit(refs).then(check_commit) return check_commit(refs) - def process_diff(self, diff_str): + @staticmethod + def process_diff(diff_str): r"""Parse unified diff with 0 lines of context. Returns: @@ -341,7 +341,6 @@ def process_diff(self, diff_str): def diff_str(self): """Run git diff against view and decode the result then.""" - def decode_diff(results): encoding = self._get_view_encoding() try: @@ -545,6 +544,7 @@ def git_file_commits(self): return self.run_command(args) def git_branches(self): + """Query all branches of the file's repository.""" args = [ settings.git_binary_path, 'for-each-ref', @@ -555,6 +555,7 @@ def git_branches(self): return self.run_command(args) def git_tags(self): + """Query all tags of the file's repository.""" args = [ settings.git_binary_path, 'show-ref', @@ -564,6 +565,7 @@ def git_tags(self): return self.run_command(args) def git_current_branch(self): + """Query the current branch of the file's repository.""" args = [ settings.git_binary_path, 'rev-parse', diff --git a/git_gutter_jump_to_changes.py b/git_gutter_jump_to_changes.py index a35d0994..9c7330fe 100644 --- a/git_gutter_jump_to_changes.py +++ b/git_gutter_jump_to_changes.py @@ -1,6 +1,6 @@ try: from .git_gutter_settings import settings -except (ImportError, ValueError): +except ValueError: from git_gutter_settings import settings diff --git a/git_gutter_popup.py b/git_gutter_popup.py index 8589b28d..5c36146f 100644 --- a/git_gutter_popup.py +++ b/git_gutter_popup.py @@ -3,16 +3,15 @@ try: if int(sublime.version()) < 3080: - raise Exception("No popup available.") + raise ImportError("No popup available.") import difflib import html - from functools import partial + import jinja2 + import mdpopups _MDPOPUPS_INSTALLED = True - import mdpopups - import jinja2 -except: +except ImportError: _MDPOPUPS_INSTALLED = False if _MDPOPUPS_INSTALLED: diff --git a/git_gutter_settings.py b/git_gutter_settings.py index b300857e..58bad958 100644 --- a/git_gutter_settings.py +++ b/git_gutter_settings.py @@ -1,7 +1,7 @@ import os import shutil import sublime -from sublime_plugin import ApplicationCommand +import sublime_plugin STVER = int(sublime.version()) ST3 = STVER >= 3000 @@ -11,13 +11,14 @@ def plugin_loaded(): settings.load_settings() -class GitGutterOpenFileCommand(ApplicationCommand): +class GitGutterOpenFileCommand(sublime_plugin.ApplicationCommand): """This is a wrapper class for SublimeText's `open_file` command. The task is to hide the command in menu if `edit_settings` is available. """ - def run(self, file): + @staticmethod + def run(file): """Expand variables and open the resulting file. NOTE: For some unknown reason the `open_file` command doesn't expand @@ -31,22 +32,25 @@ def run(self, file): file = file.replace('${platform}', platform_name) sublime.run_command('open_file', {'file': file}) - def is_visible(self): + @staticmethod + def is_visible(): """Return True to to show the command in command pallet and menu.""" return STVER < 3124 -class GitGutterEditSettingsCommand(ApplicationCommand): +class GitGutterEditSettingsCommand(sublime_plugin.ApplicationCommand): """This is a wrapper class for SublimeText's `open_file` command. Hides the command in menu if `edit_settings` is not available. """ - def run(self, **kwargs): + @staticmethod + def run(**kwargs): """Expand variables and open the resulting file.""" sublime.run_command('edit_settings', kwargs) - def is_visible(self): + @staticmethod + def is_visible(): """Return True to to show the command in command pallet and menu.""" return STVER >= 3124 diff --git a/git_gutter_show_diff.py b/git_gutter_show_diff.py index ba0ecf67..a0571c39 100644 --- a/git_gutter_show_diff.py +++ b/git_gutter_show_diff.py @@ -1,20 +1,18 @@ -import os -import sublime - try: # avoid exceptions if dependency is not yet satisfied import jinja2.environment _HAVE_JINJA2 = True -except (ImportError, ValueError): +except ImportError: _HAVE_JINJA2 = False +import sublime + try: from .git_gutter_settings import settings -except (ImportError, ValueError): +except ValueError: from git_gutter_settings import settings -ST3 = int(sublime.version()) >= 3000 -_ICON_EXT = '.png' if ST3 else '' +_ICON_EXT = '.png' if int(sublime.version()) >= 3000 else '' class GitGutterShowDiff(object): @@ -168,15 +166,15 @@ def _contents_to_regions(self, contents): return ( # deleted regions self._deleted_lines_to_regions( - first_line, del_lines, lines_regions, protected) + first_line, del_lines, lines_regions, protected) + # inserted regions - + [self._lines_to_regions( - first_line, ins_lines, lines_regions, protected)] + [self._lines_to_regions( + first_line, ins_lines, lines_regions, protected)] + # modified regions - + [self._lines_to_regions( - first_line, mod_lines, lines_regions, protected)] + [self._lines_to_regions( + first_line, mod_lines, lines_regions, protected)] + # untracked / ignored regions - + [] + []) + [] + []) def _get_modified_region(self, first_line, last_line): """Create a list of all line start points in the modified Region. diff --git a/modules/path.py b/modules/path.py index 642197dd..8277951f 100644 --- a/modules/path.py +++ b/modules/path.py @@ -2,6 +2,7 @@ try: from nt import _getfinalpathname + def realpath(path): """Resolve symlinks and return real path to file. diff --git a/modules/promise.py b/modules/promise.py index ec5050bb..121e2693 100644 --- a/modules/promise.py +++ b/modules/promise.py @@ -1,10 +1,11 @@ -from functools import partial -from threading import Lock +import functools +import threading class Promise(object): - """ - A simple implementation of the Promise spec (https://promisesaplus.com/). + """A simple implementation of the Promise specification. + + See: https://promisesaplus.com Promise is in essence a syntactic sugar for callbacks. Simplifies passing values from functions that might do work in asynchronous manner. @@ -47,8 +48,7 @@ def process_value(value): """ def __init__(self, executor): - """ - Creates an instance of Promise. + """Creates an instance of Promise. Arguments: executor: A function that is executed immediately by this Promise. @@ -57,13 +57,14 @@ def __init__(self, executor): """ self.value = None self.resolved = False - self.mutex = Lock() + self.mutex = threading.Lock() self.callbacks = [] self._invoke_executor(executor) @staticmethod def resolve(resolve_value=None): - """ + """Immediatelly resolve a Promise. + Convenience function for creating a Promise that gets immediately resolved with the specified value. @@ -76,8 +77,7 @@ def executor(resolve_fn): return Promise(executor) def then(self, callback): - """ - Creates a new promise and chains it with this promise. + """Creates a new promise and chains it with this promise. When this promise gets resolved, the callback will be called with the value that this promise resolved with. @@ -88,8 +88,7 @@ def then(self, callback): callback: The callback to call when this promise gets resolved. """ def callback_wrapper(resolve_fn, resolve_value): - """ - A wrapper called when this promise resolves. + """A wrapper called when this promise resolves. Arguments: resolve_fn: A resolve function of newly created promise. @@ -104,18 +103,20 @@ def callback_wrapper(resolve_fn, resolve_value): resolve_fn(result) def sync_executor(resolve_fn): - """ + """Call resolve_fn immediately with the resolved value. + An executor that will immediately resolve resolve_fn with the resolved value of this promise. """ callback_wrapper(resolve_fn, self._get_value()) def async_executor(resolve_fn): - """ + """Queue resolve_fn to be called after this promise resolves later. + An executor that will resolve received resolve_fn when this promise resolves later. """ - self._add_callback(partial(callback_wrapper, resolve_fn)) + self._add_callback(functools.partial(callback_wrapper, resolve_fn)) if self._is_resolved(): return Promise(sync_executor) @@ -134,8 +135,8 @@ def _do_resolve(self, new_value): "cannot set the value of an already resolved promise") with self.mutex: self.value = new_value - for cb in self.callbacks: - cb(new_value) + for callback in self.callbacks: + callback(new_value) self.resolved = True def _add_callback(self, callback):