<commit_before>import sublime
from sublime_plugin import WindowCommand
from ..git_command import GitCommand
from .log import GsLogBase
from ...common import util
from ...common.quick_panel import show_paginated_panel


PADDING = "                                                "
GIT_RESET_MODES = [
    # See analysis at http://stackoverflow.com/questions/34149356/what-exactly-is-the-difference-between-all-the-git-reset-modes/34155307#34155307
    ["--mixed" + PADDING, "unstage staged, keep unstaged, don't touch working (safe)"],
    ["--soft", "just move HEAD, stage differences (safe)"],
    ["--hard", "discard staged, discard unstaged, update working (unsafe)"],
    ["--merge", "discard staged, keep unstaged, update working (abort if unsafe)"],
    ["--keep", "unstage staged, keep unstaged, update working (abort if unsafe)"]
    # For reference, in case we ever include the (very similar) checkout command
    # ["--checkout", "keep staged, keep unstaged, update working, move branches (abort if unsafe)"]
]


class GsResetBase(WindowCommand, GitCommand):

    def do_action(self, commit_hash):
        self._selected_hash = commit_hash

        use_reset_mode = sublime.load_settings("GitSavvy.sublime-settings").get("use_reset_mode")
        if use_reset_mode:
            self.on_reset(use_reset_mode)
        else:
            self.window.show_quick_panel(
                GIT_RESET_MODES, self.on_reset_mode_selection, flags=sublime.MONOSPACE_FONT
            )

    def on_reset_mode_selection(self, index):
        if index == -1:
            sublime.set_timeout_async(self.run_async, 1)
        elif 0 <= index < len(GIT_RESET_MODES):
            self.on_reset(GIT_RESET_MODES[index][0].strip())

    def on_reset(self, reset_mode):
        # Split the reset mode to support multiple args, e.g. "--mixed -N"
        args = reset_mode.split() + [self._selected_hash]

        def do_reset():
            self.git("reset", *args)

        if reset_mode == "--hard":
            util.actions.destructive("perform a hard reset")(do_reset)()
        else:
            do_reset()


class GsResetCommand(GsResetBase, GsLogBase):

    pass


class GsResetBranch(GsResetBase, GsLogBase):

    def run_async(self):
        self.all_branches = [b.name_with_remote for b in self.get_branches()]

        if hasattr(self, '_selected_branch') and self._selected_branch in self.all_branches:
            pre_selected_index = self.all_branches.index(self._selected_branch)
        else:
            pre_selected_index = self.all_branches.index(self.get_current_branch_name())

        self.window.show_quick_panel(
            self.all_branches,
            self.on_branch_selection,
            flags=sublime.MONOSPACE_FONT,
            selected_index=pre_selected_index
        )

    def on_branch_selection(self, index):
        if index == -1:
            return
        self._selected_branch = self.all_branches[index]
        self.do_action(self._selected_branch)


class GsResetReflogCommand(GsResetBase):

    _limit = 6000

    def run(self):
        sublime.set_timeout_async(self.run_async)

    def run_async(self):
        self._hashes = []
        show_paginated_panel(self.log_generator(), self.on_done, self._limit)

    def log_generator(self):
        self._skip = 0
        while True:
            log_output = self.git(
                "reflog",
                "-{}".format(self._limit),
                "--skip={}".format(self._skip),
                '--format=%h%n%H%n%s%n%gs%n%gd%n%an%n%at%x00'
            ).strip("\x00")

            entries = log_output.split("\x00")
            for entry in entries:
                try:
                    short_hash, long_hash, summary, reflog_name, reflog_selector, author, datetime \
                        = (entry.strip("\n").split("\n"))
                    self._hashes.append(long_hash)
                    yield [
                        reflog_selector + " " + reflog_name,
                        short_hash + " " + summary,
                        author + ", " + util.dates.fuzzy(datetime)
                    ]

                except ValueError:
                    # Empty line - less expensive to catch the exception once than
                    # to check truthiness of entry.strip() each time.
                    pass

            # if `entries` does not contin "\x00", stop the loop
            if len(entries) == 1:
                break

            self._skip = self._skip + self._limit

    def on_done(self, index):
        if index == -1:
            return
        self.do_action(self._hashes[self._skip + index])<commit_msg>Enhancement: better use of show_paginated_panel in GsResetReflogCommand<commit_after>import sublime
from sublime_plugin import WindowCommand
from ..git_command import GitCommand
from .log import GsLogBase
from ...common import util
from ...common.quick_panel import show_paginated_panel


PADDING = "                                                "
GIT_RESET_MODES = [
    # See analysis at http://stackoverflow.com/questions/34149356/what-exactly-is-the-difference-between-all-the-git-reset-modes/34155307#34155307
    ["--mixed" + PADDING, "unstage staged, keep unstaged, don't touch working (safe)"],
    ["--soft", "just move HEAD, stage differences (safe)"],
    ["--hard", "discard staged, discard unstaged, update working (unsafe)"],
    ["--merge", "discard staged, keep unstaged, update working (abort if unsafe)"],
    ["--keep", "unstage staged, keep unstaged, update working (abort if unsafe)"]
    # For reference, in case we ever include the (very similar) checkout command
    # ["--checkout", "keep staged, keep unstaged, update working, move branches (abort if unsafe)"]
]


class GsResetBase(WindowCommand, GitCommand):

    def do_action(self, commit_hash):
        self._selected_hash = commit_hash

        use_reset_mode = sublime.load_settings("GitSavvy.sublime-settings").get("use_reset_mode")
        if use_reset_mode:
            self.on_reset(use_reset_mode)
        else:
            self.window.show_quick_panel(
                GIT_RESET_MODES, self.on_reset_mode_selection, flags=sublime.MONOSPACE_FONT
            )

    def on_reset_mode_selection(self, index):
        if index == -1:
            sublime.set_timeout_async(self.run_async, 1)
        elif 0 <= index < len(GIT_RESET_MODES):
            self.on_reset(GIT_RESET_MODES[index][0].strip())

    def on_reset(self, reset_mode):
        # Split the reset mode to support multiple args, e.g. "--mixed -N"
        args = reset_mode.split() + [self._selected_hash]

        def do_reset():
            self.git("reset", *args)

        if reset_mode == "--hard":
            util.actions.destructive("perform a hard reset")(do_reset)()
        else:
            do_reset()


class GsResetCommand(GsResetBase, GsLogBase):

    pass


class GsResetBranch(GsResetBase, GsLogBase):

    def run_async(self):
        self.all_branches = [b.name_with_remote for b in self.get_branches()]

        if hasattr(self, '_selected_branch') and self._selected_branch in self.all_branches:
            pre_selected_index = self.all_branches.index(self._selected_branch)
        else:
            pre_selected_index = self.all_branches.index(self.get_current_branch_name())

        self.window.show_quick_panel(
            self.all_branches,
            self.on_branch_selection,
            flags=sublime.MONOSPACE_FONT,
            selected_index=pre_selected_index
        )

    def on_branch_selection(self, index):
        if index == -1:
            return
        self._selected_branch = self.all_branches[index]
        self.do_action(self._selected_branch)


class GsResetReflogCommand(GsResetBase):

    _limit = 6000

    def run(self):
        sublime.set_timeout_async(self.run_async)

    def run_async(self):
        show_paginated_panel(self.log_generator(), self.on_done, limit=self._limit)

    def log_generator(self):
        skip = 0
        while True:
            log_output = self.git(
                "reflog",
                "-{}".format(self._limit),
                "--skip={}".format(skip),
                '--format=%h%n%H%n%s%n%gs%n%gd%n%an%n%at%x00'
            ).strip().strip("\x00")

            entries = log_output.split("\x00\n")
            for entry in entries:
                entry = entry.strip("\n")
                if not entry:
                    continue
                short_hash, long_hash, summary, reflog_name, reflog_selector, author, datetime = \
                    entry.split("\n")
                yield ([reflog_selector + " " + reflog_name,
                        short_hash + " " + summary,
                        author + ", " + util.dates.fuzzy(datetime)],
                       long_hash)

            if len(entries) == 1:
                break

            skip = skip + self._limit

    def on_done(self, commit):
        if commit:
            self.do_action(commit)
{'fraction_non_alphanumeric': 0.10880017891088002, 'fraction_numerical': 0.009504640500950463, 'mean_word_length': 2.201145311381532, 'pattern_counts': {'":': 2, '<': 7, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4701454', 'n_tokens_mistral': 2806, 'n_tokens_neox': 2625, 'n_words': 565}