git-gui: Use proper Windows shortcuts instead of bat files
[git] / lib / index.tcl
1 # git-gui index (add/remove) support
2 # Copyright (C) 2006, 2007 Shawn Pearce
3
4 proc 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
33 proc 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
69 proc 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
98 proc 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
138 proc 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
173 proc 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
203 proc 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
232 proc 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
246 proc 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
276 proc 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
290 proc 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
304 proc 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
364 proc 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
378 proc 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 }