1# git-gui index (add/remove) support
2# Copyright (C) 2006, 2007 Shawn Pearce
3
4proc update_indexinfo {msg pathList after} {
5 global update_index_cp ui_status_value
6
7 if {![lock_index update]} return
8
9 set update_index_cp 0
10 set pathList [lsort $pathList]
11 set totalCnt [llength $pathList]
12 set batch [expr {int($totalCnt * .01) + 1}]
13 if {$batch > 25} {set batch 25}
14
15 set ui_status_value [format \
16 "$msg... %i/%i files (%.2f%%)" \
17 $update_index_cp \
18 $totalCnt \
19 0.0]
20 set fd [open "| git update-index -z --index-info" w]
21 fconfigure $fd \
22 -blocking 0 \
23 -buffering full \
24 -buffersize 512 \
25 -encoding binary \
26 -translation binary
27 fileevent $fd writable [list \
28 write_update_indexinfo \
29 $fd \
30 $pathList \
31 $totalCnt \
32 $batch \
33 $msg \
34 $after \
35 ]
36}
37
38proc write_update_indexinfo {fd pathList totalCnt batch msg after} {
39 global update_index_cp ui_status_value
40 global file_states current_diff_path
41
42 if {$update_index_cp >= $totalCnt} {
43 close $fd
44 unlock_index
45 uplevel #0 $after
46 return
47 }
48
49 for {set i $batch} \
50 {$update_index_cp < $totalCnt && $i > 0} \
51 {incr i -1} {
52 set path [lindex $pathList $update_index_cp]
53 incr update_index_cp
54
55 set s $file_states($path)
56 switch -glob -- [lindex $s 0] {
57 A? {set new _O}
58 M? {set new _M}
59 D_ {set new _D}
60 D? {set new _?}
61 ?? {continue}
62 }
63 set info [lindex $s 2]
64 if {$info eq {}} continue
65
66 puts -nonewline $fd "$info\t[encoding convertto $path]\0"
67 display_file $path $new
68 }
69
70 set ui_status_value [format \
71 "$msg... %i/%i files (%.2f%%)" \
72 $update_index_cp \
73 $totalCnt \
74 [expr {100.0 * $update_index_cp / $totalCnt}]]
75}
76
77proc update_index {msg pathList after} {
78 global update_index_cp ui_status_value
79
80 if {![lock_index update]} return
81
82 set update_index_cp 0
83 set pathList [lsort $pathList]
84 set totalCnt [llength $pathList]
85 set batch [expr {int($totalCnt * .01) + 1}]
86 if {$batch > 25} {set batch 25}
87
88 set ui_status_value [format \
89 "$msg... %i/%i files (%.2f%%)" \
90 $update_index_cp \
91 $totalCnt \
92 0.0]
93 set fd [open "| git update-index --add --remove -z --stdin" w]
94 fconfigure $fd \
95 -blocking 0 \
96 -buffering full \
97 -buffersize 512 \
98 -encoding binary \
99 -translation binary
100 fileevent $fd writable [list \
101 write_update_index \
102 $fd \
103 $pathList \
104 $totalCnt \
105 $batch \
106 $msg \
107 $after \
108 ]
109}
110
111proc write_update_index {fd pathList totalCnt batch msg after} {
112 global update_index_cp ui_status_value
113 global file_states current_diff_path
114
115 if {$update_index_cp >= $totalCnt} {
116 close $fd
117 unlock_index
118 uplevel #0 $after
119 return
120 }
121
122 for {set i $batch} \
123 {$update_index_cp < $totalCnt && $i > 0} \
124 {incr i -1} {
125 set path [lindex $pathList $update_index_cp]
126 incr update_index_cp
127
128 switch -glob -- [lindex $file_states($path) 0] {
129 AD {set new __}
130 ?D {set new D_}
131 _O -
132 AM {set new A_}
133 U? {
134 if {[file exists $path]} {
135 set new M_
136 } else {
137 set new D_
138 }
139 }
140 ?M {set new M_}
141 ?? {continue}
142 }
143 puts -nonewline $fd "[encoding convertto $path]\0"
144 display_file $path $new
145 }
146
147 set ui_status_value [format \
148 "$msg... %i/%i files (%.2f%%)" \
149 $update_index_cp \
150 $totalCnt \
151 [expr {100.0 * $update_index_cp / $totalCnt}]]
152}
153
154proc checkout_index {msg pathList after} {
155 global update_index_cp ui_status_value
156
157 if {![lock_index update]} return
158
159 set update_index_cp 0
160 set pathList [lsort $pathList]
161 set totalCnt [llength $pathList]
162 set batch [expr {int($totalCnt * .01) + 1}]
163 if {$batch > 25} {set batch 25}
164
165 set ui_status_value [format \
166 "$msg... %i/%i files (%.2f%%)" \
167 $update_index_cp \
168 $totalCnt \
169 0.0]
170 set cmd [list git checkout-index]
171 lappend cmd --index
172 lappend cmd --quiet
173 lappend cmd --force
174 lappend cmd -z
175 lappend cmd --stdin
176 set fd [open "| $cmd " w]
177 fconfigure $fd \
178 -blocking 0 \
179 -buffering full \
180 -buffersize 512 \
181 -encoding binary \
182 -translation binary
183 fileevent $fd writable [list \
184 write_checkout_index \
185 $fd \
186 $pathList \
187 $totalCnt \
188 $batch \
189 $msg \
190 $after \
191 ]
192}
193
194proc write_checkout_index {fd pathList totalCnt batch msg after} {
195 global update_index_cp ui_status_value
196 global file_states current_diff_path
197
198 if {$update_index_cp >= $totalCnt} {
199 close $fd
200 unlock_index
201 uplevel #0 $after
202 return
203 }
204
205 for {set i $batch} \
206 {$update_index_cp < $totalCnt && $i > 0} \
207 {incr i -1} {
208 set path [lindex $pathList $update_index_cp]
209 incr update_index_cp
210 switch -glob -- [lindex $file_states($path) 0] {
211 U? {continue}
212 ?M -
213 ?D {
214 puts -nonewline $fd "[encoding convertto $path]\0"
215 display_file $path ?_
216 }
217 }
218 }
219
220 set ui_status_value [format \
221 "$msg... %i/%i files (%.2f%%)" \
222 $update_index_cp \
223 $totalCnt \
224 [expr {100.0 * $update_index_cp / $totalCnt}]]
225}
226
227proc unstage_helper {txt paths} {
228 global file_states current_diff_path
229
230 if {![lock_index begin-update]} return
231
232 set pathList [list]
233 set after {}
234 foreach path $paths {
235 switch -glob -- [lindex $file_states($path) 0] {
236 A? -
237 M? -
238 D? {
239 lappend pathList $path
240 if {$path eq $current_diff_path} {
241 set after {reshow_diff;}
242 }
243 }
244 }
245 }
246 if {$pathList eq {}} {
247 unlock_index
248 } else {
249 update_indexinfo \
250 $txt \
251 $pathList \
252 [concat $after {set ui_status_value {Ready.}}]
253 }
254}
255
256proc do_unstage_selection {} {
257 global current_diff_path selected_paths
258
259 if {[array size selected_paths] > 0} {
260 unstage_helper \
261 {Unstaging selected files from commit} \
262 [array names selected_paths]
263 } elseif {$current_diff_path ne {}} {
264 unstage_helper \
265 "Unstaging [short_path $current_diff_path] from commit" \
266 [list $current_diff_path]
267 }
268}
269
270proc add_helper {txt paths} {
271 global file_states current_diff_path
272
273 if {![lock_index begin-update]} return
274
275 set pathList [list]
276 set after {}
277 foreach path $paths {
278 switch -glob -- [lindex $file_states($path) 0] {
279 _O -
280 ?M -
281 ?D -
282 U? {
283 lappend pathList $path
284 if {$path eq $current_diff_path} {
285 set after {reshow_diff;}
286 }
287 }
288 }
289 }
290 if {$pathList eq {}} {
291 unlock_index
292 } else {
293 update_index \
294 $txt \
295 $pathList \
296 [concat $after {set ui_status_value {Ready to commit.}}]
297 }
298}
299
300proc do_add_selection {} {
301 global current_diff_path selected_paths
302
303 if {[array size selected_paths] > 0} {
304 add_helper \
305 {Adding selected files} \
306 [array names selected_paths]
307 } elseif {$current_diff_path ne {}} {
308 add_helper \
309 "Adding [short_path $current_diff_path]" \
310 [list $current_diff_path]
311 }
312}
313
314proc do_add_all {} {
315 global file_states
316
317 set paths [list]
318 foreach path [array names file_states] {
319 switch -glob -- [lindex $file_states($path) 0] {
320 U? {continue}
321 ?M -
322 ?D {lappend paths $path}
323 }
324 }
325 add_helper {Adding all changed files} $paths
326}
327
328proc revert_helper {txt paths} {
329 global file_states current_diff_path
330
331 if {![lock_index begin-update]} return
332
333 set pathList [list]
334 set after {}
335 foreach path $paths {
336 switch -glob -- [lindex $file_states($path) 0] {
337 U? {continue}
338 ?M -
339 ?D {
340 lappend pathList $path
341 if {$path eq $current_diff_path} {
342 set after {reshow_diff;}
343 }
344 }
345 }
346 }
347
348 set n [llength $pathList]
349 if {$n == 0} {
350 unlock_index
351 return
352 } elseif {$n == 1} {
353 set s "[short_path [lindex $pathList]]"
354 } else {
355 set s "these $n files"
356 }
357
358 set reply [tk_dialog \
359 .confirm_revert \
360 "[appname] ([reponame])" \
361 "Revert changes in $s?
362
363Any unadded changes will be permanently lost by the revert." \
364 question \
365 1 \
366 {Do Nothing} \
367 {Revert Changes} \
368 ]
369 if {$reply == 1} {
370 checkout_index \
371 $txt \
372 $pathList \
373 [concat $after {set ui_status_value {Ready.}}]
374 } else {
375 unlock_index
376 }
377}
378
379proc do_revert_selection {} {
380 global current_diff_path selected_paths
381
382 if {[array size selected_paths] > 0} {
383 revert_helper \
384 {Reverting selected files} \
385 [array names selected_paths]
386 } elseif {$current_diff_path ne {}} {
387 revert_helper \
388 "Reverting [short_path $current_diff_path]" \
389 [list $current_diff_path]
390 }
391}
392
393proc do_select_commit_type {} {
394 global commit_type selected_commit_type
395
396 if {$selected_commit_type eq {new}
397 && [string match amend* $commit_type]} {
398 create_new_commit
399 } elseif {$selected_commit_type eq {amend}
400 && ![string match amend* $commit_type]} {
401 load_last_commit
402
403 # The amend request was rejected...
404 #
405 if {![string match amend* $commit_type]} {
406 set selected_commit_type new
407 }
408 }
409}