git-gui: Fix the after callback execution in rescan.

The rescan function receives a callback command
as its parameter, which is supposed to be executed
after the scan finishes. It is generally used to
update status. However, rescan may initiate a
loading of a diff, which always calls ui_ready after
completion. If the after handler is called before
that, ui_ready will override the new status.

This commit ensures that the after callback is
properly threaded through the diff machinery.

Since it uncovered the fact that force_first_diff
actually didn't work due to an undeclared global
variable, and the desired effects appeared only
because of the race condition between the diff
system and the rescan callback, I also reimplement
this function to make it behave as originally
intended.

Signed-off-by: Alexander Gavrilov <angavrilov@gmail.com>
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
This commit is contained in:
Alexander Gavrilov 2008-11-16 21:46:48 +03:00 committed by Shawn O. Pearce
parent 153ad78b50
commit 7cf4566f48
2 changed files with 32 additions and 17 deletions

View File

@ -1491,10 +1491,8 @@ proc rescan_done {fd buf after} {
prune_selection prune_selection
unlock_index unlock_index
display_all_files display_all_files
if {$current_diff_path ne {}} reshow_diff if {$current_diff_path ne {}} { reshow_diff $after }
if {$current_diff_path eq {}} select_first_diff if {$current_diff_path eq {}} { select_first_diff $after }
uplevel #0 $after
} }
proc prune_selection {} { proc prune_selection {} {
@ -2006,16 +2004,16 @@ proc do_rescan {} {
} }
proc ui_do_rescan {} { proc ui_do_rescan {} {
rescan {force_first_diff; ui_ready} rescan {force_first_diff ui_ready}
} }
proc do_commit {} { proc do_commit {} {
commit_tree commit_tree
} }
proc next_diff {} { proc next_diff {{after {}}} {
global next_diff_p next_diff_w next_diff_i global next_diff_p next_diff_w next_diff_i
show_diff $next_diff_p $next_diff_w {} show_diff $next_diff_p $next_diff_w {} {} $after
} }
proc find_anchor_pos {lst name} { proc find_anchor_pos {lst name} {
@ -2100,25 +2098,42 @@ proc next_diff_after_action {w path {lno {}} {mmask {}}} {
} }
} }
proc select_first_diff {} { proc select_first_diff {after} {
global ui_workdir global ui_workdir
if {[find_next_diff $ui_workdir {} 1 {^_?U}] || if {[find_next_diff $ui_workdir {} 1 {^_?U}] ||
[find_next_diff $ui_workdir {} 1 {[^O]$}]} { [find_next_diff $ui_workdir {} 1 {[^O]$}]} {
next_diff next_diff $after
} else {
uplevel #0 $after
} }
} }
proc force_first_diff {} { proc force_first_diff {after} {
global current_diff_path global ui_workdir current_diff_path file_states
if {[info exists file_states($current_diff_path)]} { if {[info exists file_states($current_diff_path)]} {
set state [lindex $file_states($current_diff_path) 0] set state [lindex $file_states($current_diff_path) 0]
} else {
if {[string index $state 1] ne {O}} return set state {OO}
} }
select_first_diff set reselect 0
if {[string first {U} $state] >= 0} {
# Already a conflict, do nothing
} elseif {[find_next_diff $ui_workdir $current_diff_path {} {^_?U}]} {
set reselect 1
} elseif {[string index $state 1] ne {O}} {
# Already a diff & no conflicts, do nothing
} elseif {[find_next_diff $ui_workdir $current_diff_path {} {[^O]$}]} {
set reselect 1
}
if {$reselect} {
next_diff $after
} else {
uplevel #0 $after
}
} }
proc toggle_or_diff {w x y} { proc toggle_or_diff {w x y} {

View File

@ -16,7 +16,7 @@ proc clear_diff {} {
$ui_workdir tag remove in_diff 0.0 end $ui_workdir tag remove in_diff 0.0 end
} }
proc reshow_diff {} { proc reshow_diff {{after {}}} {
global file_states file_lists global file_states file_lists
global current_diff_path current_diff_side global current_diff_path current_diff_side
global ui_diff global ui_diff
@ -30,13 +30,13 @@ proc reshow_diff {} {
|| [lsearch -sorted -exact $file_lists($current_diff_side) $p] == -1} { || [lsearch -sorted -exact $file_lists($current_diff_side) $p] == -1} {
if {[find_next_diff $current_diff_side $p {} {[^O]}]} { if {[find_next_diff $current_diff_side $p {} {[^O]}]} {
next_diff next_diff $after
} else { } else {
clear_diff clear_diff
} }
} else { } else {
set save_pos [lindex [$ui_diff yview] 0] set save_pos [lindex [$ui_diff yview] 0]
show_diff $p $current_diff_side {} $save_pos show_diff $p $current_diff_side {} $save_pos $after
} }
} }