Eskil

Diff
Login

Differences From Artifact [c31040a233]:

To Artifact [5f68bbc01c]:


110
111
112
113
114
115
116
117

118
119
120
121
122
123
124

125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140

141
142

143
144
145

146
147
148
149
150
151
152

153
154
155
156

157
158
159
160
161
162

163
164

165
166

167
168
169
170
171
172
173
110
111
112
113
114
115
116

117
118
119
120
121
122
123

124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139

140
141

142
143
144

145
146
147
148
149
150
151

152
153
154
155

156
157
158
159
160
161

162
163

164
165

166
167
168
169
170
171
172
173







-
+






-
+















-
+

-
+


-
+






-
+



-
+





-
+

-
+

-
+







            catch {file delete -force $f}
        }
        set ::tmpfiles {}
    }
}

# insertLine, when in table mode
proc insertLineTable {top n line text {tag equal}} {
proc insertLineTable {top side line text {tag equal}} {
    set RE $::eskil($top,separator)
    set words [split $text $RE]
    set id [$::widgets($top,wTable) insert end $words]
    if {$tag ne "equal"} {
        set col 0
        foreach w $words {
            if {$n == 1} {
            if {$side == 1} {
                # TBD TABLE, r is faked here for now
                dict set ::eskil($top,tablechanges) $id,$col w1 $w
                dict set ::eskil($top,tablechanges) $id,$col w2 ""
                dict set ::eskil($top,tablechanges) $id,$col r  "0 0 1 1"
            } else {
                dict set ::eskil($top,tablechanges) $id,$col w1 ""
                dict set ::eskil($top,tablechanges) $id,$col w2 $w
                dict set ::eskil($top,tablechanges) $id,$col r  "0 0 1 1"
            }
            incr col
        }
    }
}

# Insert lineno and text
proc insertLine {top n line text {tag {equal}} {linetag {}}} {
proc insertLine {top side line text {tag {equal}} {linetag {}}} {
    if {$::eskil($top,view) eq "table"} {
        insertLineTable $top $n $line $text $tag
        insertLineTable $top $side $line $text $tag
        return
    }
    $::widgets($top,wDiff$n) insert end "$text\n" $tag
    $::widgets($top,wDiff$side) insert end "$text\n" $tag
    if {$linetag ne ""} {
        append tag " $linetag"
    }
    if {$tag != "equal"} {
        set tag "hl$::HighLightCount $tag"
    }
    $::widgets($top,wLine$n) insert end [myFormL $line] $tag
    $::widgets($top,wLine$side) insert end [myFormL $line] $tag
}

# Insert an empty line on one side of the diff.
proc emptyLine {top n {highlight 1}} {
proc emptyLine {top side {highlight 1}} {
    if {$::eskil($top,view) eq "table"} {
        # This should be ignored for table
        return
    }
    if {$highlight} {
        $::widgets($top,wLine$n) insert end "\n" hl$::HighLightCount
        $::widgets($top,wLine$side) insert end "\n" hl$::HighLightCount
    } else {
        $::widgets($top,wLine$n) insert end "*****\n"
        $::widgets($top,wLine$side) insert end "*****\n"
    }
    $::widgets($top,wDiff$n) insert end "\n" padding
    $::widgets($top,wDiff$side) insert end "\n" padding
}

# Helper to take care of -sep case
# This can be used when diffing e.g. a CSV file.
# Each column will be handled separately, so differences will never be shown
# crossing a separator
proc diffWithSeparator {RE line1 line2 opts} {
1296
1297
1298
1299
1300
1301
1302

1303
1304
1305
1306
1307
1308
1309
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310







+







#####################################
# Main diff
#####################################

proc highlightTabs {top} {
    foreach item {wDiff1 wDiff2} {
        set w $::widgets($top,$item)
        ##nagelfar vartype w _obj,text
        set count {}
        set x [$w search -regexp -all -count count {\t+} 1.0]
        foreach si $x l $count {
            $w tag add tab $si "$si + $l chars"
        }
        $w tag configure tab -background bisque
        $w tag raise tab
1747
1748
1749
1750
1751
1752
1753
1754

1755
1756
1757
1758
1759
1760
1761
1762

1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776

1777
1778
1779

1780
1781
1782
1783
1784
1785
1786
1748
1749
1750
1751
1752
1753
1754

1755
1756
1757
1758
1759
1760
1761
1762

1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776

1777
1778
1779

1780
1781
1782
1783
1784
1785
1786
1787







-
+







-
+













-
+


-
+







    }
    if {[llength [$w bbox $ei]] == 0} {
        $w yview $si
    }
}

# Highlight a diff
proc highLightChange {top n} {
proc highLightChange {top changeIndex} {
    if {[info exists ::eskil($top,currHighLight)] && \
            $::eskil($top,currHighLight) >= 0} {
        $::widgets($top,wLine1) tag configure hl$::eskil($top,currHighLight) \
                -background {}
        $::widgets($top,wLine2) tag configure hl$::eskil($top,currHighLight) \
                -background {}
    }
    set ::eskil($top,currHighLight) $n
    set ::eskil($top,currHighLight) $changeIndex
    if {$::eskil($top,currHighLight) < 0} {
        set ::eskil($top,currHighLight) -1
    } elseif {$::eskil($top,currHighLight) >= [llength $::eskil($top,changes)]} {
        set ::eskil($top,currHighLight) [llength $::eskil($top,changes)]
    } else {
        $::widgets($top,wLine1) tag configure hl$::eskil($top,currHighLight) \
                -background yellow
        $::widgets($top,wLine2) tag configure hl$::eskil($top,currHighLight) \
                -background yellow
    }
}

# Highlight a diff and scroll windows to it.
proc showDiff {top num} {
proc showDiff {top changeIndex} {
    # TBD TABLE
    if {$::eskil($top,view) eq "table"} return
    highLightChange $top $num
    highLightChange $top $changeIndex

    set change [lindex $::eskil($top,changes) $::eskil($top,currHighLight)]
    set line1 [lindex $change 0]

    if {$::eskil($top,currHighLight) < 0} {
        set line1 1.0
        set line2 1.0
1963
1964
1965
1966
1967
1968
1969
1970

1971
1972
1973
1974
1975
1976
1977
1964
1965
1966
1967
1968
1969
1970

1971
1972
1973
1974
1975
1976
1977
1978







-
+







        $w edit separator
        set ::eskil($w,allowChange) line
    }
}

# Copy a block
proc copyBlock {top from first last} {
    set to [expr {3 - $from}]
    set to [expr {$from == 1 ? 2 : 1}]

    set wfrom $::widgets($top,wDiff$from)
    set wto   $::widgets($top,wDiff$to)

    set tags ""
    set dump [$wfrom dump -all $first.0 $last.end+1c]

1999
2000
2001
2002
2003
2004
2005
2006

2007
2008
2009
2010
2011
2012
2013
2000
2001
2002
2003
2004
2005
2006

2007
2008
2009
2010
2011
2012
2013
2014







-
+







        }
    }
    endUndoBlock $wfrom $wto
}

# Copy a row between text widgets
proc copyRow {top from row} {
    set to [expr {3 - $from}]
    set to [expr {$from == 1 ? 2 : 1}]

    set wfrom $::widgets($top,wDiff$from)
    set wto   $::widgets($top,wDiff$to)

    set text [$wfrom get $row.0 $row.end+1c]

    startUndoBlock $wfrom $wto
2046
2047
2048
2049
2050
2051
2052
2053

2054
2055

2056
2057
2058
2059
2060



2061
2062
2063


2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075

2076
2077
2078

2079
2080
2081
2082

2083
2084
2085
2086
2087


2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105

2106
2107
2108

2109
2110
2111
2112

2113
2114
2115
2116
2117
2118


2119
2120
2121
2122
2123
2124
2125
2047
2048
2049
2050
2051
2052
2053

2054
2055

2056
2057
2058



2059
2060
2061
2062


2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075

2076
2077
2078

2079
2080
2081
2082

2083
2084
2085
2086


2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105

2106
2107
2108

2109
2110
2111
2112

2113
2114
2115
2116
2117


2118
2119
2120
2121
2122
2123
2124
2125
2126







-
+

-
+


-
-
-
+
+
+

-
-
+
+











-
+


-
+



-
+



-
-
+
+

















-
+


-
+



-
+




-
-
+
+







    set froml [lindex $lines 0]
    set tol [lindex $lines end]
    return [list $fromr $tor $froml $tol]
}

# Called by popup menus over row numbers to add commands for editing.
# Returns 1 if nothing was added.
proc editMenu {m top n hl x y} {
proc editMenu {m top side changeIndex x y} {

    if {![mayEdit $top $n]} {return 1}
    if {![mayEdit $top $side]} {return 1}

    # Only copy when in a change block
    if {$hl ne ""} {
        set o [expr {3 - $n}] ;# switch 1 <-> 2
        set editOther [mayEdit $top $o]
    if {$changeIndex ne ""} {
        set other [expr {$side == 1 ? 2 : 1}]
        set editOther [mayEdit $top $other]

        set w $::widgets($top,wLine$n)
        set wo $::widgets($top,wLine$o)
        set w $::widgets($top,wLine$side)
        set wo $::widgets($top,wLine$other)

        # Get the row that was clicked
        set index [$w index @$x,$y]
        set row [lindex [split $index "."] 0]

        set line  [regexp -inline {\d+} [$w  get $row.0 $row.end]]
        set lineo [regexp -inline {\d+} [$wo get $row.0 $row.end]]

        # Row copy
        if {$lineo ne ""} {
            $m add command -label "Copy Row from other side" \
                    -command [list copyRow $top $o $row]
                    -command [list copyRow $top $other $row]
        } else {
            $m add command -label "Delete Row" \
                    -command [list deleteBlock $top $n $row]
                    -command [list deleteBlock $top $side $row]
        }
        if {$line ne "" && $editOther} {
            $m add command -label "Copy Row to other side" \
                    -command [list copyRow $top $n $row]
                    -command [list copyRow $top $side $row]
        }

        # Get ranges for the change block
        set range  [$w tag ranges hl$hl]
        set rangeo [$wo tag ranges hl$hl]
        set range  [$w tag ranges hl$changeIndex]
        set rangeo [$wo tag ranges hl$changeIndex]

        # Get the lines involved in the block
        lassign [getLinesFromRange $w  $range ] from  to  froml  tol
        lassign [getLinesFromRange $wo $rangeo] fromo too fromlo tolo

        # More than one line in the block?
        set thisSize 0
        set otherSize 0
        if {$froml ne "" && $tol ne ""} {
            set thisSize [expr {$tol - $froml + 1}]
        }
        if {$fromlo ne "" && $tolo ne ""} {
            set otherSize [expr {$tolo - $fromlo + 1}]
        }
        if {$thisSize > 1 || $otherSize > 1} {
            if {$otherSize > 0} {
                $m add command -label "Copy Block from other side" \
                        -command [list copyBlock $top $o $fromo $too]
                        -command [list copyBlock $top $other $fromo $too]
            } else {
                $m add command -label "Delete Block" \
                        -command [list deleteBlock $top $n $from $to]
                        -command [list deleteBlock $top $side $from $to]
            }
            if {$editOther && $thisSize > 0} {
                $m add command -label "Copy Block to other side" \
                        -command [list copyBlock $top $n $from $to]
                        -command [list copyBlock $top $side $from $to]
            }
        }
    }

    $m add command -label "Save File" -command [list saveFile $top $n]
    $m add command -label "Save File, Reload" -command [list saveFileR $top $n]
    $m add command -label "Save File" -command [list saveFile $top $side]
    $m add command -label "Save File, Reload" -command [list saveFileR $top $side]

    return 0
}

proc saveFile {top side} {
    if {$side == 1} {
        if {!$::eskil($top,leftEdit)} return
2524
2525
2526
2527
2528
2529
2530
2531

2532
2533
2534
2535



2536
2537
2538
2539



2540
2541

2542
2543

2544
2545
2546
2547
2548
2549
2550
2525
2526
2527
2528
2529
2530
2531

2532
2533



2534
2535
2536
2537



2538
2539
2540
2541

2542
2543

2544
2545
2546
2547
2548
2549
2550
2551







-
+

-
-
-
+
+
+

-
-
-
+
+
+

-
+

-
+







    lassign [grid size $w._dyn] mCols mRows
    if {$mCols != $cols} {
        DynGridRearrange $w $cols
    }
}

# Ask for widget to have its children managed by dynGrid.
proc dynGridManage {w} {
proc dynGridManage {W} {
    # Limit its inital requirements
    pack propagate $w 0
    $w configure -width 100 -height 10
    set children [winfo children $w]
    pack propagate $W 0
    $W configure -width 100 -height 10
    set children [winfo children $W]
    # Add an inner frame
    ttk::frame $w._dyn
    lower $w._dyn
    pack $w._dyn -fill both -expand 1
    ttk::frame $W._dyn
    lower $W._dyn
    pack $W._dyn -fill both -expand 1
    # Get all children managed
    grid {*}$children -in $w._dyn -padx 3 -pady 3 -sticky w
    grid {*}$children -in $W._dyn -padx 3 -pady 3 -sticky w
    # React
    bind $w <Configure> "DynGridRedo $w"
    bind $W <Configure> "DynGridRedo $W"
}

################
# Align function
################

proc enableAlign {top} {
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591



2592
2593
2594
2595
2596
2597
2598
2583
2584
2585
2586
2587
2588
2589



2590
2591
2592
2593
2594
2595
2596
2597
2598
2599







-
-
-
+
+
+







    unset -nocomplain ::eskil($top,align1)
    unset -nocomplain ::eskil($top,align2)
    unset -nocomplain ::eskil($top,aligntext1)
    unset -nocomplain ::eskil($top,aligntext2)
}

# Mark a line as aligned.
proc markAlign {top n line text} {
    set ::eskil($top,align$n) $line
    set ::eskil($top,aligntext$n) $text
proc markAlign {top side line text} {
    set ::eskil($top,align$side) $line
    set ::eskil($top,aligntext$side) $text

    if {[info exists ::eskil($top,align1)] && [info exists ::eskil($top,align2)]} {
        if {![string equal $::eskil($top,aligntext1) $::eskil($top,aligntext2)]} {
            set apa [tk_messageBox -icon question -title "Align" -type yesno \
                    -message "Those lines are not equal.\nReally align them?"]
            if {$apa != "yes"} {
                return 0
2606
2607
2608
2609
2610
2611
2612
2613

2614
2615

2616
2617
2618
2619
2620
2621
2622
2623
2624

2625
2626
2627


2628
2629
2630
2631
2632
2633
2634
2635
2636

2637
2638
2639

2640
2641
2642
2643
2644
2645
2646
2607
2608
2609
2610
2611
2612
2613

2614
2615

2616
2617
2618
2619
2620
2621
2622
2623
2624

2625
2626


2627
2628
2629
2630
2631
2632
2633
2634
2635
2636

2637
2638
2639

2640
2641
2642
2643
2644
2645
2646
2647







-
+

-
+








-
+

-
-
+
+








-
+


-
+







        return 1
    }
    return 0
}

# Called by popup menus over row numbers to add command for alignment.
# Returns 1 if nothing was added.
proc alignMenu {m top n x y} {
proc alignMenu {m top side x y} {
    # Get the row that was clicked
    set w $::widgets($top,wLine$n)
    set w $::widgets($top,wLine$side)
    set index [$w index @$x,$y]
    set row [lindex [split $index "."] 0]

    set data [$w get $row.0 $row.end]
    # Must be a line number
    if {![regexp {\d+} $data line]} {
        return 1
    }
    set text [$::widgets($top,wDiff$n) get $row.0 $row.end]
    set text [$::widgets($top,wDiff$side) get $row.0 $row.end]

    set other [expr {$n == 1 ? 2 : 1}]
    set cmd [list markAlign $top $n $line $text]
    set other [expr {$side == 1 ? 2 : 1}]
    set cmd [list markAlign $top $side $line $text]
    if {![info exists ::eskil($top,align$other)]} {
        set label "Mark line for alignment"
    } else {
        set label "Align with line $::eskil($top,align$other) on other side"
    }

    if {[info exists ::eskil($top,aligns)]} {
        foreach {align1 align2} $::eskil($top,aligns) {
            if {$n == 1 && $line == $align1} {
            if {$side == 1 && $line == $align1} {
                set label "Remove alignment with line $align2"
                set cmd [list clearAlign $top $align1]
            } elseif {$n == 2 && $line == $align2} {
            } elseif {$side == 2 && $line == $align2} {
                set label "Remove alignment with line $align1"
                set cmd [list clearAlign $top $align1]
            }
        }
    }

    $m add command -label $label -command $cmd
2659
2660
2661
2662
2663
2664
2665
2666

2667
2668

2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680


2681
2682
2683
2684
2685



2686
2687
2688
2689
2690
2691

2692
2693
2694
2695
2696
2697
2698
2660
2661
2662
2663
2664
2665
2666

2667
2668

2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679


2680
2681
2682
2683



2684
2685
2686
2687
2688
2689
2690
2691

2692
2693
2694
2695
2696
2697
2698
2699







-
+

-
+










-
-
+
+


-
-
-
+
+
+





-
+







    bind $right <B1-Motion> [list motionAlignDrag $top 2 0 %x %y %X %Y]\;break
    bind $right <Shift-B1-Motion> [list motionAlignDrag $top 2 1 %x %y %X %Y]\;break
    bind $right <ButtonRelease-1> [list endAlignDrag $top 2 %x %y %X %Y]\;break
    bind $right <B1-Leave> break
}

# Button has been pressed over line window
proc startAlignDrag {top n x y X Y} {
proc startAlignDrag {top side x y X Y} {
    # Get the row that was clicked
    set w $::widgets($top,wLine$n)
    set w $::widgets($top,wLine$side)
    set index [$w index @$x,$y]
    set row [lindex [split $index "."] 0]

    set data [$w get $row.0 $row.end]
    set ::eskil($top,alignDrag,state) none
    # Must be a line number
    if {![regexp {\d+} $data line]} {
        return 1
    }
    # Set up information about start of drag
    set text [$::widgets($top,wDiff$n) get $row.0 $row.end]
    set other [expr {$n == 1 ? 2 : 1}]
    set text [$::widgets($top,wDiff$side) get $row.0 $row.end]
    set other [expr {$side == 1 ? 2 : 1}]
    set ::eskil($top,alignDrag,X) $X
    set ::eskil($top,alignDrag,Y) $Y
    set ::eskil($top,alignDrag,from) $n
    set ::eskil($top,alignDrag,line$n) $line
    set ::eskil($top,alignDrag,text$n) $text
    set ::eskil($top,alignDrag,from) $side
    set ::eskil($top,alignDrag,line$side) $line
    set ::eskil($top,alignDrag,text$side) $text
    set ::eskil($top,alignDrag,line$other) "?"
    set ::eskil($top,alignDrag,state) press
}

# Mouse moves with button down
proc motionAlignDrag {top n shift x y X Y} {
proc motionAlignDrag {top side shift x y X Y} {
    if {$::eskil($top,alignDrag,state) eq "press"} {
        # Have we moved enough to call it dragging?
        set dX [expr {abs($X - $::eskil($top,alignDrag,X))}]
        set dY [expr {abs($Y - $::eskil($top,alignDrag,Y))}]
        if {$dX + $dY > 3} {
            # Start a drag action
            set w $top.alignDrag
2707
2708
2709
2710
2711
2712
2713
2714

2715
2716
2717
2718
2719
2720
2721
2708
2709
2710
2711
2712
2713
2714

2715
2716
2717
2718
2719
2720
2721
2722







-
+







    }
    if {$::eskil($top,alignDrag,state) eq "drag"} {
        set w $::eskil($top,alignDrag,W)
        # Move drag label with cursor
        wm geometry $w +[expr {$X + 1}]+[expr {$Y + 1}]

        set n $::eskil($top,alignDrag,from)
        set other [expr {$n == 1 ? 2 : 1}]
        set other [expr {$side == 1 ? 2 : 1}]
        set w2 $::widgets($top,wLine$other)
        # Are we over the other line window?
        if {[winfo containing $X $Y] eq $w2} {
            set x [expr {$X - [winfo rootx $w2]}]
            set y [expr {$Y - [winfo rooty $w2]}]
            set index [$w2 index @$x,$y]
            set row [lindex [split $index "."] 0]
2737
2738
2739
2740
2741
2742
2743
2744

2745
2746
2747
2748
2749
2750
2751
2738
2739
2740
2741
2742
2743
2744

2745
2746
2747
2748
2749
2750
2751
2752







-
+







            append txt "\nAnd Redo Diff"
        }
        $w.l configure -text $txt
    }
}

# Button has been released
proc endAlignDrag {top n x y X Y} {
proc endAlignDrag {top side x y X Y} {
    if {$::eskil($top,alignDrag,state) eq "drag"} {
        destroy $::eskil($top,alignDrag,W)
        # Are both line numbers valid? I.e. is this a full align operation?
        if {$::eskil($top,alignDrag,line1) ne "?" && \
                $::eskil($top,alignDrag,line2) ne "?"} {
            NoMarkAlign $top
            markAlign $top 1 $::eskil($top,alignDrag,line1) \
2760
2761
2762
2763
2764
2765
2766
2767
2768


2769
2770
2771
2772
2773
2774




2775
2776

2777
2778
2779

2780
2781
2782

2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795

2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806

2807
2808
2809
2810
2811

2812
2813
2814
2815

2816
2817

2818
2819
2820

2821
2822
2823
2824
2825
2826
2827
2828


2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846


2847
2848

2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869






2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888


2889
2890
2891
2892
2893
2894
2895
2761
2762
2763
2764
2765
2766
2767


2768
2769
2770
2771




2772
2773
2774
2775
2776

2777
2778
2779

2780
2781
2782

2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795

2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806

2807
2808
2809
2810
2811

2812
2813
2814
2815

2816
2817

2818
2819
2820

2821
2822
2823
2824
2825
2826
2827


2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845


2846
2847
2848

2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866




2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889


2890
2891
2892
2893
2894
2895
2896
2897
2898







-
-
+
+


-
-
-
-
+
+
+
+

-
+


-
+


-
+












-
+










-
+




-
+



-
+

-
+


-
+






-
-
+
+
















-
-
+
+

-
+

















-
-
-
-
+
+
+
+
+
+

















-
-
+
+







    set ::eskil($top,alignDrag,state) none
}

###################
# Diff highlighting
###################

proc hlSelect {top hl} {
    highLightChange $top $hl
proc hlSelect {top changeIndex} {
    highLightChange $top $changeIndex
}

proc hlSeparate {top n hl} {
    set ::eskil($top,separate$n) $hl
    set wd $::widgets($top,wDiff$n)
    set wl $::widgets($top,wLine$n)
proc hlSeparate {top side changeIndex} {
    set ::eskil($top,separate$side) $changeIndex
    set wd $::widgets($top,wDiff$side)
    set wl $::widgets($top,wLine$side)

    if {$hl eq ""} {
    if {$changeIndex eq ""} {
        set range [$wd tag ranges sel]
    } else {
        set range [$wl tag ranges hl$::eskil($top,separate$n)]
        set range [$wl tag ranges hl$::eskil($top,separate$side)]
    }
    set text [$wd get {*}$range]
    set ::eskil($top,separatetext$n) $text
    set ::eskil($top,separatetext$side) $text

    # Get the lines involved in the display
    set from [lindex $range 0]
    set to   [lindex $range 1]
    lassign [split $from "."] froml fromi
    lassign [split $to   "."] tol   toi
    if {$toi == 0} {incr tol -1}
    # Get the corresponding lines in the file
    set t [$wl get $froml.0 $tol.end]
    set lines [lsort -integer [regexp -all -inline {\d+} $t]]
    set froml [lindex $lines 0]
    set tol [lindex $lines end]
    set ::eskil($top,separatelines$n) [list $froml $tol]
    set ::eskil($top,separatelines$side) [list $froml $tol]

    if {[info exists ::eskil($top,separate1)] && \
            [info exists ::eskil($top,separate2)]} {
        cloneDiff $top [concat $::eskil($top,separatelines1) \
                               $::eskil($top,separatelines2)]
        unset ::eskil($top,separate1)
        unset ::eskil($top,separate2)
    }
}

proc hlPopup {top n hl X Y x y} {
proc hlPopup {top side changeIndex X Y x y} {
    if {[info exists ::eskil($top,nopopup)] && $::eskil($top,nopopup)} return
    destroy .lpm
    menu .lpm

    if {![editMenu .lpm $top $n $hl $x $y]} {
    if {![editMenu .lpm $top $side $changeIndex $x $y]} {
        .lpm add separator
    }

    if {$hl != ""} {
    if {$changeIndex != ""} {
        .lpm add command -label "Select" \
                -command [list hlSelect $top $hl]
                -command [list hlSelect $top $changeIndex]
    }

    set other [expr {$n == 1 ? 2 : 1}]
    set other [expr {$side == 1 ? 2 : 1}]
    if {![info exists ::eskil($top,separate$other)]} {
        set label "Mark for Separate Diff"
    } else {
        set label "Separate Diff"
    }

    .lpm add command -label $label -command [list hlSeparate $top $n $hl]
    alignMenu .lpm $top $n $x $y
    .lpm add command -label $label -command [list hlSeparate $top $side $changeIndex]
    alignMenu .lpm $top $side $x $y

    set ::eskil($top,nopopup) 1
    tk_popup .lpm $X $Y
    after idle [list after 1 [list set "::eskil($top,nopopup)" 0]]

    return
}

# This is called when right clicking over the line numbers which are not
# marked for changes
proc rowPopup {w X Y x y} {
    set top [winfo toplevel $w]
    if {[info exists ::eskil($top,nopopup)] && $::eskil($top,nopopup)} return
    destroy .lpm
    menu .lpm

    regexp {(\d+)\D*$} $w -> n
    set tmp1 [editMenu  .lpm $top $n "" $x $y]
    regexp {(\d+)\D*$} $w -> side
    set tmp1 [editMenu  .lpm $top $side "" $x $y]
    if {!$tmp1} {.lpm add separator}
    set tmp2 [alignMenu .lpm $top $n $x $y]
    set tmp2 [alignMenu .lpm $top $side $x $y]
    if {$tmp1 && $tmp2} {
        # Nothing in the menu
        return
    }
    if {!$tmp1 && $tmp2} {.lpm delete last}

    set ::eskil($top,nopopup) 1
    tk_popup .lpm $X $Y
    after idle [list after 1 [list set "::eskil($top,nopopup)" 0]]
}

proc nextHighlight {top} {
    # TBD TABLE, stop for now?
    if {$::eskil($top,view) eq "table"} {
        return
    }
    set tag hl$::HighLightCount
    foreach n {1 2} {
        $::widgets($top,wLine$n) tag bind $tag <ButtonPress-3> \
                "hlPopup $top $n $::HighLightCount %X %Y %x %y ; break"
        $::widgets($top,wLine$n) tag bind $tag <ButtonPress-1> \
    foreach side {1 2} {
        set W $::widgets($top,wLine$side)
        ##nagelfar vartype W _obj,text
        $W tag bind $tag <ButtonPress-3> \
                "hlPopup $top $side $::HighLightCount %X %Y %x %y ; break"
        $W tag bind $tag <ButtonPress-1> \
                "hlSelect $top $::HighLightCount"
    }
    incr ::HighLightCount
}

#########
# Zooming
#########

proc zoomRow {w X Y x y} {
    set top [winfo toplevel $w]
    # Get the row that was clicked
    set index [$w index @$x,$y]
    set row [lindex [split $index "."] 0]

    # Check if it is selected
    if {[lsearch [$w tag names $index] sel] >= 0} {
        regexp {(\d+)\D*$} $w -> n
        hlPopup $top $n "" $X $Y $x $y
        regexp {(\d+)\D*$} $w -> side
        hlPopup $top $side "" $X $Y $x $y
        return
    }

    # Extract the data
    set data(1) [$::widgets($top,wDiff1) dump -tag -text $row.0 $row.end]
    set data(2) [$::widgets($top,wDiff2) dump -tag -text $row.0 $row.end]
    if {[llength $data(1)] == 0 && [llength $data(2)] == 0} return