git-gui: Refactor into multiple files to save my sanity
[git-gui.git] / lib / index.tcl
blob42742850eef627262844d2414a593a6e8952d08a
1 # git-gui index (add/remove) support
2 # Copyright (C) 2006, 2007 Shawn Pearce
4 proc update_indexinfo {msg pathList after} {
5 global update_index_cp ui_status_value
7 if {![lock_index update]} return
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}
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 \
38 proc write_update_indexinfo {fd pathList totalCnt batch msg after} {
39 global update_index_cp ui_status_value
40 global file_states current_diff_path
42 if {$update_index_cp >= $totalCnt} {
43 close $fd
44 unlock_index
45 uplevel #0 $after
46 return
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
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}
63 set info [lindex $s 2]
64 if {$info eq {}} continue
66 puts -nonewline $fd "$info\t[encoding convertto $path]\0"
67 display_file $path $new
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}]]
77 proc update_index {msg pathList after} {
78 global update_index_cp ui_status_value
80 if {![lock_index update]} return
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}
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 \
111 proc write_update_index {fd pathList totalCnt batch msg after} {
112 global update_index_cp ui_status_value
113 global file_states current_diff_path
115 if {$update_index_cp >= $totalCnt} {
116 close $fd
117 unlock_index
118 uplevel #0 $after
119 return
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
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_
140 ?M {set new M_}
141 ?? {continue}
143 puts -nonewline $fd "[encoding convertto $path]\0"
144 display_file $path $new
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}]]
154 proc checkout_index {msg pathList after} {
155 global update_index_cp ui_status_value
157 if {![lock_index update]} return
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}
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 \
194 proc write_checkout_index {fd pathList totalCnt batch msg after} {
195 global update_index_cp ui_status_value
196 global file_states current_diff_path
198 if {$update_index_cp >= $totalCnt} {
199 close $fd
200 unlock_index
201 uplevel #0 $after
202 return
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 ?_
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}]]
227 proc unstage_helper {txt paths} {
228 global file_states current_diff_path
230 if {![lock_index begin-update]} return
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;}
246 if {$pathList eq {}} {
247 unlock_index
248 } else {
249 update_indexinfo \
250 $txt \
251 $pathList \
252 [concat $after {set ui_status_value {Ready.}}]
256 proc do_unstage_selection {} {
257 global current_diff_path selected_paths
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]
270 proc add_helper {txt paths} {
271 global file_states current_diff_path
273 if {![lock_index begin-update]} return
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;}
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.}}]
300 proc do_add_selection {} {
301 global current_diff_path selected_paths
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]
314 proc do_add_all {} {
315 global file_states
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}
325 add_helper {Adding all changed files} $paths
328 proc revert_helper {txt paths} {
329 global file_states current_diff_path
331 if {![lock_index begin-update]} return
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;}
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"
358 set reply [tk_dialog \
359 .confirm_revert \
360 "[appname] ([reponame])" \
361 "Revert changes in $s?
363 Any unadded changes will be permanently lost by the revert." \
364 question \
366 {Do Nothing} \
367 {Revert Changes} \
369 if {$reply == 1} {
370 checkout_index \
371 $txt \
372 $pathList \
373 [concat $after {set ui_status_value {Ready.}}]
374 } else {
375 unlock_index
379 proc do_revert_selection {} {
380 global current_diff_path selected_paths
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]
393 proc do_select_commit_type {} {
394 global commit_type selected_commit_type
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
403 # The amend request was rejected...
405 if {![string match amend* $commit_type]} {
406 set selected_commit_type new