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