| # git-gui index (add/remove) support | |
| # Copyright (C) 2006, 2007 Shawn Pearce | |
| proc _delete_indexlock {} { | |
| if {[catch {file delete -- [gitdir index.lock]} err]} { | |
| error_popup [strcat [mc "Unable to unlock the index."] "\n\n$err"] | |
| } | |
| } | |
| proc _close_updateindex {fd after} { | |
| fconfigure $fd -blocking 1 | |
| if {[catch {close $fd} err]} { | |
| set w .indexfried | |
| toplevel $w | |
| wm title $w [strcat "[appname] ([reponame]): " [mc "Index Error"]] | |
| wm geometry $w "+[winfo rootx .]+[winfo rooty .]" | |
| pack [label $w.msg \ | |
| -justify left \ | |
| -anchor w \ | |
| -text [strcat \ | |
| [mc "Updating the Git index failed. A rescan will be automatically started to resynchronize git-gui."] \ | |
| "\n\n$err"] \ | |
| ] -anchor w | |
| frame $w.buttons | |
| button $w.buttons.continue \ | |
| -text [mc "Continue"] \ | |
| -command [list destroy $w] | |
| pack $w.buttons.continue -side right -padx 5 | |
| button $w.buttons.unlock \ | |
| -text [mc "Unlock Index"] \ | |
| -command "destroy $w; _delete_indexlock" | |
| pack $w.buttons.unlock -side right | |
| pack $w.buttons -side bottom -fill x -pady 10 -padx 10 | |
| wm protocol $w WM_DELETE_WINDOW update | |
| bind $w.buttons.continue <Visibility> " | |
| grab $w | |
| focus $w.buttons.continue | |
| " | |
| tkwait window $w | |
| $::main_status stop | |
| unlock_index | |
| rescan $after 0 | |
| return | |
| } | |
| $::main_status stop | |
| unlock_index | |
| uplevel #0 $after | |
| } | |
| proc update_indexinfo {msg pathList after} { | |
| global update_index_cp | |
| if {![lock_index update]} return | |
| set update_index_cp 0 | |
| set pathList [lsort $pathList] | |
| set totalCnt [llength $pathList] | |
| set batch [expr {int($totalCnt * .01) + 1}] | |
| if {$batch > 25} {set batch 25} | |
| $::main_status start $msg [mc "files"] | |
| set fd [git_write update-index -z --index-info] | |
| fconfigure $fd \ | |
| -blocking 0 \ | |
| -buffering full \ | |
| -buffersize 512 \ | |
| -encoding binary \ | |
| -translation binary | |
| fileevent $fd writable [list \ | |
| write_update_indexinfo \ | |
| $fd \ | |
| $pathList \ | |
| $totalCnt \ | |
| $batch \ | |
| $after \ | |
| ] | |
| } | |
| proc write_update_indexinfo {fd pathList totalCnt batch after} { | |
| global update_index_cp | |
| global file_states current_diff_path | |
| if {$update_index_cp >= $totalCnt} { | |
| _close_updateindex $fd $after | |
| return | |
| } | |
| for {set i $batch} \ | |
| {$update_index_cp < $totalCnt && $i > 0} \ | |
| {incr i -1} { | |
| set path [lindex $pathList $update_index_cp] | |
| incr update_index_cp | |
| set s $file_states($path) | |
| switch -glob -- [lindex $s 0] { | |
| A? {set new _O} | |
| M? {set new _M} | |
| T_ {set new _T} | |
| D_ {set new _D} | |
| D? {set new _?} | |
| ?? {continue} | |
| } | |
| set info [lindex $s 2] | |
| if {$info eq {}} continue | |
| puts -nonewline $fd "$info\t[encoding convertto $path]\0" | |
| display_file $path $new | |
| } | |
| $::main_status update $update_index_cp $totalCnt | |
| } | |
| proc update_index {msg pathList after} { | |
| global update_index_cp | |
| if {![lock_index update]} return | |
| set update_index_cp 0 | |
| set pathList [lsort $pathList] | |
| set totalCnt [llength $pathList] | |
| set batch [expr {int($totalCnt * .01) + 1}] | |
| if {$batch > 25} {set batch 25} | |
| $::main_status start $msg [mc "files"] | |
| set fd [git_write update-index --add --remove -z --stdin] | |
| fconfigure $fd \ | |
| -blocking 0 \ | |
| -buffering full \ | |
| -buffersize 512 \ | |
| -encoding binary \ | |
| -translation binary | |
| fileevent $fd writable [list \ | |
| write_update_index \ | |
| $fd \ | |
| $pathList \ | |
| $totalCnt \ | |
| $batch \ | |
| $after \ | |
| ] | |
| } | |
| proc write_update_index {fd pathList totalCnt batch after} { | |
| global update_index_cp | |
| global file_states current_diff_path | |
| if {$update_index_cp >= $totalCnt} { | |
| _close_updateindex $fd $after | |
| return | |
| } | |
| for {set i $batch} \ | |
| {$update_index_cp < $totalCnt && $i > 0} \ | |
| {incr i -1} { | |
| set path [lindex $pathList $update_index_cp] | |
| incr update_index_cp | |
| switch -glob -- [lindex $file_states($path) 0] { | |
| AD {set new __} | |
| ?D {set new D_} | |
| _O - | |
| AM {set new A_} | |
| _T {set new T_} | |
| _U - | |
| U? { | |
| if {[file exists $path]} { | |
| set new M_ | |
| } else { | |
| set new D_ | |
| } | |
| } | |
| ?M {set new M_} | |
| ?? {continue} | |
| } | |
| puts -nonewline $fd "[encoding convertto $path]\0" | |
| display_file $path $new | |
| } | |
| $::main_status update $update_index_cp $totalCnt | |
| } | |
| proc checkout_index {msg pathList after} { | |
| global update_index_cp | |
| if {![lock_index update]} return | |
| set update_index_cp 0 | |
| set pathList [lsort $pathList] | |
| set totalCnt [llength $pathList] | |
| set batch [expr {int($totalCnt * .01) + 1}] | |
| if {$batch > 25} {set batch 25} | |
| $::main_status start $msg [mc "files"] | |
| set fd [git_write checkout-index \ | |
| --index \ | |
| --quiet \ | |
| --force \ | |
| -z \ | |
| --stdin \ | |
| ] | |
| fconfigure $fd \ | |
| -blocking 0 \ | |
| -buffering full \ | |
| -buffersize 512 \ | |
| -encoding binary \ | |
| -translation binary | |
| fileevent $fd writable [list \ | |
| write_checkout_index \ | |
| $fd \ | |
| $pathList \ | |
| $totalCnt \ | |
| $batch \ | |
| $after \ | |
| ] | |
| } | |
| proc write_checkout_index {fd pathList totalCnt batch after} { | |
| global update_index_cp | |
| global file_states current_diff_path | |
| if {$update_index_cp >= $totalCnt} { | |
| _close_updateindex $fd $after | |
| return | |
| } | |
| for {set i $batch} \ | |
| {$update_index_cp < $totalCnt && $i > 0} \ | |
| {incr i -1} { | |
| set path [lindex $pathList $update_index_cp] | |
| incr update_index_cp | |
| switch -glob -- [lindex $file_states($path) 0] { | |
| U? {continue} | |
| ?M - | |
| ?T - | |
| ?D { | |
| puts -nonewline $fd "[encoding convertto $path]\0" | |
| display_file $path ?_ | |
| } | |
| } | |
| } | |
| $::main_status update $update_index_cp $totalCnt | |
| } | |
| proc unstage_helper {txt paths} { | |
| global file_states current_diff_path | |
| if {![lock_index begin-update]} return | |
| set pathList [list] | |
| set after {} | |
| foreach path $paths { | |
| switch -glob -- [lindex $file_states($path) 0] { | |
| A? - | |
| M? - | |
| T_ - | |
| D? { | |
| lappend pathList $path | |
| if {$path eq $current_diff_path} { | |
| set after {reshow_diff;} | |
| } | |
| } | |
| } | |
| } | |
| if {$pathList eq {}} { | |
| unlock_index | |
| } else { | |
| update_indexinfo \ | |
| $txt \ | |
| $pathList \ | |
| [concat $after [list ui_ready]] | |
| } | |
| } | |
| proc do_unstage_selection {} { | |
| global current_diff_path selected_paths | |
| if {[array size selected_paths] > 0} { | |
| unstage_helper \ | |
| {Unstaging selected files from commit} \ | |
| [array names selected_paths] | |
| } elseif {$current_diff_path ne {}} { | |
| unstage_helper \ | |
| [mc "Unstaging %s from commit" [short_path $current_diff_path]] \ | |
| [list $current_diff_path] | |
| } | |
| } | |
| proc add_helper {txt paths} { | |
| global file_states current_diff_path | |
| if {![lock_index begin-update]} return | |
| set pathList [list] | |
| set after {} | |
| foreach path $paths { | |
| switch -glob -- [lindex $file_states($path) 0] { | |
| _U - | |
| U? { | |
| if {$path eq $current_diff_path} { | |
| unlock_index | |
| merge_stage_workdir $path | |
| return | |
| } | |
| } | |
| _O - | |
| ?M - | |
| ?D - | |
| ?T { | |
| lappend pathList $path | |
| if {$path eq $current_diff_path} { | |
| set after {reshow_diff;} | |
| } | |
| } | |
| } | |
| } | |
| if {$pathList eq {}} { | |
| unlock_index | |
| } else { | |
| update_index \ | |
| $txt \ | |
| $pathList \ | |
| [concat $after {ui_status [mc "Ready to commit."]}] | |
| } | |
| } | |
| proc do_add_selection {} { | |
| global current_diff_path selected_paths | |
| if {[array size selected_paths] > 0} { | |
| add_helper \ | |
| {Adding selected files} \ | |
| [array names selected_paths] | |
| } elseif {$current_diff_path ne {}} { | |
| add_helper \ | |
| [mc "Adding %s" [short_path $current_diff_path]] \ | |
| [list $current_diff_path] | |
| } | |
| } | |
| proc do_add_all {} { | |
| global file_states | |
| set paths [list] | |
| foreach path [array names file_states] { | |
| switch -glob -- [lindex $file_states($path) 0] { | |
| U? {continue} | |
| ?M - | |
| ?T - | |
| ?D {lappend paths $path} | |
| } | |
| } | |
| add_helper {Adding all changed files} $paths | |
| } | |
| proc revert_helper {txt paths} { | |
| global file_states current_diff_path | |
| if {![lock_index begin-update]} return | |
| set pathList [list] | |
| set after {} | |
| foreach path $paths { | |
| switch -glob -- [lindex $file_states($path) 0] { | |
| U? {continue} | |
| ?M - | |
| ?T - | |
| ?D { | |
| lappend pathList $path | |
| if {$path eq $current_diff_path} { | |
| set after {reshow_diff;} | |
| } | |
| } | |
| } | |
| } | |
| # Split question between singular and plural cases, because | |
| # such distinction is needed in some languages. Previously, the | |
| # code used "Revert changes in" for both, but that can't work | |
| # in languages where 'in' must be combined with word from | |
| # rest of string (in diffrent way for both cases of course). | |
| # | |
| # FIXME: Unfortunately, even that isn't enough in some languages | |
| # as they have quite complex plural-form rules. Unfortunately, | |
| # msgcat doesn't seem to support that kind of string translation. | |
| # | |
| set n [llength $pathList] | |
| if {$n == 0} { | |
| unlock_index | |
| return | |
| } elseif {$n == 1} { | |
| set query [mc "Revert changes in file %s?" [short_path [lindex $pathList]]] | |
| } else { | |
| set query [mc "Revert changes in these %i files?" $n] | |
| } | |
| set reply [tk_dialog \ | |
| .confirm_revert \ | |
| "[appname] ([reponame])" \ | |
| "$query | |
| [mc "Any unstaged changes will be permanently lost by the revert."]" \ | |
| question \ | |
| 1 \ | |
| [mc "Do Nothing"] \ | |
| [mc "Revert Changes"] \ | |
| ] | |
| if {$reply == 1} { | |
| checkout_index \ | |
| $txt \ | |
| $pathList \ | |
| [concat $after [list ui_ready]] | |
| } else { | |
| unlock_index | |
| } | |
| } | |
| proc do_revert_selection {} { | |
| global current_diff_path selected_paths | |
| if {[array size selected_paths] > 0} { | |
| revert_helper \ | |
| [mc "Reverting selected files"] \ | |
| [array names selected_paths] | |
| } elseif {$current_diff_path ne {}} { | |
| revert_helper \ | |
| [mc "Reverting %s" [short_path $current_diff_path]] \ | |
| [list $current_diff_path] | |
| } | |
| } | |
| proc do_select_commit_type {} { | |
| global commit_type selected_commit_type | |
| if {$selected_commit_type eq {new} | |
| && [string match amend* $commit_type]} { | |
| create_new_commit | |
| } elseif {$selected_commit_type eq {amend} | |
| && ![string match amend* $commit_type]} { | |
| load_last_commit | |
| # The amend request was rejected... | |
| # | |
| if {![string match amend* $commit_type]} { | |
| set selected_commit_type new | |
| } | |
| } | |
| } |