Skip to content

Commit e937317

Browse files
committed
Add basic context menu to all views
Users can opt-out by setting `disable_context_menus: false` in their GitSavvy settings.
1 parent d8ebf42 commit e937317

File tree

4 files changed

+157
-1
lines changed

4 files changed

+157
-1
lines changed

Context.sublime-menu

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
[
2+
{
3+
"caption": "GitSavvy: Line History",
4+
"command": "gs_ctx_line_history"
5+
},
6+
{
7+
"caption": "GitSavvy: Pick-axe",
8+
"command": "gs_ctx_pick_axe"
9+
},
10+
{
11+
"caption": "GitSavvy: Stage selected hunk",
12+
"command": "gs_ctx_stage_hunk"
13+
}
14+
// {
15+
// "caption": " ...",
16+
// "children": [
17+
// {
18+
// "caption": "Repo History",
19+
// "command": "gs_graph",
20+
// "args": { "all": true }
21+
// },
22+
// {
23+
// "caption": "Path History",
24+
// "command": "gs_graph_current_path"
25+
// },
26+
// {
27+
// "caption": "File History",
28+
// "command": "gs_graph_current_file",
29+
// "args": { "all": false }
30+
// },
31+
// { "caption": "-" },
32+
// {
33+
// "caption": "Show current file revision at HEAD",
34+
// "command": "gs_show_file_at_commit"
35+
// },
36+
// ]
37+
// },
38+
]

GitSavvy.sublime-settings

+7-1
Original file line numberDiff line numberDiff line change
@@ -369,5 +369,11 @@
369369
When set to `true`, no views will receive the prompt asking to initialize
370370
Git in the current view's directory when not found.
371371
*/
372-
"disable_git_init_prompt": false
372+
"disable_git_init_prompt": false,
373+
374+
/*
375+
Disable adding any entries to the context menu available when right-clicking
376+
in any view.
377+
*/
378+
"disable_context_menus": false
373379
}

core/commands/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from .cherry_pick import *
88
from .commit import *
99
from .commit_compare import *
10+
from .context_menu import *
1011
from .custom import *
1112
from .diff import *
1213
from .fetch import *

core/commands/context_menu.py

+111
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
from functools import lru_cache
2+
3+
import sublime
4+
5+
from GitSavvy.core.base_commands import GsTextCommand
6+
7+
from typing import Callable, List, Optional, TypeVar
8+
T = TypeVar("T")
9+
10+
__all__ = (
11+
"gs_ctx_line_history",
12+
"gs_ctx_pick_axe",
13+
"gs_ctx_stage_hunk",
14+
)
15+
16+
17+
# Provide a `CommandContext` as the global `Context` which
18+
# is valid for this exact "runtime-task". This is to speed-up
19+
# the preconditions in `is_enabled` and `is_visible`.
20+
21+
def cached_property(fn: Callable[..., T]) -> T:
22+
return property(lru_cache(1)(fn)) # type: ignore[return-value]
23+
24+
25+
class CommandContext:
26+
def __init__(self, cmd: GsTextCommand):
27+
self._cmd = cmd
28+
29+
@cached_property
30+
def enabled(self) -> bool:
31+
return not self._cmd.savvy_settings.get("disable_context_menus")
32+
33+
@cached_property
34+
def sel(self) -> List[sublime.Region]:
35+
return list(self._cmd.view.sel())
36+
37+
@cached_property
38+
def repo_path(self) -> Optional[str]:
39+
return self._cmd.find_repo_path()
40+
41+
@cached_property
42+
def file_path(self) -> Optional[str]:
43+
return self._cmd.file_path
44+
45+
46+
Context = None
47+
48+
49+
def get_context(self) -> CommandContext:
50+
global Context
51+
if not Context:
52+
Context = CommandContext(self)
53+
sublime.set_timeout(reset_context)
54+
55+
return Context
56+
57+
58+
def reset_context():
59+
global Context
60+
Context = None
61+
62+
63+
class gs_ctx_line_history(GsTextCommand):
64+
def is_enabled(self) -> bool:
65+
ctx = get_context(self)
66+
return bool(
67+
ctx.sel
68+
and ctx.repo_path
69+
)
70+
71+
def is_visible(self) -> bool:
72+
ctx = get_context(self)
73+
return ctx.enabled and bool(ctx.repo_path)
74+
75+
def run(self, edit) -> None:
76+
self.view.run_command("gs_line_history")
77+
78+
79+
class gs_ctx_stage_hunk(GsTextCommand):
80+
def is_enabled(self) -> bool:
81+
ctx = get_context(self)
82+
return bool(
83+
ctx.sel
84+
and ctx.repo_path
85+
and self.view.file_name()
86+
and not self.view.is_dirty()
87+
)
88+
89+
def is_visible(self) -> bool:
90+
ctx = get_context(self)
91+
return ctx.enabled and bool(ctx.repo_path)
92+
93+
def run(self, edit) -> None:
94+
self.view.run_command("gs_stage_hunk")
95+
96+
97+
class gs_ctx_pick_axe(GsTextCommand):
98+
def is_enabled(self) -> bool:
99+
ctx = get_context(self)
100+
return bool(
101+
ctx.sel
102+
and ctx.repo_path
103+
and all(self.view.substr(r).strip() for r in ctx.sel)
104+
)
105+
106+
def is_visible(self) -> bool:
107+
ctx = get_context(self)
108+
return ctx.enabled and bool(ctx.repo_path)
109+
110+
def run(self, edit) -> None:
111+
self.view.run_command("gs_graph_pickaxe")

0 commit comments

Comments
 (0)