<commit_before>"""
Implements a special view to visualize and stage pieces of a project's
current diff.
"""

import os
import re
import bisect

import sublime
from sublime_plugin import WindowCommand, TextCommand, EventListener

from .navigate import GsNavigate
from ..git_command import GitCommand
from ..exceptions import GitSavvyError
from ...common import util


DIFF_TITLE = "DIFF: {}"
DIFF_CACHED_TITLE = "DIFF (cached): {}"


diff_views = {}


class GsDiffCommand(WindowCommand, GitCommand):

    """
    Create a new view to display the difference of `target_commit`
    against `base_commit`. If `target_commit` is None, compare
    working directory with `base_commit`.  If `in_cached_mode` is set,
    display a diff of the Git index. Set `disable_stage` to True to
    disable Ctrl-Enter in the diff view.
    """

    def run(self, **kwargs):
        sublime.set_timeout_async(lambda: self.run_async(**kwargs), 0)

    def run_async(self, in_cached_mode=False, file_path=None, current_file=False, base_commit=None,
                  target_commit=None, disable_stage=False, title=None):
        repo_path = self.repo_path
        if current_file:
            file_path = self.file_path or file_path

        view_key = "{0}{1}+{2}".format(
            in_cached_mode,
            "-" if base_commit is None else "--" + base_commit,
            file_path or repo_path
        )

        if view_key in diff_views and diff_views[view_key] in sublime.active_window().views():
            diff_view = diff_views[view_key]
        else:
            diff_view = util.view.get_scratch_view(self, "diff", read_only=True)
            if not title:
                title = (DIFF_CACHED_TITLE if in_cached_mode else DIFF_TITLE).format(os.path.basename(repo_path))
            diff_view.set_name(title)
            diff_view.set_syntax_file("Packages/GitSavvy/syntax/diff.sublime-syntax")
            diff_view.settings().set("git_savvy.repo_path", repo_path)
            diff_view.settings().set("git_savvy.file_path", file_path)
            diff_view.settings().set("git_savvy.diff_view.in_cached_mode", in_cached_mode)
            diff_view.settings().set("git_savvy.diff_view.ignore_whitespace", False)
            diff_view.settings().set("git_savvy.diff_view.show_word_diff", False)
            diff_view.settings().set("git_savvy.diff_view.base_commit", base_commit)
            diff_view.settings().set("git_savvy.diff_view.target_commit", target_commit)
            diff_view.settings().set("git_savvy.diff_view.disable_stage", disable_stage)
            diff_views[view_key] = diff_view

        self.window.focus_view(diff_view)
        diff_view.sel().clear()
        diff_view.run_command("gs_diff_refresh")


class GsDiffRefreshCommand(TextCommand, GitCommand):

    """
    Refresh the diff view with the latest repo state.
    """

    def run(self, edit, cursors=None):
        if self.view.settings().get("git_savvy.disable_diff"):
            return
        in_cached_mode = self.view.settings().get("git_savvy.diff_view.in_cached_mode")
        ignore_whitespace = self.view.settings().get("git_savvy.diff_view.ignore_whitespace")
        show_word_diff = self.view.settings().get("git_savvy.diff_view.show_word_diff")
        base_commit = self.view.settings().get("git_savvy.diff_view.base_commit")
        target_commit = self.view.settings().get("git_savvy.diff_view.target_commit")

        try:
            stdout = self.git(
                "diff",
                "--ignore-all-space" if ignore_whitespace else None,
                "--word-diff" if show_word_diff else None,
                "--no-color",
                "--cached" if in_cached_mode else None,
                base_commit,
                target_commit,
                "--", self.file_path)
        except GitSavvyError as err:
            # When the output of the above Git command fails to correctly parse,
            # the expected notification will be displayed to the user.  However,
            # once the userpresses OK, a new refresh event will be triggered on
            # the view.
            #
            # This causes an infinite loop of increasingly frustrating error
            # messages, ultimately resulting in psychosis and serious medical
            # bills.  This is a better, though somewhat cludgy, alternative.
            #
            if err.args and type(err.args[0]) == UnicodeDecodeError:
                self.view.settings().set("git_savvy.disable_diff", True)
                return
            raise err

        self.view.run_command("gs_replace_view_text", {"text": stdout})
        self.view.run_command("gs_diff_navigate")


class GsDiffToggleSetting(TextCommand):

    """
    Toggle view settings: `ignore_whitespace` or `show_word_diff`.
    """

    def run(self, edit, setting):
        setting_str = "git_savvy.diff_view.{}".format(setting)
        settings = self.view.settings()
        settings.set(setting_str, not settings.get(setting_str))
        print("{} is now {}".format(setting, settings.get(setting_str)))
        self.view.run_command("gs_diff_refresh")

<commit_msg>Fix: only trigger gs_diff_navigate when initialization<commit_after>"""
Implements a special view to visualize and stage pieces of a project's
current diff.
"""

import os
import re
import bisect

import sublime
from sublime_plugin import WindowCommand, TextCommand, EventListener

from .navigate import GsNavigate
from ..git_command import GitCommand
from ..exceptions import GitSavvyError
from ...common import util


DIFF_TITLE = "DIFF: {}"
DIFF_CACHED_TITLE = "DIFF (cached): {}"


diff_views = {}


class GsDiffCommand(WindowCommand, GitCommand):

    """
    Create a new view to display the difference of `target_commit`
    against `base_commit`. If `target_commit` is None, compare
    working directory with `base_commit`.  If `in_cached_mode` is set,
    display a diff of the Git index. Set `disable_stage` to True to
    disable Ctrl-Enter in the diff view.
    """

    def run(self, **kwargs):
        sublime.set_timeout_async(lambda: self.run_async(**kwargs), 0)

    def run_async(self, in_cached_mode=False, file_path=None, current_file=False, base_commit=None,
                  target_commit=None, disable_stage=False, title=None):
        repo_path = self.repo_path
        if current_file:
            file_path = self.file_path or file_path

        view_key = "{0}{1}+{2}".format(
            in_cached_mode,
            "-" if base_commit is None else "--" + base_commit,
            file_path or repo_path
        )

        if view_key in diff_views and diff_views[view_key] in sublime.active_window().views():
            diff_view = diff_views[view_key]
        else:
            diff_view = util.view.get_scratch_view(self, "diff", read_only=True)
            if not title:
                title = (DIFF_CACHED_TITLE if in_cached_mode else DIFF_TITLE).format(os.path.basename(repo_path))
            diff_view.set_name(title)
            diff_view.set_syntax_file("Packages/GitSavvy/syntax/diff.sublime-syntax")
            diff_view.settings().set("git_savvy.repo_path", repo_path)
            diff_view.settings().set("git_savvy.file_path", file_path)
            diff_view.settings().set("git_savvy.diff_view.in_cached_mode", in_cached_mode)
            diff_view.settings().set("git_savvy.diff_view.ignore_whitespace", False)
            diff_view.settings().set("git_savvy.diff_view.show_word_diff", False)
            diff_view.settings().set("git_savvy.diff_view.base_commit", base_commit)
            diff_view.settings().set("git_savvy.diff_view.target_commit", target_commit)
            diff_view.settings().set("git_savvy.diff_view.disable_stage", disable_stage)
            diff_views[view_key] = diff_view

        self.window.focus_view(diff_view)
        diff_view.sel().clear()
        diff_view.run_command("gs_diff_refresh")
        diff_view.run_command("gs_diff_navigate")


class GsDiffRefreshCommand(TextCommand, GitCommand):

    """
    Refresh the diff view with the latest repo state.
    """

    def run(self, edit, cursors=None):
        if self.view.settings().get("git_savvy.disable_diff"):
            return
        in_cached_mode = self.view.settings().get("git_savvy.diff_view.in_cached_mode")
        ignore_whitespace = self.view.settings().get("git_savvy.diff_view.ignore_whitespace")
        show_word_diff = self.view.settings().get("git_savvy.diff_view.show_word_diff")
        base_commit = self.view.settings().get("git_savvy.diff_view.base_commit")
        target_commit = self.view.settings().get("git_savvy.diff_view.target_commit")

        try:
            stdout = self.git(
                "diff",
                "--ignore-all-space" if ignore_whitespace else None,
                "--word-diff" if show_word_diff else None,
                "--no-color",
                "--cached" if in_cached_mode else None,
                base_commit,
                target_commit,
                "--", self.file_path)
        except GitSavvyError as err:
            # When the output of the above Git command fails to correctly parse,
            # the expected notification will be displayed to the user.  However,
            # once the userpresses OK, a new refresh event will be triggered on
            # the view.
            #
            # This causes an infinite loop of increasingly frustrating error
            # messages, ultimately resulting in psychosis and serious medical
            # bills.  This is a better, though somewhat cludgy, alternative.
            #
            if err.args and type(err.args[0]) == UnicodeDecodeError:
                self.view.settings().set("git_savvy.disable_diff", True)
                return
            raise err

        self.view.run_command("gs_replace_view_text", {"text": stdout})


class GsDiffToggleSetting(TextCommand):

    """
    Toggle view settings: `ignore_whitespace` or `show_word_diff`.
    """

    def run(self, edit, setting):
        setting_str = "git_savvy.diff_view.{}".format(setting)
        settings = self.view.settings()
        settings.set(setting_str, not settings.get(setting_str))
        print("{} is now {}".format(setting, settings.get(setting_str)))
        self.view.run_command("gs_diff_refresh")


{'fraction_non_alphanumeric': 0.10259399591955698, 'fraction_numerical': 0.000971534052268532, 'mean_word_length': 2.7095495495495494, 'pattern_counts': {'":': 2, '<': 3, '<?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': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3474672', 'n_tokens_mistral': 3153, 'n_tokens_neox': 3015, 'n_words': 677}