| # 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} { |
| global use_ttk NS |
| fconfigure $fd -blocking 1 |
| if {[catch {close $fd} err]} { |
| set w .indexfried |
| Dialog $w |
| wm withdraw $w |
| wm title $w [strcat "[appname] ([reponame]): " [mc "Index Error"]] |
| wm geometry $w "+[winfo rootx .]+[winfo rooty .]" |
| set s [mc "Updating the Git index failed. A rescan will be automatically started to resynchronize git-gui."] |
| text $w.msg -yscrollcommand [list $w.vs set] \ |
| -width [string length $s] -relief flat \ |
| -borderwidth 0 -highlightthickness 0 \ |
| -background [get_bg_color $w] |
| $w.msg tag configure bold -font font_uibold -justify center |
| ${NS}::scrollbar $w.vs -command [list $w.msg yview] |
| $w.msg insert end $s bold \n\n$err {} |
| $w.msg configure -state disabled |
| |
| ${NS}::button $w.continue \ |
| -text [mc "Continue"] \ |
| -command [list destroy $w] |
| ${NS}::button $w.unlock \ |
| -text [mc "Unlock Index"] \ |
| -command "destroy $w; _delete_indexlock" |
| grid $w.msg - $w.vs -sticky news |
| grid $w.unlock $w.continue - -sticky se -padx 2 -pady 2 |
| grid columnconfigure $w 0 -weight 1 |
| grid rowconfigure $w 0 -weight 1 |
| |
| wm protocol $w WM_DELETE_WINDOW update |
| bind $w.continue <Visibility> " |
| grab $w |
| focus %W |
| " |
| wm deiconify $w |
| 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} |
| MT - |
| TM - |
| T_ {set new _T} |
| M? {set new _M} |
| TD - |
| D_ {set new _D} |
| D? {set new _?} |
| ?? {continue} |
| } |
| set info [lindex $s 2] |
| if {$info eq {}} continue |
| |
| puts -nonewline $fd "$info\t[encoding convertto utf-8 $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 - |
| AT - |
| AM {set new A_} |
| TM - |
| MT - |
| _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 utf-8 $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 utf-8 $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 \ |
| [mc "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 \ |
| [mc "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] |
| set untracked_paths [list] |
| foreach path [array names file_states] { |
| switch -glob -- [lindex $file_states($path) 0] { |
| U? {continue} |
| ?M - |
| ?T - |
| ?D {lappend paths $path} |
| ?O {lappend untracked_paths $path} |
| } |
| } |
| if {[llength $untracked_paths]} { |
| set reply 0 |
| switch -- [get_config gui.stageuntracked] { |
| no { |
| set reply 0 |
| } |
| yes { |
| set reply 1 |
| } |
| ask - |
| default { |
| set reply [ask_popup [mc "Stage %d untracked files?" \ |
| [llength $untracked_paths]]] |
| } |
| } |
| if {$reply} { |
| set paths [concat $paths $untracked_paths] |
| } |
| } |
| add_helper [mc "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 different 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 |
| } |
| } |
| } |