git-gui: Reimplement and enhance auto-selection of diffs.
Generalize the next_diff system, and implement auto-reselection for merge tool resolution and reshow_diff. Also add auto-selection of diffs after rescan, if no diff is already selected. New auto-select rules: - Rescan auto-selects the first conflicting file, or if none a modified tracked file, if nothing was selected previously. - Resolving a conflict auto-selects the nearest conflicting file, or nothing if everything is resolved. - Staging the last remaining hunk auto-selects the nearest modified staged file. - Staging a file through its icon auto-selects the nearest file. Signed-off-by: Alexander Gavrilov <angavrilov@gmail.com> Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
This commit is contained in:
parent
ff515d81fa
commit
29853b9010
122
git-gui.sh
122
git-gui.sh
@ -1326,6 +1326,8 @@ proc rescan_done {fd buf after} {
|
|||||||
unlock_index
|
unlock_index
|
||||||
display_all_files
|
display_all_files
|
||||||
if {$current_diff_path ne {}} reshow_diff
|
if {$current_diff_path ne {}} reshow_diff
|
||||||
|
if {$current_diff_path eq {}} select_first_diff
|
||||||
|
|
||||||
uplevel #0 $after
|
uplevel #0 $after
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1821,7 +1823,98 @@ proc do_commit {} {
|
|||||||
|
|
||||||
proc next_diff {} {
|
proc next_diff {} {
|
||||||
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 $next_diff_i
|
show_diff $next_diff_p $next_diff_w {}
|
||||||
|
}
|
||||||
|
|
||||||
|
proc find_anchor_pos {lst name} {
|
||||||
|
set lid [lsearch -sorted -exact $lst $name]
|
||||||
|
|
||||||
|
if {$lid == -1} {
|
||||||
|
set lid 0
|
||||||
|
foreach lname $lst {
|
||||||
|
if {$lname >= $name} break
|
||||||
|
incr lid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $lid
|
||||||
|
}
|
||||||
|
|
||||||
|
proc find_file_from {flist idx delta path mmask} {
|
||||||
|
global file_states
|
||||||
|
|
||||||
|
set len [llength $flist]
|
||||||
|
while {$idx >= 0 && $idx < $len} {
|
||||||
|
set name [lindex $flist $idx]
|
||||||
|
|
||||||
|
if {$name ne $path && [info exists file_states($name)]} {
|
||||||
|
set state [lindex $file_states($name) 0]
|
||||||
|
|
||||||
|
if {$mmask eq {} || [regexp $mmask $state]} {
|
||||||
|
return $idx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
incr idx $delta
|
||||||
|
}
|
||||||
|
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
|
||||||
|
proc find_next_diff {w path {lno {}} {mmask {}}} {
|
||||||
|
global next_diff_p next_diff_w next_diff_i
|
||||||
|
global file_lists ui_index ui_workdir
|
||||||
|
|
||||||
|
set flist $file_lists($w)
|
||||||
|
if {$lno eq {}} {
|
||||||
|
set lno [find_anchor_pos $flist $path]
|
||||||
|
} else {
|
||||||
|
incr lno -1
|
||||||
|
}
|
||||||
|
|
||||||
|
if {$mmask ne {} && ![regexp {(^\^)|(\$$)} $mmask]} {
|
||||||
|
if {$w eq $ui_index} {
|
||||||
|
set mmask "^$mmask"
|
||||||
|
} else {
|
||||||
|
set mmask "$mmask\$"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set idx [find_file_from $flist $lno 1 $path $mmask]
|
||||||
|
if {$idx eq {}} {
|
||||||
|
incr lno -1
|
||||||
|
set idx [find_file_from $flist $lno -1 $path $mmask]
|
||||||
|
}
|
||||||
|
|
||||||
|
if {$idx ne {}} {
|
||||||
|
set next_diff_w $w
|
||||||
|
set next_diff_p [lindex $flist $idx]
|
||||||
|
set next_diff_i [expr {$idx+1}]
|
||||||
|
return 1
|
||||||
|
} else {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
proc next_diff_after_action {w path {lno {}} {mmask {}}} {
|
||||||
|
global current_diff_path
|
||||||
|
|
||||||
|
if {$path ne $current_diff_path} {
|
||||||
|
return {}
|
||||||
|
} elseif {[find_next_diff $w $path $lno $mmask]} {
|
||||||
|
return {next_diff;}
|
||||||
|
} else {
|
||||||
|
return {reshow_diff;}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
proc select_first_diff {} {
|
||||||
|
global ui_workdir
|
||||||
|
|
||||||
|
if {[find_next_diff $ui_workdir {} 1 {^_?U}] ||
|
||||||
|
[find_next_diff $ui_workdir {} 1 {[^O]$}]} {
|
||||||
|
next_diff
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
proc toggle_or_diff {w x y} {
|
proc toggle_or_diff {w x y} {
|
||||||
@ -1851,32 +1944,7 @@ proc toggle_or_diff {w x y} {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if {$col == 0 && $y > 1} {
|
if {$col == 0 && $y > 1} {
|
||||||
set i [expr {$lno-1}]
|
set after [next_diff_after_action $w $path $lno]
|
||||||
set ll [expr {[llength $file_lists($w)]-1}]
|
|
||||||
|
|
||||||
if {$i == $ll && $i == 0} {
|
|
||||||
set after {reshow_diff;}
|
|
||||||
} else {
|
|
||||||
global next_diff_p next_diff_w next_diff_i
|
|
||||||
|
|
||||||
set next_diff_w $w
|
|
||||||
|
|
||||||
if {$i < $ll} {
|
|
||||||
set i [expr {$i + 1}]
|
|
||||||
set next_diff_i $i
|
|
||||||
} else {
|
|
||||||
set next_diff_i $i
|
|
||||||
set i [expr {$i - 1}]
|
|
||||||
}
|
|
||||||
|
|
||||||
set next_diff_p [lindex $file_lists($w) $i]
|
|
||||||
|
|
||||||
if {$next_diff_p ne {} && $current_diff_path ne {}} {
|
|
||||||
set after {next_diff;}
|
|
||||||
} else {
|
|
||||||
set after {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if {$w eq $ui_index} {
|
if {$w eq $ui_index} {
|
||||||
update_indexinfo \
|
update_indexinfo \
|
||||||
|
18
lib/diff.tcl
18
lib/diff.tcl
@ -24,10 +24,16 @@ proc reshow_diff {} {
|
|||||||
set p $current_diff_path
|
set p $current_diff_path
|
||||||
if {$p eq {}} {
|
if {$p eq {}} {
|
||||||
# No diff is being shown.
|
# No diff is being shown.
|
||||||
} elseif {$current_diff_side eq {}
|
} elseif {$current_diff_side eq {}} {
|
||||||
|| [catch {set s $file_states($p)}]
|
|
||||||
|| [lsearch -sorted -exact $file_lists($current_diff_side) $p] == -1} {
|
|
||||||
clear_diff
|
clear_diff
|
||||||
|
} elseif {[catch {set s $file_states($p)}]
|
||||||
|
|| [lsearch -sorted -exact $file_lists($current_diff_side) $p] == -1} {
|
||||||
|
|
||||||
|
if {[find_next_diff $current_diff_side $p {} {[^O]}]} {
|
||||||
|
next_diff
|
||||||
|
} else {
|
||||||
|
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
|
||||||
@ -71,6 +77,7 @@ proc show_diff {path w {lno {}} {scroll_pos {}}} {
|
|||||||
}
|
}
|
||||||
if {$lno >= 1} {
|
if {$lno >= 1} {
|
||||||
$w tag add in_diff $lno.0 [expr {$lno + 1}].0
|
$w tag add in_diff $lno.0 [expr {$lno + 1}].0
|
||||||
|
$w see $lno.0
|
||||||
}
|
}
|
||||||
|
|
||||||
set s $file_states($path)
|
set s $file_states($path)
|
||||||
@ -366,10 +373,9 @@ proc apply_hunk {x y} {
|
|||||||
}
|
}
|
||||||
unlock_index
|
unlock_index
|
||||||
display_file $current_diff_path $mi
|
display_file $current_diff_path $mi
|
||||||
|
# This should trigger shift to the next changed file
|
||||||
if {$o eq {_}} {
|
if {$o eq {_}} {
|
||||||
clear_diff
|
reshow_diff
|
||||||
} else {
|
|
||||||
set current_diff_path $current_diff_path
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,13 +24,9 @@ This operation can be undone only by restarting the merge." \
|
|||||||
}
|
}
|
||||||
|
|
||||||
proc merge_add_resolution {path} {
|
proc merge_add_resolution {path} {
|
||||||
global current_diff_path
|
global current_diff_path ui_workdir
|
||||||
|
|
||||||
if {$path eq $current_diff_path} {
|
set after [next_diff_after_action $ui_workdir $path {} {^_?U}]
|
||||||
set after {reshow_diff;}
|
|
||||||
} else {
|
|
||||||
set after {}
|
|
||||||
}
|
|
||||||
|
|
||||||
update_index \
|
update_index \
|
||||||
[mc "Adding resolution for %s" [short_path $path]] \
|
[mc "Adding resolution for %s" [short_path $path]] \
|
||||||
|
Loading…
Reference in New Issue
Block a user