1 # git-gui index (add/remove) support
2 # Copyright (C) 2006, 2007 Shawn Pearce
4 proc _delete_indexlock {} {
5 if {[catch {file delete -- [gitdir index.lock]} err]} {
6 error_popup [strcat [mc "Unable to unlock the index."] "\n\n$err"]
10 proc _close_updateindex {fd after} {
12 fconfigure $fd -blocking 1
13 if {[catch {close $fd} err]} {
17 wm title $w [strcat "[appname] ([reponame]): " [mc "Index Error"]]
18 wm geometry $w "+[winfo rootx .]+[winfo rooty .]"
19 set s [mc "Updating the Git index failed. A rescan will be automatically started to resynchronize git-gui."]
20 text $w.msg -yscrollcommand [list $w.vs set] \
21 -width [string length $s] -relief flat \
22 -borderwidth 0 -highlightthickness 0 \
23 -background [get_bg_color $w]
24 $w.msg tag configure bold -font font_uibold -justify center
25 ${NS}::scrollbar $w.vs -command [list $w.msg yview]
26 $w.msg insert end $s bold \n\n$err {}
27 $w.msg configure -state disabled
29 ${NS}::button $w.continue \
30 -text [mc "Continue"] \
31 -command [list destroy $w]
32 ${NS}::button $w.unlock \
33 -text [mc "Unlock Index"] \
34 -command "destroy $w; _delete_indexlock"
35 grid $w.msg - $w.vs -sticky news
36 grid $w.unlock $w.continue - -sticky se -padx 2 -pady 2
37 grid columnconfigure $w 0 -weight 1
38 grid rowconfigure $w 0 -weight 1
40 wm protocol $w WM_DELETE_WINDOW update
41 bind $w.continue <Visibility> "
59 proc update_indexinfo {msg pathList after} {
60 global update_index_cp
62 if {![lock_index update]} return
65 set pathList [lsort $pathList]
66 set totalCnt [llength $pathList]
67 set batch [expr {int($totalCnt * .01) + 1}]
68 if {$batch > 25} {set batch 25}
70 $::main_status start $msg [mc "files"]
71 set fd [git_write update-index -z --index-info]
78 fileevent $fd writable [list \
79 write_update_indexinfo \
88 proc write_update_indexinfo {fd pathList totalCnt batch after} {
89 global update_index_cp
90 global file_states current_diff_path
92 if {$update_index_cp >= $totalCnt} {
93 _close_updateindex $fd $after
98 {$update_index_cp < $totalCnt && $i > 0} \
100 set path [lindex $pathList $update_index_cp]
103 set s $file_states($path)
104 switch -glob -- [lindex $s 0] {
112 set info [lindex $s 2]
113 if {$info eq {}} continue
115 puts -nonewline $fd "$info\t[encoding convertto $path]\0"
116 display_file $path $new
119 $::main_status update $update_index_cp $totalCnt
122 proc update_index {msg pathList after} {
123 global update_index_cp
125 if {![lock_index update]} return
127 set update_index_cp 0
128 set pathList [lsort $pathList]
129 set totalCnt [llength $pathList]
130 set batch [expr {int($totalCnt * .01) + 1}]
131 if {$batch > 25} {set batch 25}
133 $::main_status start $msg [mc "files"]
134 set fd [git_write update-index --add --remove -z --stdin]
141 fileevent $fd writable [list \
151 proc write_update_index {fd pathList totalCnt batch after} {
152 global update_index_cp
153 global file_states current_diff_path
155 if {$update_index_cp >= $totalCnt} {
156 _close_updateindex $fd $after
161 {$update_index_cp < $totalCnt && $i > 0} \
163 set path [lindex $pathList $update_index_cp]
166 switch -glob -- [lindex $file_states($path) 0] {
174 if {[file exists $path]} {
183 puts -nonewline $fd "[encoding convertto $path]\0"
184 display_file $path $new
187 $::main_status update $update_index_cp $totalCnt
190 proc checkout_index {msg pathList after} {
191 global update_index_cp
193 if {![lock_index update]} return
195 set update_index_cp 0
196 set pathList [lsort $pathList]
197 set totalCnt [llength $pathList]
198 set batch [expr {int($totalCnt * .01) + 1}]
199 if {$batch > 25} {set batch 25}
201 $::main_status start $msg [mc "files"]
202 set fd [git_write checkout-index \
215 fileevent $fd writable [list \
216 write_checkout_index \
225 proc write_checkout_index {fd pathList totalCnt batch after} {
226 global update_index_cp
227 global file_states current_diff_path
229 if {$update_index_cp >= $totalCnt} {
230 _close_updateindex $fd $after
235 {$update_index_cp < $totalCnt && $i > 0} \
237 set path [lindex $pathList $update_index_cp]
239 switch -glob -- [lindex $file_states($path) 0] {
244 puts -nonewline $fd "[encoding convertto $path]\0"
245 display_file $path ?_
250 $::main_status update $update_index_cp $totalCnt
253 proc unstage_helper {txt paths} {
254 global file_states current_diff_path
256 if {![lock_index begin-update]} return
260 foreach path $paths {
261 switch -glob -- [lindex $file_states($path) 0] {
266 lappend pathList $path
267 if {$path eq $current_diff_path} {
268 set after {reshow_diff;}
273 if {$pathList eq {}} {
279 [concat $after [list ui_ready]]
283 proc do_unstage_selection {} {
284 global current_diff_path selected_paths
286 if {[array size selected_paths] > 0} {
288 {Unstaging selected files from commit} \
289 [array names selected_paths]
290 } elseif {$current_diff_path ne {}} {
292 [mc "Unstaging %s from commit" [short_path $current_diff_path]] \
293 [list $current_diff_path]
297 proc add_helper {txt paths} {
298 global file_states current_diff_path
300 if {![lock_index begin-update]} return
304 foreach path $paths {
305 switch -glob -- [lindex $file_states($path) 0] {
308 if {$path eq $current_diff_path} {
310 merge_stage_workdir $path
318 lappend pathList $path
319 if {$path eq $current_diff_path} {
320 set after {reshow_diff;}
325 if {$pathList eq {}} {
331 [concat $after {ui_status [mc "Ready to commit."]}]
335 proc do_add_selection {} {
336 global current_diff_path selected_paths
338 if {[array size selected_paths] > 0} {
340 {Adding selected files} \
341 [array names selected_paths]
342 } elseif {$current_diff_path ne {}} {
344 [mc "Adding %s" [short_path $current_diff_path]] \
345 [list $current_diff_path]
353 foreach path [array names file_states] {
354 switch -glob -- [lindex $file_states($path) 0] {
358 ?D {lappend paths $path}
361 add_helper {Adding all changed files} $paths
364 proc revert_helper {txt paths} {
365 global file_states current_diff_path
367 if {![lock_index begin-update]} return
371 foreach path $paths {
372 switch -glob -- [lindex $file_states($path) 0] {
377 lappend pathList $path
378 if {$path eq $current_diff_path} {
379 set after {reshow_diff;}
386 # Split question between singular and plural cases, because
387 # such distinction is needed in some languages. Previously, the
388 # code used "Revert changes in" for both, but that can't work
389 # in languages where 'in' must be combined with word from
390 # rest of string (in diffrent way for both cases of course).
392 # FIXME: Unfortunately, even that isn't enough in some languages
393 # as they have quite complex plural-form rules. Unfortunately,
394 # msgcat doesn't seem to support that kind of string translation.
396 set n [llength $pathList]
401 set query [mc "Revert changes in file %s?" [short_path [lindex $pathList]]]
403 set query [mc "Revert changes in these %i files?" $n]
406 set reply [tk_dialog \
408 "[appname] ([reponame])" \
411 [mc "Any unstaged changes will be permanently lost by the revert."]" \
415 [mc "Revert Changes"] \
421 [concat $after [list ui_ready]]
427 proc do_revert_selection {} {
428 global current_diff_path selected_paths
430 if {[array size selected_paths] > 0} {
432 [mc "Reverting selected files"] \
433 [array names selected_paths]
434 } elseif {$current_diff_path ne {}} {
436 [mc "Reverting %s" [short_path $current_diff_path]] \
437 [list $current_diff_path]
441 proc do_select_commit_type {} {
442 global commit_type selected_commit_type
444 if {$selected_commit_type eq {new}
445 && [string match amend* $commit_type]} {
447 } elseif {$selected_commit_type eq {amend}
448 && ![string match amend* $commit_type]} {
451 # The amend request was rejected...
453 if {![string match amend* $commit_type]} {
454 set selected_commit_type new