Eskil

Check-in [46064856af]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Cleanup
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 46064856af969349b574671050b08dfba934936b5e3d1ab32d0b389d47ee034b
User & Date: peter 2019-11-10 16:29:47
Context
2019-11-10
17:28
Cleanup check-in: f02d0c04f1 user: peter tags: trunk
16:29
Cleanup check-in: 46064856af user: peter tags: trunk
2019-11-09
00:37
Started to rebuild debug proc editor check-in: 96d2928ff7 user: peter tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to Makefile.

156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173

spell:
	@cat doc/*.txt | ispell -d british -l | sort -u

CHKFILES = $(SRCFILES) $(wildcard plugins/*.tcl) \
	eskil.vfs/lib/psballoon/psballoon.tcl \
	eskil.vfs/lib/pstools/pstools.tcl
NAGELFARFLAGS = -s syntaxdb.tcl -pkgpicky -filter "*Non constant definition*" -quiet

# Create a common "header" file for all source files.
eskil_h.syntax: $(SRCFILES) src/eskil.syntax
	@echo Creating syntax header file...
	@$(NAGELFAR) $(NAGELFARFLAGS) -header eskil_h.syntax $(SRCFILES)

check: eskil_h.syntax
	@echo Checking...
	@for i in $(CHKFILES); do $(NAGELFAR)  $(NAGELFARFLAGS) eskil_h.syntax $$i ; done








|


|







156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173

spell:
	@cat doc/*.txt | ispell -d british -l | sort -u

CHKFILES = $(SRCFILES) $(wildcard plugins/*.tcl) \
	eskil.vfs/lib/psballoon/psballoon.tcl \
	eskil.vfs/lib/pstools/pstools.tcl
NAGELFARFLAGS = -s syntaxdb.tcl -pkgpicky -filter "*Non constant definition*" -quiet -plugin nfplugin.tcl

# Create a common "header" file for all source files.
eskil_h.syntax: $(SRCFILES) src/eskil.syntax nfplugin.tcl
	@echo Creating syntax header file...
	@$(NAGELFAR) $(NAGELFARFLAGS) -header eskil_h.syntax $(SRCFILES)

check: eskil_h.syntax
	@echo Checking...
	@for i in $(CHKFILES); do $(NAGELFAR)  $(NAGELFARFLAGS) eskil_h.syntax $$i ; done

Added nfplugin.tcl.























































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
##Nagelfar Plugin : Check of Eskil's sources

proc statementWords {words info} {
    set caller [dict get $info caller]
    set callee [lindex $words 0]
    set res {}

    # Experiment with coding standard
    if {$callee eq "if"} {
        set e [lindex $words 1]
        if {[regexp {\{(\s*)!(\s*)\[} $e -> pre post]} {
            # Trying two possible rules for whitespace
            if 1 {
                if {$pre ne "" || $post ne ""} {
                    lappend res warning
                    lappend res "Not (!) should not be surrounded by space"
                }
            } else {
                if {$pre ne " " || $post ne " "} {
                    lappend res warning
                    lappend res "Not (!) should be surrounded by one space"
                }
            }
        }
    }
    return $res
}

Changes to src/dirdiff.tcl.

572
573
574
575
576
577
578

579
580
581
582
583
584
585
...
829
830
831
832
833
834
835

836
837
838
839
840
841
842
...
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
....
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
....
1334
1335
1336
1337
1338
1339
1340

1341
1342
1343
1344
1345
1346
1347
....
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
            # FIXA: update file info in tree too
            #$self SetNodeStatus $node equal
        }
    }

    # Copy a file from one directory to the other
    method CopyFile {node from} {

        if {$from eq "left"} {
            set to right
        } elseif {$from eq "right"} {
            set to left
        } else {
            error "Bad from argument to CopyFile: $from"
        }
................................................................................
            }} continue
            
            trace add execution $cmd enter [mymethod Dlog]
            puts "Traced $cmd"
        }
    }
    method UpdateIdle {} {

        $self Dlog UpdateIdle
        set AfterId "X"

        if {$PauseBgProcessing} {
            $self Dlog Pause
            set AfterId [after 200 [mymethod UpdateIdle]]
            return
................................................................................
                set AfterId ""
                return
            }
        }

        if {[llength $IdleQueue] > 0} {
            set node [lindex $IdleQueue end]
            set leftfull [$tree rowattrib $node leftfull]
            set rightfull [$tree rowattrib $node rightfull]
            if {$leftfull ne ""} {
                set statusvar "$leftfull  ($count)"
            } else {
                set statusvar "$rightfull  ($count)"
            }

            $self Dlog Reschedule
................................................................................
                    $size2 $time2]
            # TODO: Configurable large file value?
            if {$size1 > 1000000 && $size2 > 1000000} {
                set largeFile 1
            }
        }
        set id [$tree insertchild $node end $values]
        $tree rowattrib $id type $type
        set NodeStatus($id) unknown
        $tree rowattrib $id leftfull $df1
        $tree rowattrib $id rightfull $df2
        $tree rowattrib $id largefile $largeFile
        if {$type ne "directory"} {
            if {$type eq "link"} {
                $tree cellconfigure $id,structure -image $::img(link)
................................................................................
    method DoDirCompare {} {
        # Reconfiguring the dirdiff widget triggers a rerun
        $tree configure -leftdirvariable ::dirdiff(leftDir) \
                -rightdirvariable ::dirdiff(rightDir)
    }

    method DoNice {} {

        $tree nice $::Pref(dir,nice)
    }

    # Go up one level in directory hierarchy.
    # 0 = both
    method UpDir {{n 0}} {
        global dirdiff
................................................................................
    grid $check.rb2 -sticky w -padx 3 -pady 3
    grid $check.rb3 -sticky w -padx 3 -pady 3
    grid columnconfigure $check {0 1 2} -uniform a -weight 1

    set opts [ttk::labelframe $top.opts -text "Options" -padding 3]
    ttk::checkbutton $opts.cb1 -variable ::TmpPref(dir,ignorekey) \
            -text "Ignore \$Keyword:\$"
    pack {*}[winfo children $opts] -side top -anchor w

    set filter [ttk::labelframe $top.filter -text "Filter" -padding 3]
    ttk::label $filter.l1 -text "Include Files" -anchor w
    ttk::entryX $filter.e1 -width 20 -textvariable ::TmpPref(dir,incfiles)
    ttk::label $filter.l2 -text "Exclude Files" -anchor w
    ttk::entryX $filter.e2 -width 20 -textvariable ::TmpPref(dir,exfiles)
    ttk::label $filter.l3 -text "Include Dirs" -anchor w







>







 







>







 







|
|







 







|







 







>







 







|







572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
...
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
...
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
....
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
....
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
....
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
            # FIXA: update file info in tree too
            #$self SetNodeStatus $node equal
        }
    }

    # Copy a file from one directory to the other
    method CopyFile {node from} {
        ##nagelfar vartype tree _obj,tablelist
        if {$from eq "left"} {
            set to right
        } elseif {$from eq "right"} {
            set to left
        } else {
            error "Bad from argument to CopyFile: $from"
        }
................................................................................
            }} continue
            
            trace add execution $cmd enter [mymethod Dlog]
            puts "Traced $cmd"
        }
    }
    method UpdateIdle {} {
        ##nagelfar vartype tree _obj,tablelist
        $self Dlog UpdateIdle
        set AfterId "X"

        if {$PauseBgProcessing} {
            $self Dlog Pause
            set AfterId [after 200 [mymethod UpdateIdle]]
            return
................................................................................
                set AfterId ""
                return
            }
        }

        if {[llength $IdleQueue] > 0} {
            set node [lindex $IdleQueue end]
            set leftfull [$tree rowattrib $node "leftfull"]
            set rightfull [$tree rowattrib $node "rightfull"]
            if {$leftfull ne ""} {
                set statusvar "$leftfull  ($count)"
            } else {
                set statusvar "$rightfull  ($count)"
            }

            $self Dlog Reschedule
................................................................................
                    $size2 $time2]
            # TODO: Configurable large file value?
            if {$size1 > 1000000 && $size2 > 1000000} {
                set largeFile 1
            }
        }
        set id [$tree insertchild $node end $values]
        $tree rowattrib $id "type" $type
        set NodeStatus($id) unknown
        $tree rowattrib $id leftfull $df1
        $tree rowattrib $id rightfull $df2
        $tree rowattrib $id largefile $largeFile
        if {$type ne "directory"} {
            if {$type eq "link"} {
                $tree cellconfigure $id,structure -image $::img(link)
................................................................................
    method DoDirCompare {} {
        # Reconfiguring the dirdiff widget triggers a rerun
        $tree configure -leftdirvariable ::dirdiff(leftDir) \
                -rightdirvariable ::dirdiff(rightDir)
    }

    method DoNice {} {
        ##nagelfar vartype tree _obj,tablelist
        $tree nice $::Pref(dir,nice)
    }

    # Go up one level in directory hierarchy.
    # 0 = both
    method UpDir {{n 0}} {
        global dirdiff
................................................................................
    grid $check.rb2 -sticky w -padx 3 -pady 3
    grid $check.rb3 -sticky w -padx 3 -pady 3
    grid columnconfigure $check {0 1 2} -uniform a -weight 1

    set opts [ttk::labelframe $top.opts -text "Options" -padding 3]
    ttk::checkbutton $opts.cb1 -variable ::TmpPref(dir,ignorekey) \
            -text "Ignore \$Keyword:\$"
    pack {*}[winfo children $opts] -side "top" -anchor w

    set filter [ttk::labelframe $top.filter -text "Filter" -padding 3]
    ttk::label $filter.l1 -text "Include Files" -anchor w
    ttk::entryX $filter.e1 -width 20 -textvariable ::TmpPref(dir,incfiles)
    ttk::label $filter.l2 -text "Exclude Files" -anchor w
    ttk::entryX $filter.e2 -width 20 -textvariable ::TmpPref(dir,exfiles)
    ttk::label $filter.l3 -text "Include Dirs" -anchor w

Changes to src/eskil.syntax.

47
48
49
50
51
52
53

54
55
56
57
58
59
60
..
65
66
67
68
69
70
71


72
73
74
75
76
77
78
##nagelfar package known vfs

##nagelfar syntax pdf4tcl::getPaperSize x
##nagelfar syntax pdf4tcl::getPaperSizeList
##nagelfar syntax pdf4tcl::loadBaseType1Font 3
##nagelfar syntax pdf4tcl::loadBaseTrueTypeFont r 2 3
##nagelfar syntax pdf4tcl::createFont 3

##nagelfar package known pdf4tcl

##nagelfar syntax twapi::get_foreground_window
##nagelfar syntax twapi::get_window_coordinates x
##nagelfar syntax twapi::get_window_at_location x x
##nagelfar syntax twapi::set_focus x
##nagelfar syntax twapi::send_keys x
................................................................................
##nagelfar syntax tablelist::convEventFields x x x
##nagelfar syntax tablelist::synchronize x
##nagelfar syntax tablelist::updateKeyToRowMap x
##nagelfar syntax tablelist::displayItems x
##nagelfar syntax tablelist::cellIndex x x x
##nagelfar syntax tablelist::findTabs x x x x n n
##nagelfar syntax mwutil::wrongNumArgs x


##nagelfar package known tablelist_tile

##nagelfar syntax MySpinBox x p*
##nagelfar option MySpinBox -textvariable -from -to -increment -width -format
##nagelfar option MySpinBox\ -textvariable n

# Operators







>







 







>
>







47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
..
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
##nagelfar package known vfs

##nagelfar syntax pdf4tcl::getPaperSize x
##nagelfar syntax pdf4tcl::getPaperSizeList
##nagelfar syntax pdf4tcl::loadBaseType1Font 3
##nagelfar syntax pdf4tcl::loadBaseTrueTypeFont r 2 3
##nagelfar syntax pdf4tcl::createFont 3
##nagelfar syntax _obj,pdf4tcl s x*
##nagelfar package known pdf4tcl

##nagelfar syntax twapi::get_foreground_window
##nagelfar syntax twapi::get_window_coordinates x
##nagelfar syntax twapi::get_window_at_location x x
##nagelfar syntax twapi::set_focus x
##nagelfar syntax twapi::send_keys x
................................................................................
##nagelfar syntax tablelist::convEventFields x x x
##nagelfar syntax tablelist::synchronize x
##nagelfar syntax tablelist::updateKeyToRowMap x
##nagelfar syntax tablelist::displayItems x
##nagelfar syntax tablelist::cellIndex x x x
##nagelfar syntax tablelist::findTabs x x x x n n
##nagelfar syntax mwutil::wrongNumArgs x
##nagelfar syntax _obj,tablelist s x*
##nagelfar subcmd _obj,tablelist parent rowattrib nice
##nagelfar package known tablelist_tile

##nagelfar syntax MySpinBox x p*
##nagelfar option MySpinBox -textvariable -from -to -increment -width -format
##nagelfar option MySpinBox\ -textvariable n

# Operators

Changes to src/eskil.tcl.

110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
...
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
....
1296
1297
1298
1299
1300
1301
1302

1303
1304
1305
1306
1307
1308
1309
....
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
....
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
....
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
....
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
....
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
....
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
....
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
....
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
....
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
....
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
....
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
....
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
....
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
....
2859
2860
2861
2862
2863
2864
2865
2866


2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
....
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
            catch {file delete -force $f}
        }
        set ::tmpfiles {}
    }
}

# insertLine, when in table mode
proc insertLineTable {top n 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} {
                # 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
................................................................................
            }
            incr col
        }
    }
}

# Insert lineno and text
proc insertLine {top n line text {tag {equal}} {linetag {}}} {
    if {$::eskil($top,view) eq "table"} {
        insertLineTable $top $n $line $text $tag
        return
    }
    $::widgets($top,wDiff$n) 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
}

# Insert an empty line on one side of the diff.
proc emptyLine {top n {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
    } else {
        $::widgets($top,wLine$n) insert end "*****\n"
    }
    $::widgets($top,wDiff$n) 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} {
................................................................................
#####################################
# Main diff
#####################################

proc highlightTabs {top} {
    foreach item {wDiff1 wDiff2} {
        set w $::widgets($top,$item)

        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
................................................................................
    }
    if {[llength [$w bbox $ei]] == 0} {
        $w yview $si
    }
}

# Highlight a diff
proc highLightChange {top n} {
    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
    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} {
    # TBD TABLE
    if {$::eskil($top,view) eq "table"} return
    highLightChange $top $num

    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
................................................................................
        $w edit separator
        set ::eskil($w,allowChange) line
    }
}

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

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

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

................................................................................
        }
    }
    endUndoBlock $wfrom $wto
}

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

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

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

    startUndoBlock $wfrom $wto
................................................................................
    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} {

    if {![mayEdit $top $n]} {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]

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

        # 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]
        } else {
            $m add command -label "Delete Row" \
                    -command [list deleteBlock $top $n $row]
        }
        if {$line ne "" && $editOther} {
            $m add command -label "Copy Row to other side" \
                    -command [list copyRow $top $n $row]
        }

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

        # 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
................................................................................
        }
        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]
            } else {
                $m add command -label "Delete Block" \
                        -command [list deleteBlock $top $n $from $to]
            }
            if {$editOther && $thisSize > 0} {
                $m add command -label "Copy Block to other side" \
                        -command [list copyBlock $top $n $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]

    return 0
}

proc saveFile {top side} {
    if {$side == 1} {
        if {!$::eskil($top,leftEdit)} return
................................................................................
    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} {
    # Limit its inital requirements
    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
    # Get all children managed
    grid {*}$children -in $w._dyn -padx 3 -pady 3 -sticky w
    # React
    bind $w <Configure> "DynGridRedo $w"
}

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

proc enableAlign {top} {
................................................................................
    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

    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
................................................................................
        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} {
    # Get the row that was clicked
    set w $::widgets($top,wLine$n)
    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 other [expr {$n == 1 ? 2 : 1}]
    set cmd [list markAlign $top $n $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} {
                set label "Remove alignment with line $align2"
                set cmd [list clearAlign $top $align1]
            } elseif {$n == 2 && $line == $align2} {
                set label "Remove alignment with line $align1"
                set cmd [list clearAlign $top $align1]
            }
        }
    }

    $m add command -label $label -command $cmd
................................................................................
    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} {
    # Get the row that was clicked
    set w $::widgets($top,wLine$n)
    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 ::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,line$other) "?"
    set ::eskil($top,alignDrag,state) press
}

# Mouse moves with button down
proc motionAlignDrag {top n 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
................................................................................
    }
    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 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]
................................................................................
            append txt "\nAnd Redo Diff"
        }
        $w.l configure -text $txt
    }
}

# Button has been released
proc endAlignDrag {top n 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) \
................................................................................
    set ::eskil($top,alignDrag,state) none
}

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

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

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

    if {$hl eq ""} {
        set range [$wd tag ranges sel]
    } else {
        set range [$wl tag ranges hl$::eskil($top,separate$n)]
    }
    set text [$wd get {*}$range]
    set ::eskil($top,separatetext$n) $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]

    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} {
    if {[info exists ::eskil($top,nopopup)] && $::eskil($top,nopopup)} return
    destroy .lpm
    menu .lpm

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

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

    set other [expr {$n == 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

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

    return
}
................................................................................
# 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]
    if {!$tmp1} {.lpm add separator}
    set tmp2 [alignMenu .lpm $top $n $x $y]
    if {$tmp1 && $tmp2} {
        # Nothing in the menu
        return
    }
    if {!$tmp1 && $tmp2} {.lpm delete last}

    set ::eskil($top,nopopup) 1
................................................................................

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> \
                "hlSelect $top $::HighLightCount"
    }
    incr ::HighLightCount
}

#########
# Zooming
................................................................................
    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
        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







|






|







 







|

|


|






|



|





|

|

|







 







>







 







|







|













|


|







 







|







 







|







 







|

|


|
|
|

|
|











|


|



|



|
|







 







|


|



|




|
|







 







|

|
|
|

|
|
|

|

|







 







|
|
|







 







|

|








|

|
|








|


|







 







|

|










|
|


|
|
|





|







 







|







 







|







 







|
|


|
|
|
|

|


|


|












|










|




|



|

|


|






|
|







 







|
|

|







 







|
>
>
|
|
|







 







|
|







110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
...
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
....
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
....
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
....
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
....
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
....
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
....
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
....
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
....
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
....
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
....
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
....
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
....
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
....
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
....
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
....
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
....
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
            catch {file delete -force $f}
        }
        set ::tmpfiles {}
    }
}

# insertLine, when in table mode
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 {$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
................................................................................
            }
            incr col
        }
    }
}

# Insert lineno and text
proc insertLine {top side line text {tag {equal}} {linetag {}}} {
    if {$::eskil($top,view) eq "table"} {
        insertLineTable $top $side $line $text $tag
        return
    }
    $::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$side) insert end [myFormL $line] $tag
}

# Insert an empty line on one side of the diff.
proc emptyLine {top side {highlight 1}} {
    if {$::eskil($top,view) eq "table"} {
        # This should be ignored for table
        return
    }
    if {$highlight} {
        $::widgets($top,wLine$side) insert end "\n" hl$::HighLightCount
    } else {
        $::widgets($top,wLine$side) insert end "*****\n"
    }
    $::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} {
................................................................................
#####################################
# 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
................................................................................
    }
    if {[llength [$w bbox $ei]] == 0} {
        $w yview $si
    }
}

# Highlight a diff
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) $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 changeIndex} {
    # TBD TABLE
    if {$::eskil($top,view) eq "table"} return
    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
................................................................................
        $w edit separator
        set ::eskil($w,allowChange) line
    }
}

# Copy a block
proc copyBlock {top from first last} {
    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]

................................................................................
        }
    }
    endUndoBlock $wfrom $wto
}

# Copy a row between text widgets
proc copyRow {top from row} {
    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
................................................................................
    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 side changeIndex x y} {

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

    # Only copy when in a change block
    if {$changeIndex ne ""} {
        set other [expr {$side == 1 ? 2 : 1}]
        set editOther [mayEdit $top $other]

        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 $other $row]
        } else {
            $m add command -label "Delete Row" \
                    -command [list deleteBlock $top $side $row]
        }
        if {$line ne "" && $editOther} {
            $m add command -label "Copy Row to other side" \
                    -command [list copyRow $top $side $row]
        }

        # Get ranges for the change block
        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
................................................................................
        }
        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 $other $fromo $too]
            } else {
                $m add command -label "Delete Block" \
                        -command [list deleteBlock $top $side $from $to]
            }
            if {$editOther && $thisSize > 0} {
                $m add command -label "Copy Block to other side" \
                        -command [list copyBlock $top $side $from $to]
            }
        }
    }

    $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
................................................................................
    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} {
    # Limit its inital requirements
    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
    # Get all children managed
    grid {*}$children -in $W._dyn -padx 3 -pady 3 -sticky w
    # React
    bind $W <Configure> "DynGridRedo $W"
}

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

proc enableAlign {top} {
................................................................................
    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 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
................................................................................
        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 side x y} {
    # Get the row that was clicked
    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$side) get $row.0 $row.end]

    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 {$side == 1 && $line == $align1} {
                set label "Remove alignment with line $align2"
                set cmd [list clearAlign $top $align1]
            } 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
................................................................................
    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 side x y X Y} {
    # Get the row that was clicked
    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$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) $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 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
................................................................................
    }
    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 {$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]
................................................................................
            append txt "\nAnd Redo Diff"
        }
        $w.l configure -text $txt
    }
}

# Button has been released
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) \
................................................................................
    set ::eskil($top,alignDrag,state) none
}

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

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

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

    if {$changeIndex eq ""} {
        set range [$wd tag ranges sel]
    } else {
        set range [$wl tag ranges hl$::eskil($top,separate$side)]
    }
    set text [$wd get {*}$range]
    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$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 side changeIndex X Y x y} {
    if {[info exists ::eskil($top,nopopup)] && $::eskil($top,nopopup)} return
    destroy .lpm
    menu .lpm

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

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

    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 $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
}
................................................................................
# 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 -> side
    set tmp1 [editMenu  .lpm $top $side "" $x $y]
    if {!$tmp1} {.lpm add separator}
    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
................................................................................

proc nextHighlight {top} {
    # TBD TABLE, stop for now?
    if {$::eskil($top,view) eq "table"} {
        return
    }
    set tag hl$::HighLightCount
    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
................................................................................
    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 -> 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

Changes to src/merge.tcl.

102
103
104
105
106
107
108

109
110
111
112
113
114
115
}

# Fill up the merge window with the initial version of merged files.
proc fillMergeWindow {top} {
    global eskil

    set w $top.merge.t

    $w delete 1.0 end
    set marks {}
    set t 0
    set firstConflict -1
    foreach {commLeft diffLeft} $eskil($top,leftMergeData) \
            {commRight diffRight} $eskil($top,rightMergeData) {
        $w insert end $commRight







>







102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
}

# Fill up the merge window with the initial version of merged files.
proc fillMergeWindow {top} {
    global eskil

    set w $top.merge.t
    ##nagelfar vartype w _obj,text
    $w delete 1.0 end
    set marks {}
    set t 0
    set firstConflict -1
    foreach {commLeft diffLeft} $eskil($top,leftMergeData) \
            {commRight diffRight} $eskil($top,rightMergeData) {
        $w insert end $commRight