0.1.18
by Michael Ellerman
Split out HunkSelector class. |
1 |
#!/usr/bin/python
|
2 |
||
3 |
import sys |
|
4 |
||
5 |
class HunkSelector: |
|
6 |
class Option: |
|
7 |
def __init__(self, char, action, help, default=False): |
|
8 |
self.char = char |
|
9 |
self.action = action |
|
10 |
self.default = default |
|
11 |
self.help = help |
|
12 |
||
13 |
standard_options = [ |
|
14 |
Option('n', 'shelve', 'shelve this change for the moment.', |
|
15 |
default=True), |
|
16 |
Option('y', 'keep', 'keep this change in your tree.'), |
|
17 |
Option('d', 'done', 'done, skip to the end.'), |
|
18 |
Option('i', 'invert', 'invert the current selection of all hunks.'), |
|
19 |
Option('s', 'status', 'show status of hunks.'), |
|
20 |
Option('q', 'quit', 'quit') |
|
21 |
]
|
|
22 |
||
23 |
end_options = [ |
|
24 |
Option('y', 'continue', 'proceed to shelve selected changes.', |
|
25 |
default=True), |
|
26 |
Option('r', 'restart', 'restart the hunk selection loop.'), |
|
27 |
Option('s', 'status', 'show status of hunks.'), |
|
28 |
Option('i', 'invert', 'invert the current selection of all hunks.'), |
|
29 |
Option('q', 'quit', 'quit') |
|
30 |
]
|
|
31 |
||
32 |
def __init__(self, patches): |
|
33 |
self.patches = patches |
|
34 |
self.total_hunks = 0 |
|
35 |
for patch in patches: |
|
36 |
for hunk in patch.hunks: |
|
37 |
# everything's shelved by default
|
|
38 |
hunk.selected = True |
|
39 |
self.total_hunks += 1 |
|
40 |
||
41 |
def __get_option(self, char): |
|
42 |
for opt in self.standard_options: |
|
43 |
if opt.char == char: |
|
44 |
return opt |
|
45 |
raise Exception('Option "%s" not found!' % char) |
|
46 |
||
47 |
def __select_loop(self): |
|
48 |
j = 0 |
|
49 |
for patch in self.patches: |
|
50 |
i = 0 |
|
51 |
lasti = -1 |
|
52 |
while i < len(patch.hunks): |
|
53 |
hunk = patch.hunks[i] |
|
54 |
if lasti != i: |
|
55 |
print patch.get_header(), hunk |
|
56 |
j += 1 |
|
57 |
lasti = i |
|
58 |
||
59 |
prompt = 'Keep this change? (%d of %d)' \ |
|
60 |
% (j, self.total_hunks) |
|
61 |
||
62 |
if hunk.selected: |
|
63 |
self.__get_option('n').default = True |
|
64 |
self.__get_option('y').default = False |
|
65 |
else: |
|
66 |
self.__get_option('n').default = False |
|
67 |
self.__get_option('y').default = True |
|
68 |
||
69 |
action = self.__ask_user(prompt, self.standard_options) |
|
70 |
||
71 |
if action == 'keep': |
|
72 |
hunk.selected = False |
|
73 |
elif action == 'shelve': |
|
74 |
hunk.selected = True |
|
75 |
elif action == 'done': |
|
76 |
return True |
|
77 |
elif action == 'invert': |
|
78 |
self.__invert_selection() |
|
79 |
self.__show_status() |
|
80 |
continue
|
|
81 |
elif action == 'status': |
|
82 |
self.__show_status() |
|
83 |
continue
|
|
84 |
elif action == 'quit': |
|
85 |
return False |
|
86 |
||
87 |
i += 1 |
|
88 |
return True |
|
89 |
||
90 |
def select(self): |
|
91 |
if self.total_hunks == 0: |
|
92 |
return [] |
|
93 |
||
94 |
done = False |
|
95 |
while not done: |
|
96 |
if not self.__select_loop(): |
|
97 |
return [] |
|
98 |
||
99 |
while True: |
|
100 |
self.__show_status() |
|
101 |
prompt = "Shelve these changes, or restart?" |
|
102 |
action = self.__ask_user(prompt, self.end_options) |
|
103 |
||
104 |
if action == 'continue': |
|
105 |
done = True |
|
106 |
break
|
|
107 |
elif action == 'quit': |
|
108 |
return [] |
|
109 |
elif action == 'status': |
|
110 |
self.__show_status() |
|
111 |
elif action == 'invert': |
|
112 |
self.__invert_selection() |
|
113 |
elif action == 'restart': |
|
114 |
break
|
|
115 |
||
116 |
||
117 |
for patch in self.patches: |
|
118 |
tmp = [] |
|
119 |
for hunk in patch.hunks: |
|
120 |
if hunk.selected: |
|
121 |
tmp.append(hunk) |
|
122 |
patch.hunks = tmp |
|
123 |
||
124 |
tmp = [] |
|
125 |
for patch in self.patches: |
|
126 |
if len(patch.hunks): |
|
127 |
tmp.append(patch) |
|
128 |
self.patches = tmp |
|
129 |
||
130 |
return self.patches |
|
131 |
||
132 |
def __invert_selection(self): |
|
133 |
for patch in self.patches: |
|
134 |
for hunk in patch.hunks: |
|
135 |
if hunk.__dict__.has_key('selected'): |
|
136 |
hunk.selected = not hunk.selected |
|
137 |
else: |
|
138 |
hunk.selected = True |
|
139 |
||
140 |
def __show_status(self): |
|
141 |
print '\nStatus:' |
|
142 |
for patch in self.patches: |
|
143 |
print ' %s' % patch.oldname |
|
144 |
shelve = 0 |
|
145 |
keep = 0 |
|
146 |
for hunk in patch.hunks: |
|
147 |
if hunk.selected: |
|
148 |
shelve += 1 |
|
149 |
else: |
|
150 |
keep += 1 |
|
151 |
||
152 |
print ' %d hunks to be shelved' % shelve |
|
153 |
print ' %d hunks to be kept' % keep |
|
154 |
print
|
|
155 |
||
156 |
if sys.platform == "win32": |
|
157 |
import msvcrt |
|
158 |
def __getchar(self): |
|
159 |
return msvcrt.getche() |
|
160 |
else: |
|
161 |
def __getchar(self): |
|
162 |
import tty |
|
163 |
import termios |
|
164 |
fd = sys.stdin.fileno() |
|
165 |
settings = termios.tcgetattr(fd) |
|
166 |
try: |
|
167 |
tty.setraw(fd) |
|
168 |
ch = sys.stdin.read(1) |
|
169 |
finally: |
|
170 |
termios.tcsetattr(fd, termios.TCSADRAIN, settings) |
|
171 |
return ch |
|
172 |
||
173 |
def __ask_user(self, prompt, options): |
|
174 |
while True: |
|
175 |
sys.stdout.write(prompt) |
|
176 |
sys.stdout.write(' [') |
|
177 |
for opt in options: |
|
178 |
if opt.default: |
|
179 |
default = opt |
|
180 |
sys.stdout.write(opt.char) |
|
181 |
sys.stdout.write('?] (%s): ' % default.char) |
|
182 |
||
183 |
response = self.__getchar() |
|
184 |
||
185 |
# default, which we see as newline, is 'n'
|
|
186 |
if response in ['\n', '\r', '\r\n']: |
|
187 |
response = default.char |
|
188 |
||
189 |
print response # because echo is off |
|
190 |
||
191 |
for opt in options: |
|
192 |
if opt.char == response: |
|
193 |
return opt.action |
|
194 |
||
195 |
for opt in options: |
|
196 |
print ' %s - %s' % (opt.char, opt.help) |