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