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>
Alexander Gavrilov committed
Aug 31, 2008 at 01:02 UTC
29853b901045ff09ac8e5b48a01ebbc96fa4874d
3 files changed
+109
-39
git-gui.sh
+95
-27
@@ -1326,6 +1326,8 @@ proc rescan_done {fd buf after} {
1326
unlock_index
1327
display_all_files
1328
if {$current_diff_path ne {}} reshow_diff
1329
+ if {$current_diff_path eq {}} select_first_diff
1330
+
1331
uplevel #0 $after
1332
}
1333
@@ -1821,7 +1823,98 @@ proc do_commit {} {
1823
1824
proc next_diff {} {
1825
global next_diff_p next_diff_w next_diff_i
1824
- show_diff $next_diff_p $next_diff_w $next_diff_i
1826
+ show_diff $next_diff_p $next_diff_w {}
1827
+}
1828
+
1829
+proc find_anchor_pos {lst name} {
1830
+ set lid [lsearch -sorted -exact $lst $name]
1831
+
1832
+ if {$lid == -1} {
1833
+ set lid 0
1834
+ foreach lname $lst {
1835
+ if {$lname >= $name} break
1836
+ incr lid
1837
+ }
1838
+ }
1839
+
1840
+ return $lid
1841
+}
1842
+
1843
+proc find_file_from {flist idx delta path mmask} {
1844
+ global file_states
1845
+
1846
+ set len [llength $flist]
1847
+ while {$idx >= 0 && $idx < $len} {
1848
+ set name [lindex $flist $idx]
1849
+
1850
+ if {$name ne $path && [info exists file_states($name)]} {
1851
+ set state [lindex $file_states($name) 0]
1852
+
1853
+ if {$mmask eq {} || [regexp $mmask $state]} {
1854
+ return $idx
1855
+ }
1856
+ }
1857
+
1858
+ incr idx $delta
1859
+ }
1860
+
1861
+ return {}
1862
+}
1863
+
1864
+proc find_next_diff {w path {lno {}} {mmask {}}} {
1865
+ global next_diff_p next_diff_w next_diff_i
1866
+ global file_lists ui_index ui_workdir
1867
+
1868
+ set flist $file_lists($w)
1869
+ if {$lno eq {}} {
1870
+ set lno [find_anchor_pos $flist $path]
1871
+ } else {
1872
+ incr lno -1
1873
+ }
1874
+
1875
+ if {$mmask ne {} && ![regexp {(^\^)|(\$$)} $mmask]} {
1876
+ if {$w eq $ui_index} {
1877
+ set mmask "^$mmask"
1878
+ } else {
1879
+ set mmask "$mmask\$"
1880
+ }
1881
+ }
1882
+
1883
+ set idx [find_file_from $flist $lno 1 $path $mmask]
1884
+ if {$idx eq {}} {
1885
+ incr lno -1
1886
+ set idx [find_file_from $flist $lno -1 $path $mmask]
1887
+ }
1888
+
1889
+ if {$idx ne {}} {
1890
+ set next_diff_w $w
1891
+ set next_diff_p [lindex $flist $idx]
1892
+ set next_diff_i [expr {$idx+1}]
1893
+ return 1
1894
+ } else {
1895
+ return 0
1896
+ }
1897
+}
1898
+
1899
+proc next_diff_after_action {w path {lno {}} {mmask {}}} {
1900
+ global current_diff_path
1901
+
1902
+ if {$path ne $current_diff_path} {
1903
+ return {}
1904
+ } elseif {[find_next_diff $w $path $lno $mmask]} {
1905
+ return {next_diff;}
1906
+ } else {
1907
+ return {reshow_diff;}
1908
+ }
1909
+}
1910
+
1911
+proc select_first_diff {} {
1912
+ global ui_workdir
1913
+
1914
+ if {[find_next_diff $ui_workdir {} 1 {^_?U}] ||
1915
+ [find_next_diff $ui_workdir {} 1 {[^O]$}]} {
1916
+ next_diff
1917
+ }
1918
}
1919
1920
proc toggle_or_diff {w x y} {
@@ -1851,32 +1944,7 @@ proc toggle_or_diff {w x y} {
1944
}
1945
1946
if {$col == 0 && $y > 1} {
1854
- set i [expr {$lno-1}]
1855
- set ll [expr {[llength $file_lists($w)]-1}]
1856
-
1857
- if {$i == $ll && $i == 0} {
1858
- set after {reshow_diff;}
1859
- } else {
1860
- global next_diff_p next_diff_w next_diff_i
1861
-
1862
- set next_diff_w $w
1863
-
1864
- if {$i < $ll} {
1865
- set i [expr {$i + 1}]
1866
- set next_diff_i $i
1867
- } else {
1868
- set next_diff_i $i
1869
- set i [expr {$i - 1}]
1870
- }
1871
-
1872
- set next_diff_p [lindex $file_lists($w) $i]
1873
-
1874
- if {$next_diff_p ne {} && $current_diff_path ne {}} {
1875
- set after {next_diff;}
1876
- } else {
1877
- set after {}
1878
- }
1879
- }
1947
+ set after [next_diff_after_action $w $path $lno]
1948
1949
if {$w eq $ui_index} {
1950
update_indexinfo \
lib/diff.tcl
+12
-6
@@ -24,10 +24,16 @@ proc reshow_diff {} {
24
set p $current_diff_path
25
if {$p eq {}} {
26
# No diff is being shown.
27
- } elseif {$current_diff_side eq {}
28
- || [catch {set s $file_states($p)}]
29
- || [lsearch -sorted -exact $file_lists($current_diff_side) $p] == -1} {
27
+ } elseif {$current_diff_side eq {}} {
28
clear_diff
29
+ } elseif {[catch {set s $file_states($p)}]
30
+ || [lsearch -sorted -exact $file_lists($current_diff_side) $p] == -1} {
31
+
32
+ if {[find_next_diff $current_diff_side $p {} {[^O]}]} {
33
+ next_diff
34
+ } else {
35
+ clear_diff
36
+ }
37
} else {
38
set save_pos [lindex [$ui_diff yview] 0]
39
show_diff $p $current_diff_side {} $save_pos
@@ -71,6 +77,7 @@ proc show_diff {path w {lno {}} {scroll_pos {}}} {
77
}
78
if {$lno >= 1} {
79
$w tag add in_diff $lno.0 [expr {$lno + 1}].0
80
+ $w see $lno.0
81
}
82
83
set s $file_states($path)
@@ -366,10 +373,9 @@ proc apply_hunk {x y} {
373
}
374
unlock_index
375
display_file $current_diff_path $mi
376
+ # This should trigger shift to the next changed file
377
if {$o eq {_}} {
370
- clear_diff
371
- } else {
372
- set current_diff_path $current_diff_path
378
+ reshow_diff
379
}
380
}
381
lib/mergetool.tcl
+2
-6
@@ -24,13 +24,9 @@ This operation can be undone only by restarting the merge." \
24
}
25
26
proc merge_add_resolution {path} {
27
- global current_diff_path
27
+ global current_diff_path ui_workdir
28
29
- if {$path eq $current_diff_path} {
30
- set after {reshow_diff;}
31
- } else {
32
- set after {}
33
- }
29
+ set after [next_diff_after_action $ui_workdir $path {} {^_?U}]
30
31
update_index \
32
[mc "Adding resolution for %s" [short_path $path]] \