Skip to content

Commit

Permalink
Merge 401aff7 into a37d9b3
Browse files Browse the repository at this point in the history
  • Loading branch information
kaste committed Nov 27, 2018
2 parents a37d9b3 + 401aff7 commit 2910a03
Show file tree
Hide file tree
Showing 20 changed files with 3,126 additions and 115 deletions.
4 changes: 4 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Files and directories with the attribute export-ignore won’t be added to
# archive files. See http://git-scm.com/docs/gitattributes for details.

/tests/ export-ignore
13 changes: 12 additions & 1 deletion common/commands/view_manipulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,13 @@ class GsReplaceViewTextCommand(TextCommand):
a single cursor at the start of the file.
"""

def run(self, edit, text, nuke_cursors=False):
def run(self, edit, text, nuke_cursors=False, restore_cursors=False):
cursors_num = len(self.view.sel())

if restore_cursors:
save_cursors = [self.view.rowcol(s.a) for s in self.view.sel()]
self.view.sel().clear()

is_read_only = self.view.is_read_only()
self.view.set_read_only(False)
self.view.replace(edit, sublime.Region(0, self.view.size()), text)
Expand All @@ -43,6 +48,12 @@ def run(self, edit, text, nuke_cursors=False):
pt = sublime.Region(0, 0)
selections.add(pt)

elif restore_cursors:
self.view.sel().clear()
for (row, col) in save_cursors:
cursor = self.view.text_point(row, col)
self.view.sel().add(cursor)


class GsReplaceRegionCommand(TextCommand):

Expand Down
266 changes: 162 additions & 104 deletions core/commands/log_graph.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import sublime
from sublime_plugin import WindowCommand, TextCommand
from functools import lru_cache, partial
import re

import sublime
from sublime_plugin import WindowCommand, TextCommand, EventListener

from ..git_command import GitCommand
from .log import GsLogActionCommand, GsLogCommand
from .navigate import GsNavigate
Expand Down Expand Up @@ -31,26 +34,22 @@ def run(self, file_path=None, title=None):
def run_async(self):
# need to get repo_path before the new view is created.
repo_path = self.repo_path

view = util.view.get_scratch_view(self, "log_graph", read_only=True)
view.set_syntax_file("Packages/GitSavvy/syntax/graph.sublime-syntax")
view.run_command("gs_handle_vintageous")
view.run_command("gs_handle_arrow_keys")

settings = view.settings()
settings.set("git_savvy.repo_path", repo_path)
settings.set("git_savvy.file_path", self._file_path)
settings.set("git_savvy.git_graph_args", self.get_graph_args())
view.set_syntax_file("Packages/GitSavvy/syntax/graph.sublime-syntax")
self.prepare_target_view(view)
view.set_name(self.title)
view.sel().clear()
view.run_command("gs_log_graph_refresh")
view.run_command("gs_log_graph_navigate")

def get_graph_args(self):
args = self.savvy_settings.get("git_graph_args")
follow = self.savvy_settings.get("log_follow_rename")
if self._file_path and follow:
args = args + ["--follow"]
if self._file_path:
file_path = self.get_rel_path(self._file_path)
args = args + ["--", file_path]
return args
view.run_command("gs_log_graph_refresh", {"navigate_after_draw": True})

def prepare_target_view(self, view):
pass


class GsLogGraphRefreshCommand(TextCommand, GitCommand):
Expand All @@ -59,25 +58,63 @@ class GsLogGraphRefreshCommand(TextCommand, GitCommand):
Refresh the current graph view with the latest commits.
"""

def run(self, edit):
def run(self, edit, navigate_after_draw=False):
sublime.set_timeout_async(partial(self.run_async, navigate_after_draw))

def run_async(self, navigate_after_draw=False):
file_path = self.file_path
if file_path:
graph_content = "File: {}\n\n".format(file_path)
else:
graph_content = ""

args = self.view.settings().get("git_savvy.git_graph_args")
args = self.build_git_command()
graph_content += self.git(*args)
graph_content = re.sub(
r'(^[{}]*)\*'.format(GRAPH_CHAR_OPTIONS),
r'\1' + COMMIT_NODE_CHAR, graph_content,
flags=re.MULTILINE)

self.view.run_command("gs_replace_view_text", {"text": graph_content})
self.view.run_command("gs_log_graph_more_info")
self.view.run_command("gs_replace_view_text", {"text": graph_content, "restore_cursors": True})
if navigate_after_draw:
self.view.run_command("gs_log_graph_navigate")

self.view.run_command("gs_handle_vintageous")
self.view.run_command("gs_handle_arrow_keys")
draw_info_panel(self.view, self.savvy_settings.get("graph_show_more_commit_info"))

def build_git_command(self):
args = self.savvy_settings.get("git_graph_args")
follow = self.savvy_settings.get("log_follow_rename")
if self.file_path and follow:
args.insert(1, "--follow")

if self.view.settings().get("git_savvy.log_graph_view.all_branches"):
args.insert(1, "--all")

author = self.view.settings().get("git_savvy.log_graph_view.filter_by_author")
if author:
args.insert(1, "--author={}".format(author))

branch = self.view.settings().get("git_savvy.log_graph_view.filter_by_branch")
if branch:
args.append(branch)

return args


class GsLogGraphCommand(GsLogCommand):
"""
Defines the main menu if you invoke `git: graph` or `git: graph current file`.
Accepts `current_file: bool` or `file_path: str` as (keyword) arguments, and
ensures that each of the defined actions/commands in `default_actions` are finally
called with `file_path` set.
"""
default_actions = [
["gs_log_graph_current_branch", "For current branch"],
["gs_log_graph_all_branches", "For all branches"],
["gs_log_graph_by_author", "Filtered by author"],
["gs_log_graph_by_branch", "Filtered by branch"],
]


class GsLogGraphCurrentBranch(LogGraphMixin, WindowCommand, GitCommand):
Expand All @@ -86,10 +123,8 @@ class GsLogGraphCurrentBranch(LogGraphMixin, WindowCommand, GitCommand):

class GsLogGraphAllBranches(LogGraphMixin, WindowCommand, GitCommand):

def get_graph_args(self):
args = super().get_graph_args()
args.append("--all")
return args
def prepare_target_view(self, view):
view.settings().set("git_savvy.log_graph_view.all_branches", True)


class GsLogGraphByAuthorCommand(LogGraphMixin, WindowCommand, GitCommand):
Expand Down Expand Up @@ -127,10 +162,8 @@ def on_author_selection(self, index):
self._selected_author = self._entries[index][3]
super().run_async()

def get_graph_args(self):
args = super().get_graph_args()
args.insert(1, "--author={}".format(self._selected_author))
return args
def prepare_target_view(self, view):
view.settings().set("git_savvy.log_graph_view.filter_by_author", self._selected_author)


class GsLogGraphByBranchCommand(LogGraphMixin, WindowCommand, GitCommand):
Expand All @@ -143,25 +176,110 @@ def on_branch_selection(self, branch):
self._selected_branch = branch
super().run_async()

def get_graph_args(self):
args = super().get_graph_args()
args.append(self._selected_branch)
return args
def prepare_target_view(self, view):
view.settings().set("git_savvy.log_graph_view.filter_by_branch", self._selected_branch)


class GsLogGraphCommand(GsLogCommand):
default_actions = [
["gs_log_graph_current_branch", "For current branch"],
["gs_log_graph_all_branches", "For all branches"],
["gs_log_graph_by_author", "Filtered by author"],
["gs_log_graph_by_branch", "Filtered by branch"],
]
class GsLogGraphNavigateCommand(GsNavigate):

"""
Travel between commits. It is also used by compare_commit_view.
"""
offset = 0

def get_available_regions(self):
return self.view.find_by_selector("constant.numeric.graph.commit-hash.git-savvy")


class GsLogGraphCursorListener(EventListener, GitCommand):
def is_applicable(self, view):
settings = view.settings()
return (
settings.get("git_savvy.log_graph_view")
or settings.get("git_savvy.compare_commit_view")
)

# `on_selection_modified` triggers twice per mouse click
# multiplied with the number of views into the same buffer.
# Well, ... sublime. Anyhow we're also not interested
# in vertical movement.
# We throttle in `draw_info_panel` below by line_text
# bc a log line is pretty unique if it contains the commit's sha.
def on_selection_modified_async(self, view):
if not self.is_applicable(view):
return

draw_info_panel(view, self.savvy_settings.get("graph_show_more_commit_info"))

def on_post_window_command(self, window, command_name, args):
# If the user hides the panel via `<ESC>` or mouse click,
if command_name == 'hide_panel':
self.savvy_settings.set("graph_show_more_commit_info", False)

# If the user opens a different panel, don't fight with it.
# Note: 'show_panel' can also be used to actually *hide* a panel if you pass
# the 'toggle' arg.
elif command_name == 'show_panel':
# Note: After 'show_panel' `on_selection_modified` runs *if* you used a
# keyboard shortcut for it. If you open a panel via mouse it doesn't.
show_panel = args.get('panel') == "output.show_commit_info"
self.savvy_settings.set("graph_show_more_commit_info", show_panel)
# If the user opened our panel via mouse click we MUST draw bc it can be
# out of sync. For now
view = window.active_view()
if self.is_applicable(view):
draw_info_panel(view, show_panel)


def draw_info_panel(view, show_panel):
"""Extract line under the first cursor and draw info panel."""
try:
cursor = next(s.a for s in view.sel() if s.empty())
except StopIteration:
return

line_span = view.line(cursor)
line_text = view.substr(line_span)

# Defer to a second fn to reduce side-effects
draw_info_panel_for_line(view.window().id(), line_text, show_panel)


@lru_cache(maxsize=1)
# ^- used to throttle the side-effect!
# Read: distinct until (wid, line_text, show_panel) changes
def draw_info_panel_for_line(wid, line_text, show_panel):
window = sublime.Window(wid)

if show_panel:
m = COMMIT_LINE.search(line_text)
commit_hash = m.groupdict()['commit_hash'] if m else ""
if len(commit_hash) <= 3:
return

window.run_command("gs_show_commit_info", {"commit_hash": commit_hash})
else:
if window.active_panel() == "output.show_commit_info":
window.run_command("hide_panel")


class GsLogGraphToggleMoreInfoCommand(TextCommand, WindowCommand, GitCommand):

"""
Toggle global `graph_show_more_commit_info` setting. Also used by compare_commit_view.
"""

def run(self, edit):
show_panel = not self.savvy_settings.get("graph_show_more_commit_info")
self.savvy_settings.set("graph_show_more_commit_info", show_panel)
draw_info_panel(self.view, show_panel)


class GsLogGraphActionCommand(GsLogActionCommand):

"""
Checkout the commit at the selected line. It is also used by compare_commit_view.
Define menu shown if you `<enter>` on a specific commit.
Also used by `compare_commit_view`.
"""
default_actions = [
["show_commit", "Show commit"],
Expand All @@ -172,12 +290,11 @@ class GsLogGraphActionCommand(GsLogActionCommand):
]

def update_actions(self):
super().update_actions()
super().update_actions() # GsLogActionCommand will mutate actions if `_file_path` is set!
view = self.window.active_view()
if view.settings().get("git_savvy.log_graph_view"):
if self._file_path:
# for `git: graph current file`, two more options would be inserted
# at index 1
# for `git: graph current file`
self.actions.insert(5, ["revert_commit", "Revert commit"])
else:
self.actions.insert(3, ["revert_commit", "Revert commit"])
Expand Down Expand Up @@ -206,62 +323,3 @@ def run(self):
return

super().run(commit_hash=self._commit_hash, file_path=self._file_path)


class GsLogGraphNavigateCommand(GsNavigate):

"""
Travel between commits. It is also used by compare_commit_view.
"""
offset = 0

def run(self, edit, **kwargs):
super().run(edit, **kwargs)
self.view.window().run_command("gs_log_graph_more_info")

def get_available_regions(self):
return self.view.find_by_selector("constant.numeric.graph.commit-hash.git-savvy")


class GsLogGraphMoreInfoCommand(TextCommand, GitCommand):

"""
Show all info about a commit in a quick panel. It is also used by compare_commit_view.
"""

def run(self, edit):
show_more = self.savvy_settings.get("graph_show_more_commit_info")
if not show_more:
return

selections = self.view.sel()
if len(selections) != 1:
return

lines = util.view.get_lines_from_regions(self.view, selections)
if not lines:
return
line = lines[0]

m = COMMIT_LINE.search(line)
commit_hash = m.groupdict()['commit_hash'] if m else ""

if len(commit_hash) <= 3:
return

self.view.window().run_command("gs_show_commit_info", {"commit_hash": commit_hash})


class GsLogGraphToggleMoreInfoCommand(TextCommand, WindowCommand, GitCommand):

"""
Toggle `graph_show_more_commit_info` setting. It is also used by compare_commit_view.
"""

def run(self, edit):
show_more = not self.savvy_settings.get("graph_show_more_commit_info")
self.savvy_settings.set("graph_show_more_commit_info", show_more)
if not show_more:
self.view.window().run_command("hide_panel")

self.view.run_command("gs_log_graph_more_info")
Loading

0 comments on commit 2910a03

Please sign in to comment.