Skip to content

Commit d4b2590

Browse files
committed
Add first part of the plugin
1 parent 20fe6c0 commit d4b2590

File tree

5 files changed

+104
-0
lines changed

5 files changed

+104
-0
lines changed

Context.sublime-menu

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[
2+
{
3+
"id": "blame",
4+
"caption": "Git Blame",
5+
"command": "blame"
6+
}
7+
]

Default (Linux).sublime-keymap

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[
2+
{
3+
"keys": ["ctrl+shift+q"],
4+
"command": "blame"
5+
}
6+
]

Default (OSX).sublime-keymap

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[
2+
{
3+
"keys": ["ctrl+shift+q"],
4+
"command": "blame"
5+
}
6+
]

Default (Windows).sublime-keymap

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[
2+
{
3+
"keys": ["ctrl+shift+q"],
4+
"command": "blame"
5+
}
6+
]

git-blame.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import sublime
2+
import sublime_plugin
3+
import os
4+
import functools
5+
from subprocess import check_output as shell
6+
7+
8+
blame_cache = {}
9+
template = '''
10+
<span>
11+
<style>
12+
span {{
13+
background-color: brown;
14+
}}
15+
a {{
16+
text-decoration: none;
17+
}}
18+
</style>
19+
<a href="close">
20+
<strong>Git Blame:</strong> ({user})
21+
Last updated: {date} {time} | [{sha}]
22+
<close>X</close>&nbsp;
23+
</a>
24+
</span>
25+
'''
26+
27+
si = subprocess.STARTUPINFO()
28+
si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
29+
30+
31+
class BlameCommand(sublime_plugin.TextCommand):
32+
33+
def __init__(self, view):
34+
self.view = view
35+
self.phantom_set = sublime.PhantomSet(view, 'git-blame')
36+
37+
@functools.lru_cache(128, False)
38+
def get_blame(self, line, path):
39+
try:
40+
return shell(["git", "blame", "--minimal", "-w",
41+
"-L {0},{0}".format(line), path],
42+
cwd=os.path.dirname(os.path.realpath(path)),
43+
startupinfo=si)
44+
except Exception as e:
45+
return
46+
47+
def parse_blame(self, blame):
48+
sha, file_path, user, date, time, tz_offset, *_ = blame.decode('utf-8').split()
49+
50+
# Was part of the inital commit so no updates
51+
if file_path[0] == '(':
52+
user, date, time, tz_offset = file_path, user, date, time
53+
file_path = None
54+
55+
return(sha, user[1:], date, time)
56+
57+
def on_phantom_close(self, href):
58+
self.view.erase_phantoms('git-blame')
59+
60+
61+
def run(self, edit):
62+
phantoms = []
63+
self.view.erase_phantoms('git-blame')
64+
65+
for region in self.view.sel():
66+
line = self.view.line(region)
67+
(row, col) = self.view.rowcol(region.begin())
68+
full_path = self.view.file_name()
69+
result = self.get_blame(int(row)+1, full_path)
70+
if not result:
71+
# Unable to get blame
72+
return
73+
74+
sha, user, date, time = self.parse_blame(result)
75+
body = template.format(sha=sha, user=user, date=date, time=time)
76+
77+
phantom = sublime.Phantom(line, body, sublime.LAYOUT_BLOCK, self.on_phantom_close)
78+
phantoms.append(phantom)
79+
self.phantom_set.update(phantoms)

0 commit comments

Comments
 (0)