git-gui: Don't show blame tooltips that we have no data for
[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         ui_status [format \
16                 "$msg... %i/%i files (%.2f%%)" \
17                 $update_index_cp \
18                 $totalCnt \
19                 0.0]
20         set fd [git_write update-index -z --index-info]
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
38 proc write_update_indexinfo {fd pathList totalCnt batch msg after} {
39         global update_index_cp
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         ui_status [format \
71                 "$msg... %i/%i files (%.2f%%)" \
72                 $update_index_cp \
73                 $totalCnt \
74                 [expr {100.0 * $update_index_cp / $totalCnt}]]
75 }
76
77 proc update_index {msg pathList after} {
78         global update_index_cp
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         ui_status [format \
89                 "$msg... %i/%i files (%.2f%%)" \
90                 $update_index_cp \
91                 $totalCnt \
92                 0.0]
93         set fd [git_write update-index --add --remove -z --stdin]
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
111 proc write_update_index {fd pathList totalCnt batch msg after} {
112         global update_index_cp
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         ui_status [format \
148                 "$msg... %i/%i files (%.2f%%)" \
149                 $update_index_cp \
150                 $totalCnt \
151                 [expr {100.0 * $update_index_cp / $totalCnt}]]
152 }
153
154 proc checkout_index {msg pathList after} {
155         global update_index_cp
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         ui_status [format \
166                 "$msg... %i/%i files (%.2f%%)" \
167                 $update_index_cp \
168                 $totalCnt \
169                 0.0]
170         set fd [git_write checkout-index \
171                 --index \
172                 --quiet \
173                 --force \
174                 -z \
175                 --stdin \
176                 ]
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
194 proc write_checkout_index {fd pathList totalCnt batch msg after} {
195         global update_index_cp
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         ui_status [format \
221                 "$msg... %i/%i files (%.2f%%)" \
222                 $update_index_cp \
223                 $totalCnt \
224                 [expr {100.0 * $update_index_cp / $totalCnt}]]
225 }
226
227 proc 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 [list ui_ready]]
253         }
254 }
255
256 proc 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
270 proc 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 {ui_status {Ready to commit.}}]
297         }
298 }
299
300 proc 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
314 proc 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
328 proc 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
363 Any 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 [list ui_ready]]
374         } else {
375                 unlock_index
376         }
377 }
378
379 proc 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
393 proc 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 }