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>
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