Eskil

Diff
Login

Differences From Artifact [3c7ec2186b]:

To Artifact [aeee97dbc7]:


48
49
50
51
52
53
54

55
56
57
58
59
60
61
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62







+







# Do initalisations for needed packages and globals.
# This is not run until needed to speed up command line error reporting.
proc Init {} {
    package require Tk 8.4
    catch {package require textSearch}
    package require wcb
    package require snit
    package require tablelist_tile

    if {[catch {package require psballoon}]} {
        # Add a dummy if it does not exist.
        proc addBalloon {args} {}
    } else {
        namespace import -force psballoon::addBalloon
    }
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94

95
96
97
98
99
100
101
80
81
82
83
84
85
86


87
88
89
90
91
92

93
94
95
96
97
98
99
100







-
-






-
+







    source $::eskil(thisDir)/dirdiff.tcl
    source $::eskil(thisDir)/help.tcl
    source $::eskil(thisDir)/plugin.tcl
    source $::eskil(thisDir)/printobj.tcl
    source $::eskil(thisDir)/print.tcl
    source $::eskil(thisDir)/rev.tcl

    set ::util(diffexe) diff

    # Diff functionality is in the DiffUtil package.
    package require DiffUtil
    # Help DiffUtil to find a diff executable, if needed
    catch {DiffUtil::LocateDiffExe $::eskil(thisScript)}

    # Figure out a place to store temporary files.
    locateTmp ::diff(tmpdir)
    locateTmp ::eskil(tmpdir)

    if {$::tcl_platform(platform) eq "windows"} {
        # Locate CVS if it is in c:/bin
        if {[auto_execok cvs] eq "" && [file exists "c:/bin/cvs.exe"]} {
            set ::env(PATH) "$::env(PATH);c:\\bin"
            auto_reset
        }
162
163
164
165
166
167
168

169
170
171








172
173
174
175
176
177
178
161
162
163
164
165
166
167
168



169
170
171
172
173
174
175
176
177
178
179
180
181
182
183







+
-
-
-
+
+
+
+
+
+
+
+







        }
    }

    interp alias {} toplevel {} ttk::toplevel

    # Use demo images from Tablelist
    set dir $::eskil(thisDir)/../lib/tablelist/demos
    if {[catch {
    set ::img(clsd) [image create photo -file [file join $dir clsdFolder.gif]]
    set ::img(open) [image create photo -file [file join $dir openFolder.gif]]
    set ::img(file) [image create photo -file [file join $dir file.gif]]
        set ::img(clsd) [image create photo -file [file join $dir clsdFolder.gif]]
        set ::img(open) [image create photo -file [file join $dir openFolder.gif]]
        set ::img(file) [image create photo -file [file join $dir file.gif]]
    }]} then {
        set ::img(clsd) ""
        set ::img(open) ""
        set ::img(file) ""
    }
    # Local images
    set dir $::eskil(thisDir)/images
    set ::img(link) [image create photo -file [file join $dir link.gif]]
    set ::img(left) [image create photo -file [file join $dir arrow_left.gif]]
    set ::img(right) [image create photo -file [file join $dir arrow_right.gif]]
    set ::img(browse) [image create photo -file [file join $dir folderopen1.gif]]
    set ::img(up) [image create photo -file [file join $dir arrow_up.gif]]
216
217
218
219
220
221
222
223

224
225

226
227
228
229
230
231
232
233

234
235
236

237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254

255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275

276
277
278
279
280
281
282
221
222
223
224
225
226
227

228
229

230
231
232
233
234
235
236
237

238
239
240

241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258

259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279

280
281
282
283
284
285
286
287







-
+

-
+







-
+


-
+

















-
+




















-
+







# If top = "all" it means quit.
# If eskil is embedded, this should be used to close an eskil toplevel.
proc cleanupAndExit {top} {
    # A security thing to make sure we can exit.
    set cont 0
    if {[catch {
        if {$top != "all"} {
            set i [lsearch $::diff(diffWindows) $top]
            set i [lsearch $::eskil(diffWindows) $top]
            if {$i >= 0} {
                set ::diff(diffWindows) [lreplace $::diff(diffWindows) $i $i]
                set ::eskil(diffWindows) [lreplace $::eskil(diffWindows) $i $i]
            }
            set i [lsearch $::widgets(toolbars) $top.f]
            if {$i >= 0} {
                set ::widgets(toolbars) [lreplace $::widgets(toolbars) $i $i]
            }

            destroy $top
            array unset ::diff $top,*
            array unset ::eskil $top,*

            # Any windows remaining?
            if {[llength $::diff(diffWindows)] > 0} {
            if {[llength $::eskil(diffWindows)] > 0} {
                set cont 1
            }
        }
    } errMsg]} {
        tk_messageBox -icon error -title "Eskil Error" -message \
                "An error occured in the close process.\n$errMsg\n\
                (This is a bug)\nTerminating application." -type ok
    }
    if {$cont} return

    clearTmp
    exit
}

# If embedding, tell eskil about any other toplevel, then
# cleanupAndExit can be used to get rid of it.
proc eskilRegisterToplevel {top} {
    lappend ::diff(diffWindows) $top
    lappend ::eskil(diffWindows) $top
}

# Format a line number
proc myFormL {lineNo} {
    if {![string is integer -strict $lineNo]} {return "$lineNo\n"}
      return [format "%3d: \n" $lineNo]
}

# Get a name for a temporary file
# A tail can be given to make the file more recognisable.
proc tmpFile {{tail {}}} {
    if {[info exists ::tmpcnt]} {
        incr ::tmpcnt
    } else {
        set ::tmpcnt 0
    }
    set name "tmpd[pid]a$::tmpcnt"
    if {$tail ne ""} {
        append name " [file tail $tail]"
    }
    set name [file join $::diff(tmpdir) $name]
    set name [file join $::eskil(tmpdir) $name]
    lappend ::tmpfiles $name
    return $name
}

# Delete temporary files
proc clearTmp {args} {
    if {![info exists ::tmpfiles]} {
323
324
325
326
327
328
329
330
331


332
333
334
335
336

337
338
339

340
341
342
343
344
345
346
328
329
330
331
332
333
334


335
336
337
338
339
340

341
342
343

344
345
346
347
348
349
350
351







-
-
+
+




-
+


-
+








# Insert one line in each text widget.
# Mark them as changed, and optionally parse them.
proc insertMatchingLines {top line1 line2} {
    global doingLine1 doingLine2 Pref

    # FIXA: fully implement filter
    if {$::diff(filter) != ""} {
        if {[regexp $::diff(filter) $line1]} {
    if {$::eskil(filter) != ""} {
        if {[regexp $::eskil(filter) $line1]} {
            insertLine $top 1 $doingLine1 $line1
            insertLine $top 2 $doingLine2 $line2
            incr doingLine1
            incr doingLine2
            set ::diff(filterflag) 1
            set ::eskil(filterflag) 1
            return
        }
        set ::diff(filterflag) 0
        set ::eskil(filterflag) 0
    }

    if {$Pref(parse) != 0} {
        set opts $Pref(ignore)
        if {$Pref(nocase)} {lappend opts -nocase}
        if {$Pref(lineparsewords)} {lappend opts -words}
        set res [DiffUtil::diffStrings {*}$opts $line1 $line2]
501
502
503
504
505
506
507
508

509
510
511
512
513

514
515

516
517
518
519
520
521
522
523
524

525
526

527
528
529
530
531
532
533
506
507
508
509
510
511
512

513
514
515
516
517

518
519

520
521
522
523
524
525
526
527
528

529
530

531
532
533
534
535
536
537
538







-
+




-
+

-
+








-
+

-
+








    set apa [compareBlocks $block1 $block2]
    # Fine grained changes means that each line is considered its own
    # chunk. This is used for merging better to avoid the same decision
    # for an entire block.
    set finegrain [expr {$::Pref(finegrainchunks) && $details}]

    if {$finegrain && $::diff($top,ancestorFile) ne ""} {
    if {$finegrain && $::eskil($top,ancestorFile) ne ""} {
        # Avoid fine grain depending on relation to ancestor
        set leftChange 0
        set leftChangeOrAdd 0
        for {set t $line1} {$t < $line1 + $n1} {incr t} {
            if {[info exists ::diff($top,ancestorLeft,$t)]} {
            if {[info exists ::eskil($top,ancestorLeft,$t)]} {
                set leftChangeOrAdd 1
                if {$::diff($top,ancestorLeft,$t) eq "c"} {
                if {$::eskil($top,ancestorLeft,$t) eq "c"} {
                    set leftChange 1
                    break
                }
            }
        }
        set rightChange 0
        set rightChangeOrAdd 0
        for {set t $line2} {$t < $line2 + $n2} {incr t} {
            if {[info exists ::diff($top,ancestorRight,$t)]} {
            if {[info exists ::eskil($top,ancestorRight,$t)]} {
                set rightChangeOrAdd 1
                if {$::diff($top,ancestorRight,$t) eq "c"} {
                if {$::eskil($top,ancestorRight,$t) eq "c"} {
                    set rightChange 1
                    break
                }
            }
        }
        # Avoid fine grain if either side has no changes against ancestor
        if {!$leftChangeOrAdd || !$rightChangeOrAdd} {
626
627
628
629
630
631
632
633
634


635
636
637
638
639
640
641
631
632
633
634
635
636
637


638
639
640
641
642
643
644
645
646







-
-
+
+







        # All blocks have been processed. Continue until end of file.
        # If "show all" is not on, just display a couple of context lines.
        set limit -1
        if {$Pref(context) >= 0} {
            set limit $Pref(context)
        }
	# Consider any total limit on displayed lines.
        if {$::diff($top,limitlines)} {
            set limit [expr {$::diff($top,limitlines) - $::diff($top,mapMax)}]
        if {$::eskil($top,limitlines)} {
            set limit [expr {$::eskil($top,limitlines) - $::eskil($top,mapMax)}]
            if {$limit < 0} {
                set limit 0
            }
        }
        if {$limit >= 0} {disallowEdit $top}

        set t 0
691
692
693
694
695
696
697
698
699


700
701
702
703
704
705
706
696
697
698
699
700
701
702


703
704
705
706
707
708
709
710
711







-
-
+
+







                emptyLine $top 2 0
                addMapLines $top 1
            }
        }
        incr doingLine1
        incr doingLine2
        incr t
        if {$::diff($top,limitlines) && \
                ($::diff($top,mapMax) > $::diff($top,limitlines))} {
        if {$::eskil($top,limitlines) && \
                ($::eskil($top,mapMax) > $::eskil($top,limitlines))} {
            return
        }
    }
    # This should not happen unless something is wrong...
    if {$doingLine2 != $line2} {
        disallowEdit $top
        $::widgets($top,wDiff1) insert end \
718
719
720
721
722
723
724
725

726
727
728
729
730
731
732
723
724
725
726
727
728
729

730
731
732
733
734
735
736
737







-
+







        # If block parsing is turned off, only do line parsing for
        # blocks of equal size.
        for {set t 0} {$t < $n1} {incr t} {
            gets $ch1 textline1
            gets $ch2 textline2
            insertMatchingLines $top $textline1 $textline2
        }
        if {$::diff(filter) != "" &&  $::diff(filterflag)} {
        if {$::eskil(filter) != "" &&  $::eskil(filterflag)} {
            addMapLines $top $n1
        } else {
            addChange $top $n1 change $line1 $n1 $line2 $n2
            nextHighlight $top
        }
    } else {
        if {$n1 != 0 && $n2 != 0 && $Pref(parse) >= 2 && \
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825








826
827
828
829
830
831
832
833
834
835
836
837

838
839

840
841
842
843
844
845
846
847
848
849


850
851
852
853



854
855

856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874

875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895

896
897
898
899


900
901
902
903
904
905
906
907
908
909



910
911
912
913
914
915
916
816
817
818
819
820
821
822








823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841

842
843

844
845
846
847
848
849
850
851
852


853
854
855



856
857
858
859

860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878

879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899

900
901
902


903
904
905
906
907
908
909
910
911



912
913
914
915
916
917
918
919
920
921







-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+











-
+

-
+








-
-
+
+

-
-
-
+
+
+

-
+


















-
+




















-
+


-
-
+
+







-
-
-
+
+
+







}

#####################################
# Special cases.  Conflict/patch
#####################################

proc startConflictDiff {top file} {
    set ::diff($top,mode) "conflict"
    set ::diff($top,modetype) ""
    set ::diff($top,conflictFile) $file
    set ::diff($top,rightDir) [file dirname $file]
    set ::diff($top,rightOK) 1
    set ::diff($top,rightLabel) $file
    set ::diff($top,leftLabel) $file
    set ::diff($top,leftOK) 0
    set ::eskil($top,mode) "conflict"
    set ::eskil($top,modetype) ""
    set ::eskil($top,conflictFile) $file
    set ::eskil($top,rightDir) [file dirname $file]
    set ::eskil($top,rightOK) 1
    set ::eskil($top,rightLabel) $file
    set ::eskil($top,leftLabel) $file
    set ::eskil($top,leftOK) 0

    # Turn off ignore
    set ::Pref(ignore) " "
    set ::Pref(nocase) 0
    set ::Pref(noempty) 0

    # Try to autodetect line endings in file
    set ch [open $file rb]
    set data [read $ch 10000]
    close $ch
    if {[string first \r\n $data] >= 0} {
        set ::diff($top,mergetranslation) crlf
        set ::eskil($top,mergetranslation) crlf
    } else {
        set ::diff($top,mergetranslation) lf
        set ::eskil($top,mergetranslation) lf
    }
}

# Read a conflict file and extract the two versions.
proc prepareConflict {top} {
    global Pref

    disallowEdit $top
    set ::diff($top,leftFile) [tmpFile]
    set ::diff($top,rightFile) [tmpFile]
    set ::eskil($top,leftFile) [tmpFile]
    set ::eskil($top,rightFile) [tmpFile]

    set ch1 [open $::diff($top,leftFile) w]
    set ch2 [open $::diff($top,rightFile) w]
    set ch [open $::diff($top,conflictFile) r]
    set ch1 [open $::eskil($top,leftFile) w]
    set ch2 [open $::eskil($top,rightFile) w]
    set ch [open $::eskil($top,conflictFile) r]

    set ::diff($top,conflictDiff) {}
    set ::eskil($top,conflictDiff) {}
    set leftLine 1
    set rightLine 1
    set state both
    set rightName ""
    set leftName ""
    while {[gets $ch line] != -1} {
        if {[string match <<<<<<* $line]} {
            set state right
            regexp {<*\s*(.*)} $line -> rightName
            set start2 $rightLine
        } elseif {[string match ======* $line] && $state eq "right"} {
            set state left
            set end2 [expr {$rightLine - 1}]
            set start1 $leftLine
        } elseif {[string match >>>>>>* $line] && $state eq "left"} {
            set state both
            regexp {>*\s*(.*)} $line -> leftName
            set end1 [expr {$leftLine - 1}]
            lappend ::diff($top,conflictDiff) [list \
            lappend ::eskil($top,conflictDiff) [list \
                    $start1 [expr {$end1 - $start1 + 1}] \
                    $start2 [expr {$end2 - $start2 + 1}]]
        } elseif {$state eq "both"} {
            puts $ch1 $line
            puts $ch2 $line
            incr leftLine
            incr rightLine
        } elseif {$state eq "left"} {
            puts $ch1 $line
            incr leftLine
        } else {
            puts $ch2 $line
            incr rightLine
        }
    }
    close $ch
    close $ch1
    close $ch2

    if {$leftName eq "" && $rightName eq ""} {
        set leftName "No Conflict: [file tail $::diff($top,conflictFile)]"
        set leftName "No Conflict: [file tail $::eskil($top,conflictFile)]"
        set rightName $leftName
    }
    set ::diff($top,leftLabel) $leftName
    set ::diff($top,rightLabel) $rightName
    set ::eskil($top,leftLabel) $leftName
    set ::eskil($top,rightLabel) $rightName
    update idletasks
}

# Clean up after a conflict diff.
proc cleanupConflict {top} {
    global Pref

    clearTmp $::diff($top,rightFile) $::diff($top,leftFile)
    set ::diff($top,rightFile) $::diff($top,conflictFile)
    set ::diff($top,leftFile) $::diff($top,conflictFile)
    clearTmp $::eskil($top,rightFile) $::eskil($top,leftFile)
    set ::eskil($top,rightFile) $::eskil($top,conflictFile)
    set ::eskil($top,leftFile) $::eskil($top,conflictFile)
}

# Display one chunk from a patch file
proc displayOnePatch {top leftLines rightLines leftLine rightLine} {
    emptyLine $top 1
    emptyLine $top 2

1014
1015
1016
1017
1018
1019
1020
1021
1022


1023
1024
1025
1026


1027
1028
1029

1030
1031

1032
1033
1034

1035
1036
1037
1038
1039
1040
1041
1019
1020
1021
1022
1023
1024
1025


1026
1027
1028
1029


1030
1031
1032
1033

1034
1035

1036
1037
1038

1039
1040
1041
1042
1043
1044
1045
1046







-
-
+
+


-
-
+
+


-
+

-
+


-
+







    }
}

# Read a patch file and display it
proc displayPatch {top} {
    global Pref

    set ::diff($top,leftLabel) "Patch $::diff($top,patchFile): old"
    set ::diff($top,rightLabel) "Patch $::diff($top,patchFile): new"
    set ::eskil($top,leftLabel) "Patch $::eskil($top,patchFile): old"
    set ::eskil($top,rightLabel) "Patch $::eskil($top,patchFile): new"
    update idletasks

    if {$::diff($top,patchFile) eq ""} {
        if {$::diff($top,patchData) eq ""} {
    if {$::eskil($top,patchFile) eq ""} {
        if {$::eskil($top,patchData) eq ""} {
            set data [getFullPatch $top]
        } else {
            set data $::diff($top,patchData)
            set data $::eskil($top,patchData)
        }
    } elseif {$::diff($top,patchFile) eq "-"} {
    } elseif {$::eskil($top,patchFile) eq "-"} {
        set data [read stdin]
    } else {
        set ch [open $::diff($top,patchFile) r]
        set ch [open $::eskil($top,patchFile) r]
        set data [read $ch]
        close $ch
    }

    set style ""
    set divider "-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-"

1197
1198
1199
1200
1201
1202
1203
1204
1205


1206
1207
1208


1209
1210

1211
1212

1213
1214

1215
1216
1217
1218
1219
1220

1221
1222
1223
1224
1225
1226
1227

1228
1229
1230
1231
1232
1233
1234
1202
1203
1204
1205
1206
1207
1208


1209
1210
1211


1212
1213
1214

1215
1216

1217
1218

1219
1220
1221
1222
1223
1224

1225
1226
1227
1228
1229
1230
1231

1232
1233
1234
1235
1236
1237
1238
1239







-
-
+
+

-
-
+
+

-
+

-
+

-
+





-
+






-
+








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

# Prepare for a diff by creating needed temporary files
proc prepareFiles {top} {
    set ::diff($top,cleanup) {}
    if {$::diff($top,mode) eq "rev"} {
    set ::eskil($top,cleanup) {}
    if {$::eskil($top,mode) eq "rev"} {
        prepareRev $top
        lappend ::diff($top,cleanup) "rev"
    } elseif {$::diff($top,mode) eq "conflict"} {
        lappend ::eskil($top,cleanup) "rev"
    } elseif {$::eskil($top,mode) eq "conflict"} {
        prepareConflict $top
        lappend ::diff($top,cleanup) "conflict"
        lappend ::eskil($top,cleanup) "conflict"
    }
    if {$::diff($top,plugin) ne ""} {
    if {$::eskil($top,plugin) ne ""} {
        preparePlugin $top
        set ::diff($top,cleanup) "plugin $::diff($top,cleanup)"
        set ::eskil($top,cleanup) "plugin $::eskil($top,cleanup)"
    }
}

# Clean up after a diff
proc cleanupFiles {top} {
    foreach keyword $::diff($top,cleanup) {
    foreach keyword $::eskil($top,cleanup) {
        switch $keyword {
            "rev"      {cleanupRev      $top}
            "conflict" {cleanupConflict $top}
            "plugin"   {cleanupPlugin   $top}
        }
    }
    set ::diff($top,cleanup) {}
    set ::eskil($top,cleanup) {}
}

# Redo Diff command
proc redoDiff {top} {
    # Note what rows are being displayed
    set w $::widgets($top,wDiff1)

1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268







1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281

1282
1283
1284
1285
1286
1287
1288
1260
1261
1262
1263
1264
1265
1266







1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285

1286
1287
1288
1289
1290
1291
1292
1293







-
-
-
-
-
-
-
+
+
+
+
+
+
+












-
+







        set w $::widgets($top,$item)
        seeText $w $first.0 $last.0
    }
}

# Make an appropriate tail for a window title, depending on mode and files.
proc TitleTail {top} {
    set tail1 [file tail $::diff($top,rightLabel)]
    set tail2 [file tail $::diff($top,leftLabel)]
    if {$::diff($top,mode) ne "" || $tail1 eq $tail2} {
        if {$::diff($top,mode) eq "rev"} {
            set tail1 [file tail $::diff($top,RevFile)]
        } elseif {$::diff($top,mode) eq "conflict"} {
            set tail1 [file tail $::diff($top,conflictFile)]
    set tail1 [file tail $::eskil($top,rightLabel)]
    set tail2 [file tail $::eskil($top,leftLabel)]
    if {$::eskil($top,mode) ne "" || $tail1 eq $tail2} {
        if {$::eskil($top,mode) eq "rev"} {
            set tail1 [file tail $::eskil($top,RevFile)]
        } elseif {$::eskil($top,mode) eq "conflict"} {
            set tail1 [file tail $::eskil($top,conflictFile)]
        }
        return $tail1
    } else {
        return "$tail2 vs $tail1"
    }
}

# Main diff function.
proc doDiff {top} {
    global Pref
    global doingLine1 doingLine2

    if {$::diff($top,mode) eq "" && ($::diff($top,leftOK) == 0 || $::diff($top,rightOK) == 0)} {
    if {$::eskil($top,mode) eq "" && ($::eskil($top,leftOK) == 0 || $::eskil($top,rightOK) == 0)} {
        disableRedo $top
        return
    } else {
        enableRedo $top
    }

    busyCursor $top
1300
1301
1302
1303
1304
1305
1306
1307

1308
1309
1310
1311
1312
1313
1314
1315
1316

1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332



1333
1334
1335
1336
1337



1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348


1349
1350

1351
1352
1353


1354
1355

1356
1357
1358
1359
1360
1361
1362
1363
1364
1365


1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386

1387
1388
1389
1390
1391
1392
1393


1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414


1415
1416
1417
1418
1419
1420

1421
1422
1423
1424
1425
1426
1427
1305
1306
1307
1308
1309
1310
1311

1312
1313
1314
1315
1316
1317
1318
1319
1320

1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334



1335
1336
1337
1338
1339



1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351


1352
1353
1354

1355
1356


1357
1358
1359

1360
1361
1362
1363
1364
1365
1366
1367
1368


1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390

1391
1392
1393
1394
1395
1396


1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417


1418
1419
1420
1421
1422
1423
1424

1425
1426
1427
1428
1429
1430
1431
1432







-
+








-
+













-
-
-
+
+
+


-
-
-
+
+
+









-
-
+
+

-
+

-
-
+
+

-
+








-
-
+
+




















-
+





-
-
+
+



















-
-
+
+





-
+







    # Display a star during diff execution, to know when the internal
    # processing starts, and when the label is "valid".
    set ::widgets($top,eqLabel) "*"

    wm title $top "Eskil:"
    update idletasks

    if {$::diff($top,mode) eq "patch"} {
    if {$::eskil($top,mode) eq "patch"} {
        disallowEdit $top
        displayPatch $top
        drawMap $top -1
        foreach item {wLine1 wLine2} {
            set w $::widgets($top,$item)
            $w configure -state disabled
        }
        update idletasks
        wm title $top "Eskil: [file tail $::diff($top,patchFile)]"
        wm title $top "Eskil: [file tail $::eskil($top,patchFile)]"
        $::widgets($top,wLine2) see 1.0
        normalCursor $top
        return
    } else {
        prepareFiles $top
    }

    wm title $top "Eskil: [TitleTail $top]"

    # Run diff and parse the result.
    set opts $Pref(ignore)
    if {$Pref(nocase)} {lappend opts -nocase}
    if {$Pref(noempty)} {lappend opts -noempty}
    if {[info exists ::diff($top,aligns)] && \
            [llength $::diff($top,aligns)] > 0} {
        lappend opts -align $::diff($top,aligns)
    if {[info exists ::eskil($top,aligns)] && \
            [llength $::eskil($top,aligns)] > 0} {
        lappend opts -align $::eskil($top,aligns)
    }
    set range {}
    if {[info exists ::diff($top,range)] && \
            [llength $::diff($top,range)] == 4} {
        set range $::diff($top,range)
    if {[info exists ::eskil($top,range)] && \
            [llength $::eskil($top,range)] == 4} {
        set range $::eskil($top,range)
        lappend opts -range $range
    }
    if {[llength $Pref(regsub)] > 0} {
        lappend opts -regsub $Pref(regsub)
    }
    # Apply nodigit after preprocess
    if {$Pref(nodigit)} {lappend opts -nodigit}

    # If a special file for diffing is present, use it.
    if {[info exists ::diff($top,leftFileDiff)]} {
        set dFile1 $::diff($top,leftFileDiff)
    if {[info exists ::eskil($top,leftFileDiff)]} {
        set dFile1 $::eskil($top,leftFileDiff)
    } else {
        set dFile1 $::diff($top,leftFile)
        set dFile1 $::eskil($top,leftFile)
    }
    if {[info exists ::diff($top,rightFileDiff)]} {
        set dFile2 $::diff($top,rightFileDiff)
    if {[info exists ::eskil($top,rightFileDiff)]} {
        set dFile2 $::eskil($top,rightFileDiff)
    } else {
        set dFile2 $::diff($top,rightFile)
        set dFile2 $::eskil($top,rightFile)
    }

    set differr [catch {DiffUtil::diffFiles {*}$opts \
            $dFile1 $dFile2} diffres]

    # In conflict mode we can use the diff information collected when
    # parsing the conflict file. This makes sure the blocks in the conflict
    # file become change-blocks during merge.
    if {$::diff($top,mode) eq "conflict" && $::diff($top,modetype) eq "Pure"} {
        set diffres $::diff($top,conflictDiff)
    if {$::eskil($top,mode) eq "conflict" && $::eskil($top,modetype) eq "Pure"} {
        set diffres $::eskil($top,conflictDiff)
    }

    if {$differr != 0} {
        $::widgets($top,wDiff1) insert end $diffres
        normalCursor $top
        return
    }
    if {[llength $diffres] == 0} {
        set ::widgets($top,eqLabel) "="
        # Automatically close if equal
        if {$::eskil(autoclose)} {
            after idle cleanupAndExit $top
            return
        }
    } else {
        set ::widgets($top,eqLabel) " "
    }
    # Update the equal label immediately for better feedback
    update idletasks

    if {$::diff($top,ancestorFile) ne ""} {
    if {$::eskil($top,ancestorFile) ne ""} {
        collectAncestorInfo $top $dFile1 $dFile2 $opts
    }

    set firstview 1

    set ch1 [open $::diff($top,leftFile)]
    set ch2 [open $::diff($top,rightFile)]
    set ch1 [open $::eskil($top,leftFile)]
    set ch2 [open $::eskil($top,rightFile)]
    set doingLine1 1
    set doingLine2 1

    # If there is a range, skip lines up to the range
    if {[llength $range] != 0} {
        disallowEdit $top
        lassign $range start1 end1 start2 end2
        while {$doingLine1 < $start1 && [gets $ch1 line] >= 0} {
            incr doingLine1
        }
        while {$doingLine2 < $start2 && [gets $ch2 line] >= 0} {
            incr doingLine2
        }
    }

    set t 0
    foreach i $diffres {
        lassign $i line1 n1 line2 n2
        doText $top $ch1 $ch2 $n1 $n2 $line1 $line2
        if {$::diff($top,limitlines) && \
                ($::diff($top,mapMax) > $::diff($top,limitlines))} {
        if {$::eskil($top,limitlines) && \
                ($::eskil($top,mapMax) > $::eskil($top,limitlines))} {
            break
        }

        # Get one update when the screen has been filled.
        # Show the first diff.
        if {$firstview && $::diff($top,mapMax) > 100} {
        if {$firstview && $::eskil($top,mapMax) > 100} {
            set firstview 0
            showDiff $top 0
            update idletasks
        }
    }

    # If there is a range, just display the range
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463



1464
1465
1466
1467
1468
1469
1470
1459
1460
1461
1462
1463
1464
1465



1466
1467
1468
1469
1470
1471
1472
1473
1474
1475







-
-
-
+
+
+







    close $ch2

    # We can turn off editing in the text windows after everything
    # is displayed.
    noEdit $top

    # Mark aligned lines
    if {[info exists ::diff($top,aligns)] && \
            [llength $::diff($top,aligns)] > 0} {
        foreach {align1 align2} $::diff($top,aligns) {
    if {[info exists ::eskil($top,aligns)] && \
            [llength $::eskil($top,aligns)] > 0} {
        foreach {align1 align2} $::eskil($top,aligns) {
            set i [$::widgets($top,wLine1) search -regexp "\\m$align1\\M" 1.0]
            if {$i != ""} {
                $::widgets($top,wLine1) tag add align \
                        "$i linestart" "$i lineend"
            }
            set i [$::widgets($top,wLine2) search -regexp "\\m$align2\\M" 1.0]
            if {$i != ""} {
1484
1485
1486
1487
1488
1489
1490
1491

1492
1493
1494
1495

1496
1497
1498
1499
1500

1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516

1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538



1539
1540

1541
1542
1543
1544
1545
1546
1547





1548
1549

1550
1551

1552
1553
1554
1555
1556
1557
1558
1559
1560

1561
1562
1563

1564
1565
1566
1567
1568
1569
1570
1489
1490
1491
1492
1493
1494
1495

1496
1497
1498
1499

1500
1501
1502
1503
1504

1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520

1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540



1541
1542
1543
1544

1545
1546
1547





1548
1549
1550
1551
1552
1553

1554
1555

1556
1557
1558
1559
1560
1561
1562
1563
1564

1565
1566
1567

1568
1569
1570
1571
1572
1573
1574
1575







-
+



-
+




-
+















-
+



















-
-
-
+
+
+

-
+


-
-
-
-
-
+
+
+
+
+

-
+

-
+








-
+


-
+







    normalCursor $top
    showDiff $top 0
    if {$::widgets($top,eqLabel) eq "!"} {
        set ::widgets($top,eqLabel) " "
    }

    cleanupFiles $top
    if {$::diff($top,mode) eq "conflict"} {
    if {$::eskil($top,mode) eq "conflict"} {
        if {$::widgets($top,eqLabel) != "="} {
            makeMergeWin $top
        }
    } elseif {$::diff($top,ancestorFile) ne ""} {
    } elseif {$::eskil($top,ancestorFile) ne ""} {
        if {$::widgets($top,eqLabel) != "="} {
            makeMergeWin $top
        }
    }
    if {$::diff($top,printFile) ne ""} {
    if {$::eskil($top,printFile) ne ""} {
        after idle "doPrint $top 1 ; cleanupAndExit all"
    }
}

# This is the entrypoint to do a diff via DDE or Send
proc remoteDiff {file1 file2} {
    newDiff $file1 $file2
}

#####################################
# Highlight and navigation stuff
#####################################

# Scroll windows to next/previous diff
proc findDiff {top delta} {
    showDiff $top [expr {$::diff($top,currHighLight) + $delta}]
    showDiff $top [expr {$::eskil($top,currHighLight) + $delta}]
}

# Scroll a text window to view a certain range, and possibly some
# lines before and after.
proc seeText {w si ei} {
    $w see $ei
    $w see $si
    $w see $si-5lines
    $w see $ei+5lines
    if {[llength [$w bbox $si]] == 0} {
        $w yview $si-5lines
    }
    if {[llength [$w bbox $ei]] == 0} {
        $w yview $si
    }
}

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

# Highlight a diff and scroll windows to it.
proc showDiff {top num} {
    highLightChange $top $num

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

    if {$::diff($top,currHighLight) < 0} {
    if {$::eskil($top,currHighLight) < 0} {
        set line1 1.0
        set line2 1.0
    } elseif {$line1 eq ""} {
        set line1 end
        set line2 end
    } else {
        set line2 [expr {$line1 + [lindex $change 1]}]
1584
1585
1586
1587
1588
1589
1590
1591
1592


1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605

1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619

1620
1621
1622
1623
1624
1625
1626

1627
1628
1629
1630

1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649

1650
1651
1652
1653

1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671

1672
1673
1674
1675
1676
1677
1678


1679
1680
1681
1682


1683
1684
1685
1686
1687
1688
1689
1690

1691
1692
1693

1694
1695

1696
1697
1698
1699
1700
1701
1702
1703

1704
1705

1706
1707
1708
1709
1710
1711
1712
1713
1714

1715
1716
1717
1718
1719
1720
1721
1722
1723

1724
1725
1726
1727
1728
1729
1730
1589
1590
1591
1592
1593
1594
1595


1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609

1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623

1624
1625
1626
1627
1628
1629
1630

1631
1632
1633
1634

1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653

1654
1655
1656
1657

1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675

1676
1677
1678
1679
1680
1681


1682
1683
1684
1685


1686
1687
1688
1689
1690
1691
1692
1693
1694

1695
1696
1697

1698
1699

1700
1701
1702
1703
1704
1705
1706
1707

1708
1709

1710
1711
1712
1713
1714
1715
1716
1717
1718

1719
1720
1721
1722
1723
1724
1725
1726
1727

1728
1729
1730
1731
1732
1733
1734
1735







-
-
+
+












-
+













-
+






-
+



-
+


















-
+



-
+

















-
+





-
-
+
+


-
-
+
+







-
+


-
+

-
+







-
+

-
+








-
+








-
+







#####################################

# FIXA: Use snit to adapt text widget instead of using wcb
# include seeText in such a snidget.

# Clear Editing state
proc resetEdit {top} {
    set ::diff($top,leftEdit) 0
    set ::diff($top,rightEdit) 0
    set ::eskil($top,leftEdit) 0
    set ::eskil($top,rightEdit) 0
    $top.m.mt entryconfigure "Edit Mode" -state normal

    resetEditW $::widgets($top,wDiff1)
    resetEditW $::widgets($top,wDiff2)
}

# Clear Editing state for a Text widget
proc resetEditW {w} {
    $w tag configure padding -background {}
    $w edit reset
    $w configure -undo 0

    set ::diff($w,allowChange) all
    set ::eskil($w,allowChange) all

    wcb::callback $w before insert {}
    wcb::callback $w before delete {}
}

# Do not allow any editing
proc noEdit {top} {
    noEditW $::widgets($top,wDiff1)
    noEditW $::widgets($top,wDiff2)
}

# Do not allow any editing in a Text widget
proc noEditW {w} {
    set ::diff($w,allowChange) none
    set ::eskil($w,allowChange) none

    wcb::callback $w before insert [list TextInterceptInsert $w]
    wcb::callback $w before delete [list TextInterceptDelete $w]
}

proc TextInterceptInsert {w ow index str args} {
    if {$::diff($w,allowChange) eq "none"} {
    if {$::eskil($w,allowChange) eq "none"} {
        wcb::cancel
        return
    }
    if {$::diff($w,allowChange) eq "all"} return
    if {$::eskil($w,allowChange) eq "all"} return

    #wcb::cancel - Cancel a widget command
    #wcb::replace - Replace arguments of a widget command with new ones

    # Disallow all new lines
    if {[string first "\n" $str] >= 0} {
        wcb::cancel
        return
    }
    foreach {tag str2} $args {
        if {[string first "\n" $str2] >= 0} {
            wcb::cancel
            return
        }
    }
}

proc TextInterceptDelete {w ow from {to {}}} {
    if {$::diff($w,allowChange) eq "none"} {
    if {$::eskil($w,allowChange) eq "none"} {
        wcb::cancel
        return
    }
    if {$::diff($w,allowChange) eq "all"} return
    if {$::eskil($w,allowChange) eq "all"} return

    if {$to eq ""} {
        set to $from+1char
    }
    set text [$ow get $from $to]
    # Disallow all new lines
    if {[string first "\n" $text] >= 0} {
        wcb::cancel
        return
    }
}

# Turn on editing for a Text widget
proc turnOnEdit {w} {
    $w tag configure padding -background \#f0f0f0
    $w configure -undo 1

    set ::diff($w,allowChange) line
    set ::eskil($w,allowChange) line
}

# Turn on editing on sides where it has not been disallowed
proc allowEdit {top} {
    $top.m.mt entryconfigure "Edit Mode" -state disable
    if {$::diff($top,leftEdit) == 0} {
        set ::diff($top,leftEdit) 1
    if {$::eskil($top,leftEdit) == 0} {
        set ::eskil($top,leftEdit) 1
        turnOnEdit $::widgets($top,wDiff1)
    }
    if {$::diff($top,rightEdit) == 0} {
        set ::diff($top,rightEdit) 1
    if {$::eskil($top,rightEdit) == 0} {
        set ::eskil($top,rightEdit) 1
        turnOnEdit $::widgets($top,wDiff2)
    }
}

# Turn off editing on sides that do not correspond to a file
proc disallowEdit {top {side 0}} {
    if {$side == 0 || $side == 1} {
        set ::diff($top,leftEdit) -1
        set ::eskil($top,leftEdit) -1
    }
    if {$side == 0 || $side == 2} {
        set ::diff($top,rightEdit) -1
        set ::eskil($top,rightEdit) -1
    }
    if {$::diff($top,leftEdit) == -1 && $::diff($top,rightEdit) == -1} {
    if {$::eskil($top,leftEdit) == -1 && $::eskil($top,rightEdit) == -1} {
        $top.m.mt entryconfigure "Edit Mode" -state disabled
    }
}

# Ask if editing is allowed on a side
proc mayEdit {top side} {
    if {$side == 1} {
        return [expr {$::diff($top,leftEdit) == 1}]
        return [expr {$::eskil($top,leftEdit) == 1}]
    } else {
        return [expr {$::diff($top,rightEdit) == 1}]
        return [expr {$::eskil($top,rightEdit) == 1}]
    }
}

# Start an undo block in a bunch of text widgets
proc startUndoBlock {args} {
    foreach w $args {
        $w configure -autoseparators 0
        # Open up editing for copy functions
        set ::diff($w,allowChange) all
        set ::eskil($w,allowChange) all
    }
}

# End an undo block in a bunch of text widgets
proc endUndoBlock {args} {
    foreach w $args {
        $w configure -autoseparators 1
        $w edit separator
        set ::diff($w,allowChange) line
        set ::eskil($w,allowChange) line
    }
}

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

1876
1877
1878
1879
1880
1881
1882
1883
1884


1885
1886
1887


1888
1889
1890
1891
1892
1893
1894
1881
1882
1883
1884
1885
1886
1887


1888
1889
1890


1891
1892
1893
1894
1895
1896
1897
1898
1899







-
-
+
+

-
-
+
+







    $m add command -label "Save File" -command [list saveFile $top $n]

    return 0
}

proc saveFile {top side} {
    if {$side == 1} {
        if {!$::diff($top,leftEdit)} return
        set fileName $::diff($top,leftFile)
        if {!$::eskil($top,leftEdit)} return
        set fileName $::eskil($top,leftFile)
    } else {
        if {!$::diff($top,rightEdit)} return
        set fileName $::diff($top,rightFile)
        if {!$::eskil($top,rightEdit)} return
        set fileName $::eskil($top,rightFile)
    }

    set w $::widgets($top,wDiff$side)

    # Confirm dialog
    set apa [tk_messageBox -parent $top -icon question \
            -title "Overwrite file" -type yesnocancel -message \
1953
1954
1955
1956
1957
1958
1959
1960

1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976




1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987




1988
1989
1990
1991
1992
1993
1994
1995
1996
1997




1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008




2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020






2021
2022
2023
2024
2025
2026
2027

2028
2029
2030
2031
2032
2033
2034
2035
2036


2037
2038
2039
2040
2041
2042
2043
2044


2045
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
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139






2140
2141
2142
2143
2144
2145
2146
2147






2148
2149

2150
2151
2152
2153
2154
2155
2156
1958
1959
1960
1961
1962
1963
1964

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




1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988




1989
1990
1991
1992
1993
1994
1995
1996
1997
1998




1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009




2010
2011
2012
2013
2014
2015
2016
2017
2018
2019






2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031

2032
2033
2034
2035
2036
2037
2038
2039


2040
2041
2042
2043
2044
2045
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
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138






2139
2140
2141
2142
2143
2144
2145
2146






2147
2148
2149
2150
2151
2152
2153

2154
2155
2156
2157
2158
2159
2160
2161







-
+












-
-
-
-
+
+
+
+







-
-
-
-
+
+
+
+






-
-
-
-
+
+
+
+







-
-
-
-
+
+
+
+






-
-
-
-
-
-
+
+
+
+
+
+






-
+







-
-
+
+






-
-
+
+














-
-
+
+







-
+



-
-
+
+











-
+



-
-
+
+





-
+



-
+


-
-
+
+







-
-
+
+




















-
-
-
-
-
-
+
+
+
+
+
+


-
-
-
-
-
-
+
+
+
+
+
+

-
+







    return [file isdirectory $file]
}

# A wrapper for tk_getOpenFile
proc myOpenFile {args} {
    # When in tutorial mode, make sure the Tcl file dialog is used
    # to be able to access the files in a starkit.
    if {[info exists ::diff(tutorial)] && $::diff(tutorial)} {
    if {[info exists ::eskil(tutorial)] && $::eskil(tutorial)} {
        # Only do this if tk_getOpenFile is not a proc.
        if {[info procs tk_getOpenFile] eq ""} {
            # If there is any problem, call the real one
            if {![catch {set res [::tk::dialog::file:: open {*}$args]}]} {
                return $res
            }
        }
    }
    return [tk_getOpenFile {*}$args]
}

proc doOpenLeft {top {forget 0}} {
    if {!$forget && [info exists ::diff($top,leftDir)]} {
        set initDir $::diff($top,leftDir)
    } elseif {[info exists ::diff($top,rightDir)]} {
        set initDir $::diff($top,rightDir)
    if {!$forget && [info exists ::eskil($top,leftDir)]} {
        set initDir $::eskil($top,leftDir)
    } elseif {[info exists ::eskil($top,rightDir)]} {
        set initDir $::eskil($top,rightDir)
    } else {
        set initDir [pwd]
    }

    set apa [myOpenFile -title "Select left file" -initialdir $initDir \
            -parent $top]
    if {$apa != ""} {
        set ::diff($top,leftDir) [file dirname $apa]
        set ::diff($top,leftFile) $apa
        set ::diff($top,leftLabel) $apa
        set ::diff($top,leftOK) 1
        set ::eskil($top,leftDir) [file dirname $apa]
        set ::eskil($top,leftFile) $apa
        set ::eskil($top,leftLabel) $apa
        set ::eskil($top,leftOK) 1
        return 1
    }
    return 0
}

proc doOpenRight {top {forget 0}} {
    if {!$forget && [info exists ::diff($top,rightDir)]} {
        set initDir $::diff($top,rightDir)
    } elseif {[info exists ::diff($top,leftDir)]} {
        set initDir $::diff($top,leftDir)
    if {!$forget && [info exists ::eskil($top,rightDir)]} {
        set initDir $::eskil($top,rightDir)
    } elseif {[info exists ::eskil($top,leftDir)]} {
        set initDir $::eskil($top,leftDir)
    } else {
        set initDir [pwd]
    }

    set apa [myOpenFile -title "Select right file" -initialdir $initDir \
            -parent $top]
    if {$apa != ""} {
        set ::diff($top,rightDir) [file dirname $apa]
        set ::diff($top,rightFile) $apa
        set ::diff($top,rightLabel) $apa
        set ::diff($top,rightOK) 1
        set ::eskil($top,rightDir) [file dirname $apa]
        set ::eskil($top,rightFile) $apa
        set ::eskil($top,rightLabel) $apa
        set ::eskil($top,rightOK) 1
        return 1
    }
    return 0
}

proc doOpenAncestor {top} {
    if {$::diff($top,ancestorFile) ne ""} {
        set initDir [file dirname $::diff($top,ancestorFile)]
    } elseif {[info exists ::diff($top,leftDir)]} {
        set initDir $::diff($top,leftDir)
    } elseif {[info exists ::diff($top,rightDir)]} {
        set initDir $::diff($top,rightDir)
    if {$::eskil($top,ancestorFile) ne ""} {
        set initDir [file dirname $::eskil($top,ancestorFile)]
    } elseif {[info exists ::eskil($top,leftDir)]} {
        set initDir $::eskil($top,leftDir)
    } elseif {[info exists ::eskil($top,rightDir)]} {
        set initDir $::eskil($top,rightDir)
    } else {
        set initDir [pwd]
    }
    set apa [myOpenFile -title "Select ancestor file" -initialdir $initDir \
            -parent $top]
    if {$apa != ""} {
        set ::diff($top,ancestorFile) $apa
        set ::eskil($top,ancestorFile) $apa
        return 1
    }
    return 0
}

proc openLeft {top} {
    if {[doOpenLeft $top]} {
        set ::diff($top,mode) ""
        set ::diff($top,mergeFile) ""
        set ::eskil($top,mode) ""
        set ::eskil($top,mergeFile) ""
        doDiff $top
    }
}

proc openRight {top} {
    if {[doOpenRight $top]} {
        set ::diff($top,mode) ""
        set ::diff($top,mergeFile) ""
        set ::eskil($top,mode) ""
        set ::eskil($top,mergeFile) ""
        doDiff $top
    }
}

proc openAncestor {top} {
    if {[doOpenAncestor $top]} {
        # Redo diff with ancestor
        doDiff $top
    }
}

proc openConflict {top} {
    global Pref
    if {[doOpenRight $top]} {
        startConflictDiff $top $::diff($top,rightFile)
        set ::diff($top,mergeFile) ""
        startConflictDiff $top $::eskil($top,rightFile)
        set ::eskil($top,mergeFile) ""
        doDiff $top
    }
}

proc openPatch {top} {
    global Pref
    if {[doOpenLeft $top]} {
        set ::diff($top,mode) "patch"
        set ::eskil($top,mode) "patch"
        set Pref(ignore) " "
        set Pref(nocase) 0
        set Pref(noempty) 0 
        set ::diff($top,patchFile) $::diff($top,leftFile)
        set ::diff($top,patchData) ""
        set ::eskil($top,patchFile) $::eskil($top,leftFile)
        set ::eskil($top,patchData) ""
        doDiff $top
    }
}

# Get data from clipboard and display as a patch.
proc doPastePatch {top} {
    if {[catch {::tk::GetSelection $top CLIPBOARD} sel]} {
        tk_messageBox -icon error -title "Eskil Error" -parent $top \
                -message "Could not retreive clipboard" -type ok
        return
    }
    set ::diff($top,mode) "patch"
    set ::eskil($top,mode) "patch"
    set ::Pref(ignore) " "
    set ::Pref(nocase) 0
    set ::Pref(noempty) 0 
    set ::diff($top,patchFile) ""
    set ::diff($top,patchData) $sel
    set ::eskil($top,patchFile) ""
    set ::eskil($top,patchData) $sel
    doDiff $top
}

proc openRev {top} {
    if {[doOpenRight $top]} {
        set rev [detectRevSystem $::diff($top,rightFile)]
        set rev [detectRevSystem $::eskil($top,rightFile)]
        if {$rev eq ""} {
            tk_messageBox -icon error -title "Eskil Error" -message \
                    "Could not figure out which revison control system\
                    \"$::diff($top,rightFile)\" is under." -type ok
                    \"$::eskil($top,rightFile)\" is under." -type ok
            return
        }
        startRevMode $top $rev $::diff($top,rightFile)
        set ::diff($top,mergeFile) ""
        startRevMode $top $rev $::eskil($top,rightFile)
        set ::eskil($top,mergeFile) ""
        doDiff $top
    }
}

proc openBoth {top forget} {
    if {[doOpenLeft $top]} {
        if {[doOpenRight $top $forget]} {
            set ::diff($top,mode) ""
            set ::diff($top,mergeFile) ""
            set ::eskil($top,mode) ""
            set ::eskil($top,mergeFile) ""
            doDiff $top
        }
    }
}

# File drop using TkDnd
proc fileDrop {top side files} {
    # FIXA: Maybe single drop during rev mode should stay in rev mode?
    # Dropping two files mean set both
    if {[llength $files] >= 2} {
        set leftFile [lindex $files 0]
        set rightFile [lindex $files 1]
    } elseif {$side eq "left"} {
        set leftFile [lindex $files 0]
        set rightFile ""
    } else {
        set leftFile ""
        set rightFile [lindex $files 0]
    }
    if {$leftFile ne ""} {
        set ::diff($top,leftDir) [file dirname $leftFile]
        set ::diff($top,leftFile) $leftFile
        set ::diff($top,leftLabel) $leftFile
        set ::diff($top,leftOK) 1
        set ::diff($top,mode) ""
        set ::diff($top,mergeFile) ""
        set ::eskil($top,leftDir) [file dirname $leftFile]
        set ::eskil($top,leftFile) $leftFile
        set ::eskil($top,leftLabel) $leftFile
        set ::eskil($top,leftOK) 1
        set ::eskil($top,mode) ""
        set ::eskil($top,mergeFile) ""
    }
    if {$rightFile ne ""} {
        set ::diff($top,rightDir) [file dirname $rightFile]
        set ::diff($top,rightFile) $rightFile
        set ::diff($top,rightLabel) $rightFile
        set ::diff($top,rightOK) 1
        set ::diff($top,mode) ""
        set ::diff($top,mergeFile) ""
        set ::eskil($top,rightDir) [file dirname $rightFile]
        set ::eskil($top,rightFile) $rightFile
        set ::eskil($top,rightLabel) $rightFile
        set ::eskil($top,rightOK) 1
        set ::eskil($top,mode) ""
        set ::eskil($top,mergeFile) ""
    }
    if {$::diff($top,leftOK) && $::diff($top,rightOK)} {
    if {$::eskil($top,leftOK) && $::eskil($top,rightOK)} {
        doDiff $top
    }
}

#####################################
# GUI stuff
#####################################
2214
2215
2216
2217
2218
2219
2220
2221

2222
2223
2224
2225

2226
2227
2228

2229
2230
2231
2232
2233
2234
2235
2236

2237
2238
2239
2240
2241
2242
2243
2244
2245




2246
2247
2248
2249
2250
2251


2252
2253
2254


2255
2256
2257
2258
2259
2260
2261
2262

2263
2264
2265
2266
2267
2268
2269
2219
2220
2221
2222
2223
2224
2225

2226
2227
2228
2229

2230
2231
2232

2233
2234
2235
2236
2237
2238
2239
2240

2241
2242
2243
2244
2245
2246




2247
2248
2249
2250
2251
2252
2253
2254


2255
2256
2257


2258
2259
2260
2261
2262
2263
2264
2265
2266

2267
2268
2269
2270
2271
2272
2273
2274







-
+



-
+


-
+







-
+





-
-
-
-
+
+
+
+




-
-
+
+

-
-
+
+







-
+







proc disableAlign {top} {
    eval $::widgets($top,disableAlignCmd)
}

# Remove one or all alignment pairs
proc clearAlign {top {leftline {}}} {
    if {$leftline == ""} {
        set ::diff($top,aligns) {}
        set ::eskil($top,aligns) {}
    } else {
        set i 0
        while 1 {
            set i [lsearch -integer -start $i $::diff($top,aligns) $leftline]
            set i [lsearch -integer -start $i $::eskil($top,aligns) $leftline]
            if {$i < 0} break
            if {($i % 2) == 0} {
                set ::diff($top,aligns) [lreplace $::diff($top,aligns) \
                set ::eskil($top,aligns) [lreplace $::eskil($top,aligns) \
                        $i [+ $i 1]]
                break
            }
            incr i
        }
    }

    if {[llength $::diff($top,aligns)] == 0} {
    if {[llength $::eskil($top,aligns)] == 0} {
        disableAlign $top
    }
}

proc NoMarkAlign {top} {
    unset -nocomplain ::diff($top,align1)
    unset -nocomplain ::diff($top,align2)
    unset -nocomplain ::diff($top,aligntext1)
    unset -nocomplain ::diff($top,aligntext2)
    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 ::diff($top,align$n) $line
    set ::diff($top,aligntext$n) $text
    set ::eskil($top,align$n) $line
    set ::eskil($top,aligntext$n) $text

    if {[info exists ::diff($top,align1)] && [info exists ::diff($top,align2)]} {
        if {![string equal $::diff($top,aligntext1) $::diff($top,aligntext2)]} {
    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
            }
        }

        lappend ::diff($top,aligns) $::diff($top,align1) $::diff($top,align2)
        lappend ::eskil($top,aligns) $::eskil($top,align1) $::eskil($top,align2)
        enableAlign $top

        NoMarkAlign $top
        return 1
    }
    return 0
}
2281
2282
2283
2284
2285
2286
2287
2288

2289
2290
2291

2292
2293
2294
2295


2296
2297
2298
2299
2300
2301
2302
2286
2287
2288
2289
2290
2291
2292

2293
2294
2295

2296
2297
2298


2299
2300
2301
2302
2303
2304
2305
2306
2307







-
+


-
+


-
-
+
+







    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 ::diff($top,align$other)]} {
    if {![info exists ::eskil($top,align$other)]} {
        set label "Mark line for alignment"
    } else {
        set label "Align with line $::diff($top,align$other) on other side"
        set label "Align with line $::eskil($top,align$other) on other side"
    }

    if {[info exists ::diff($top,aligns)]} {
        foreach {align1 align2} $::diff($top,aligns) {
    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]
            }
2326
2327
2328
2329
2330
2331
2332
2333

2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347







2348
2349
2350
2351
2352

2353
2354
2355


2356
2357
2358
2359
2360
2361
2362
2363
2364
2365


2366
2367
2368
2369


2370
2371
2372
2373

2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384

2385
2386

2387
2388

2389
2390
2391

2392
2393
2394
2395



2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406


2407
2408
2409


2410
2411
2412
2413
2414
2415





2416
2417
2418
2419
2420

2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432

2433
2434
2435
2436
2437
2438
2439

2440
2441
2442

2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455

2456
2457
2458


2459
2460
2461


2462
2463
2464
2465
2466

2467
2468
2469

2470
2471
2472
2473
2474
2475


2476
2477
2478
2479
2480

2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494

2495
2496
2497
2498
2499
2500
2501
2502
2503

2504
2505

2506
2507
2508
2509
2510
2511
2512
2513
2514

2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528

2529
2530

2531
2532
2533
2534
2535
2536
2537
2331
2332
2333
2334
2335
2336
2337

2338
2339
2340
2341
2342
2343
2344
2345







2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356

2357
2358


2359
2360
2361
2362
2363
2364
2365
2366
2367
2368


2369
2370
2371
2372


2373
2374
2375
2376
2377

2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388

2389
2390

2391
2392

2393
2394
2395

2396
2397



2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409


2410
2411
2412


2413
2414
2415





2416
2417
2418
2419
2420
2421
2422
2423
2424

2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436

2437
2438
2439
2440
2441
2442
2443

2444
2445
2446

2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459

2460
2461


2462
2463
2464


2465
2466
2467
2468
2469
2470

2471
2472
2473

2474
2475
2476
2477
2478


2479
2480
2481
2482
2483
2484

2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498

2499
2500
2501
2502
2503
2504
2505
2506
2507

2508
2509

2510
2511
2512
2513
2514
2515
2516
2517
2518

2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532

2533
2534

2535
2536
2537
2538
2539
2540
2541
2542







-
+







-
-
-
-
-
-
-
+
+
+
+
+
+
+




-
+

-
-
+
+








-
-
+
+


-
-
+
+



-
+










-
+

-
+

-
+


-
+

-
-
-
+
+
+









-
-
+
+

-
-
+
+

-
-
-
-
-
+
+
+
+
+




-
+











-
+






-
+


-
+












-
+

-
-
+
+

-
-
+
+




-
+


-
+




-
-
+
+




-
+













-
+








-
+

-
+








-
+













-
+

-
+







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 ::diff($top,alignDrag,state) none
    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 ::diff($top,alignDrag,X) $X
    set ::diff($top,alignDrag,Y) $Y
    set ::diff($top,alignDrag,from) $n
    set ::diff($top,alignDrag,line$n) $line
    set ::diff($top,alignDrag,text$n) $text
    set ::diff($top,alignDrag,line$other) "?"
    set ::diff($top,alignDrag,state) press
    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 {$::diff($top,alignDrag,state) eq "press"} {
    if {$::eskil($top,alignDrag,state) eq "press"} {
        # Have we moved enough to call it dragging?
        set dX [expr {abs($X - $::diff($top,alignDrag,X))}]
        set dY [expr {abs($Y - $::diff($top,alignDrag,Y))}]
        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
            destroy $w
            toplevel $w
            wm overrideredirect $w 1
            label $w.l -borderwidth 1 -relief solid -justify left
            pack $w.l
            set ::diff($top,alignDrag,W) $w
            set ::diff($top,alignDrag,state) "drag"
            set ::eskil($top,alignDrag,W) $w
            set ::eskil($top,alignDrag,state) "drag"
        }
    }
    if {$::diff($top,alignDrag,state) eq "drag"} {
        set w $::diff($top,alignDrag,W)
    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 $::diff($top,alignDrag,from)
        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]
            set data [$w2 get $row.0 $row.end]
            if {![regexp {\d+} $data line]} {
                set ::diff($top,alignDrag,line$other) "?"
                set ::eskil($top,alignDrag,line$other) "?"
            } else {
                set ::diff($top,alignDrag,line$other) $line
                set ::eskil($top,alignDrag,line$other) $line
                set text [$::widgets($top,wDiff$other) get $row.0 $row.end]
                set ::diff($top,alignDrag,text$other) $text
                set ::eskil($top,alignDrag,text$other) $text
            }
        } else {
            set ::diff($top,alignDrag,line$other) "?"
            set ::eskil($top,alignDrag,line$other) "?"
        }
        set txt "Align Left $::diff($top,alignDrag,line1)"
        append txt "\nwith Right $::diff($top,alignDrag,line2)"
        set ::diff($top,alignDrag,shift) $shift
        set txt "Align Left $::eskil($top,alignDrag,line1)"
        append txt "\nwith Right $::eskil($top,alignDrag,line2)"
        set ::eskil($top,alignDrag,shift) $shift
        if {$shift} {
            append txt "\nAnd Redo Diff"
        }
        $w.l configure -text $txt
    }
}

# Button has been released
proc endAlignDrag {top n x y X Y} {
    if {$::diff($top,alignDrag,state) eq "drag"} {
        destroy $::diff($top,alignDrag,W)
    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 {$::diff($top,alignDrag,line1) ne "?" && \
                $::diff($top,alignDrag,line2) ne "?"} {
        if {$::eskil($top,alignDrag,line1) ne "?" && \
                $::eskil($top,alignDrag,line2) ne "?"} {
            NoMarkAlign $top
            markAlign $top 1 $::diff($top,alignDrag,line1) \
                    $::diff($top,alignDrag,text1)
            set marked [markAlign $top 2 $::diff($top,alignDrag,line2) \
                    $::diff($top,alignDrag,text2)]
            if {$::diff($top,alignDrag,shift) && $marked} {
            markAlign $top 1 $::eskil($top,alignDrag,line1) \
                    $::eskil($top,alignDrag,text1)
            set marked [markAlign $top 2 $::eskil($top,alignDrag,line2) \
                    $::eskil($top,alignDrag,text2)]
            if {$::eskil($top,alignDrag,shift) && $marked} {
                redoDiff $top
            }
        }
    }
    set ::diff($top,alignDrag,state) none
    set ::eskil($top,alignDrag,state) none
}

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

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

proc hlSeparate {top n hl} {
    set ::diff($top,separate$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$::diff($top,separate$n)]
        set range [$wl tag ranges hl$::eskil($top,separate$n)]
    }
    set text [$wd get {*}$range]
    set ::diff($top,separatetext$n) $text
    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 ::diff($top,separatelines$n) [list $froml $tol]
    set ::eskil($top,separatelines$n) [list $froml $tol]

    if {[info exists ::diff($top,separate1)] && \
            [info exists ::diff($top,separate2)]} {
    if {[info exists ::eskil($top,separate1)] && \
            [info exists ::eskil($top,separate2)]} {
        if {1} {
            cloneDiff $top [concat $::diff($top,separatelines1) \
                    $::diff($top,separatelines2)]
            cloneDiff $top [concat $::eskil($top,separatelines1) \
                    $::eskil($top,separatelines2)]
        } else {
            set f1 [tmpFile]
            set f2 [tmpFile]
            set ch [open $f1 w]
            puts $ch $::diff($top,separatetext1)
            puts $ch $::eskil($top,separatetext1)
            close $ch
            set ch [open $f2 w]
            puts $ch $::diff($top,separatetext2)
            puts $ch $::eskil($top,separatetext2)
            close $ch

            newDiff $f1 $f2
        }
        unset ::diff($top,separate1)
        unset ::diff($top,separate2)
        unset ::eskil($top,separate1)
        unset ::eskil($top,separate2)
    }
}

proc hlPopup {top n hl X Y x y} {
    if {[info exists ::diff($top,nopopup)] && $::diff($top,nopopup)} return
    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 ::diff($top,separate$other)]} {
    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 ::diff($top,nopopup) 1
    set ::eskil($top,nopopup) 1
    tk_popup .lpm $X $Y
    after idle [list after 1 [list set ::diff($top,nopopup) 0]]
    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 ::diff($top,nopopup)] && $::diff($top,nopopup)} return
    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 ::diff($top,nopopup) 1
    set ::eskil($top,nopopup) 1
    tk_popup .lpm $X $Y
    after idle [list after 1 [list set ::diff($top,nopopup) 0]]
    after idle [list after 1 [list set ::eskil($top,nopopup) 0]]
}

proc nextHighlight {top} {
    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"
2653
2654
2655
2656
2657
2658
2659
2660

2661
2662
2663
2664
2665
2666
2667
2658
2659
2660
2661
2662
2663
2664

2665
2666
2667
2668
2669
2670
2671
2672







-
+







    font configure myfont -size $Pref(fontsize) -family $Pref(fontfamily)
}

# Change color settings
proc applyColor {} {
    global dirdiff Pref

    foreach top $::diff(diffWindows) {
    foreach top $::eskil(diffWindows) {
        if {$top eq ".clipdiff"} continue
        if {$top != ".dirdiff"} {
            foreach item {wLine1 wDiff1 wLine2 wDiff2} {
                if {![info exists ::widgets($top,$item)]} continue
                set w $::widgets($top,$item)

                $w tag configure equal -foreground $Pref(colorequal) \
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732









2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749










2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765

2766
2767
2768

2769
2770
2771
2772
2773
2774
2775
2722
2723
2724
2725
2726
2727
2728









2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744










2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769

2770
2771
2772

2773
2774
2775
2776
2777
2778
2779
2780







-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+







-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+















-
+


-
+







	uplevel \#0 "trace variable $var w \
		{after idle {$w xview end} ;#}"
    }
}

# Fill in default data for a diff window
proc initDiffData {top} {
    set ::diff($top,leftOK) 0
    set ::diff($top,rightOK) 0
    set ::diff($top,mode) ""
    set ::diff($top,printFile) ""
    set ::diff($top,mergeFile) ""
    set ::diff($top,ancestorFile) ""
    set ::diff($top,conflictFile) ""
    set ::diff($top,limitlines) 0
    set ::diff($top,plugin) ""
    set ::eskil($top,leftOK) 0
    set ::eskil($top,rightOK) 0
    set ::eskil($top,mode) ""
    set ::eskil($top,printFile) ""
    set ::eskil($top,mergeFile) ""
    set ::eskil($top,ancestorFile) ""
    set ::eskil($top,conflictFile) ""
    set ::eskil($top,limitlines) 0
    set ::eskil($top,plugin) ""
}

# Create a new diff window and diff two files
proc newDiff {file1 file2 {range {}}} {
    set top [makeDiffWin]
    update

    set ::diff($top,leftDir) [file dirname $file1]
    set ::diff($top,leftFile) $file1
    set ::diff($top,leftLabel) $file1
    set ::diff($top,leftOK) 1
    set ::diff($top,rightDir) [file dirname $file2]
    set ::diff($top,rightFile) $file2
    set ::diff($top,rightLabel) $file2
    set ::diff($top,rightOK) 1
    set ::diff($top,mode) ""
    set ::diff($top,range) $range
    set ::eskil($top,leftDir) [file dirname $file1]
    set ::eskil($top,leftFile) $file1
    set ::eskil($top,leftLabel) $file1
    set ::eskil($top,leftOK) 1
    set ::eskil($top,rightDir) [file dirname $file2]
    set ::eskil($top,rightFile) $file2
    set ::eskil($top,rightLabel) $file2
    set ::eskil($top,rightOK) 1
    set ::eskil($top,mode) ""
    set ::eskil($top,range) $range
    wm deiconify $top
    raise $top
    update
    doDiff $top
    return $top
}


# Create a new diff window equal to another, except for possibly a range
proc cloneDiff {other {range {}}} {
    set top [makeDiffWin]
    update

    foreach item [array names ::diff $other,*] {
        regsub {^[^,]*,} $item {} item
        set ::diff($top,$item) $::diff($other,$item)
        set ::eskil($top,$item) $::eskil($other,$item)
    }
    if {[llength $range] != 0} {
        set ::diff($top,range) $range
        set ::eskil($top,range) $range
    }
    wm deiconify $top
    raise $top
    update
    doDiff $top
}

2789
2790
2791
2792
2793
2794
2795
2796
2797


2798
2799
2800
2801
2802
2803
2804
2794
2795
2796
2797
2798
2799
2800


2801
2802
2803
2804
2805
2806
2807
2808
2809







-
-
+
+







    global Pref tcl_platform

    if {$top != "" && [winfo exists $top] && [winfo toplevel $top] eq $top} {
        # Reuse the old window
        destroy {*}[winfo children $top]
    } else {
        # Locate a free toplevel name
        if {[info exists ::diff(topDiffCnt)]} {
            set t $::diff(topDiffCnt)
        if {[info exists ::eskil(topDiffCnt)]} {
            set t $::eskil(topDiffCnt)
        } else {
            set t 0
        }
        while {[winfo exists .diff$t]} {
            incr t
        }
        set top .diff$t
2980
2981
2982
2983
2984
2985
2986
2987

2988
2989
2990
2991
2992
2993

2994
2995
2996
2997
2998
2999
3000
2985
2986
2987
2988
2989
2990
2991

2992
2993
2994
2995
2996
2997

2998
2999
3000
3001
3002
3003
3004
3005







-
+





-
+







                -command [list makeDocWin $file] -underline 0
    }
    $top.m.help add separator
    $top.m.help add command -label "About" -command makeAboutWin -underline 0

    ttk::label $top.lr1 -text "Rev 1"
    addBalloon $top.lr1 "Revision number for version diff."
    ttk::entryX $top.er1 -width 12 -textvariable diff($top,doptrev1)
    ttk::entryX $top.er1 -width 12 -textvariable ::eskil($top,doptrev1)
    set ::widgets($top,rev1) $top.er1
    bind $top.er1 <Key-Return> [list redoDiff $top]

    ttk::label $top.lr2 -text "Rev 2"
    addBalloon $top.lr2 "Revision number for version diff."
    ttk::entryX $top.er2 -width 12 -textvariable diff($top,doptrev2)
    ttk::entryX $top.er2 -width 12 -textvariable ::eskil($top,doptrev2)
    set ::widgets($top,rev2) $top.er2
    bind $top.er2 <Key-Return> [list redoDiff $top]

    ttk::button $top.bcm -text Commit -command [list revCommit $top] \
            -state disabled -underline 0
    set ::widgets($top,commit) $top.bcm
    ttk::button $top.blg -text Log -command [list revLog $top] \
3010
3011
3012
3013
3014
3015
3016
3017
3018


3019
3020
3021
3022
3023
3024
3025
3015
3016
3017
3018
3019
3020
3021


3022
3023
3024
3025
3026
3027
3028
3029
3030







-
-
+
+







    bind $top <Alt-p> [list findDiff $top -1]
    bind $top <Alt-c> [list revCommit $top]
    bind $top <Alt-l> [list revLog $top]

    catch {font delete myfont}
    font create myfont -family $Pref(fontfamily) -size $Pref(fontsize)

    fileLabel $top.l1 -textvariable diff($top,leftLabel)
    fileLabel $top.l2 -textvariable diff($top,rightLabel)
    fileLabel $top.l1 -textvariable ::eskil($top,leftLabel)
    fileLabel $top.l2 -textvariable ::eskil($top,rightLabel)

    ttk::frame $top.ft1 -borderwidth 2 -relief sunken
    text $top.ft1.tl -height $Pref(lines) -width 5 -wrap none \
            -font myfont -borderwidth 0 -padx 0 -highlightthickness 0 \
            -takefocus 0
    text $top.ft1.tt -height $Pref(lines) -width $Pref(linewidth) -wrap none \
            -xscrollcommand [list $top.sbx1 set] \
3125
3126
3127
3128
3129
3130
3131
3132

3133
3134
3135
3136
3137
3138
3139
3130
3131
3132
3133
3134
3135
3136

3137
3138
3139
3140
3141
3142
3143
3144







-
+







            $top.m.md add separator
        }
        $top.m.md add checkbutton -label "Wrap" -variable wrapstate \
                -onvalue char -offvalue none -command \
                "$top.ft1.tt configure -wrap \$wrapstate ;\
                $top.ft2.tt configure -wrap \$wrapstate"
        $top.m.md add command -label "Date Filter" \
                -command {set ::diff(filter) {^Date}}
                -command {set ::eskil(filter) {^Date}}
        $top.m.md add separator
        $top.m.md add command -label "Reread Source" -underline 0 \
                -command {EskilRereadSource}
        $top.m.md add separator
        $top.m.md add command -label "Redraw Window" \
                -command [list makeDiffWin $top]
        $top.m.md add separator
3308
3309
3310
3311
3312
3313
3314
3315

3316
3317
3318
3319
3320
3321
3322
3313
3314
3315
3316
3317
3318
3319

3320
3321
3322
3323
3324
3325
3326
3327







-
+







        font configure tmpfont -size $TmpPref(fontsize)
    }
}

proc UpdateFontBox {lb} {
    $lb delete 0 end
    foreach {f fixed} $::FontCache {
        if {$fixed || !$::diff(fixedfont)} {
        if {$fixed || !$::eskil(fixedfont)} {
            $lb insert end $f
            if {[string equal -nocase $f $::Pref(fontfamily)]} {
                $lb selection set end
                $lb see end
            }
        }
    }
3347
3348
3349
3350
3351
3352
3353
3354
3355


3356
3357
3358
3359
3360
3361
3362
3352
3353
3354
3355
3356
3357
3358


3359
3360
3361
3362
3363
3364
3365
3366
3367







-
-
+
+







    ttk::labelframe .fo.ls -text "Size" -padding 3
    spinbox .fo.ls.sp -from 1 -to 30 -increment 1 -width 3 -state readonly \
            -textvariable TmpPref(fontsize) -command [list exampleFont $lb]
    pack .fo.ls.sp -fill both -expand 1

    ttk::label .fo.le -text "Example\n0Ooi1Il" -anchor w -font tmpfont \
            -width 1 -justify left
    if {![info exists ::diff(fixedfont)]} {set ::diff(fixedfont) 1}
    ttk::checkbutton .fo.cb -text "Fixed" -variable ::diff(fixedfont) \
    if {![info exists ::eskil(fixedfont)]} {set ::eskil(fixedfont) 1}
    ttk::checkbutton .fo.cb -text "Fixed" -variable ::eskil(fixedfont) \
            -command [list UpdateFontBox $lb]
    ttk::button .fo.bo -text "Ok"    -command "applyFont $lb ; destroy .fo"
    ttk::button .fo.ba -text "Apply" -command "applyFont $lb"
    ttk::button .fo.bc -text "Close" -command "destroy .fo"

    if {![info exists FontCache]} {
        set fam [lsort -dictionary [font families]]
3387
3388
3389
3390
3391
3392
3393
3394

3395
3396
3397
3398
3399



3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412


3413
3414
3415
3416
3417


3418
3419
3420
3421
3422



3423
3424
3425
3426
3427

3428
3429
3430
3431
3432
3433
3434

3435
3436
3437
3438
3439
3440
3441
3442


3443
3444
3445
3446
3447
3448
3449
3450
3451
3452

3453
3454

3455
3456
3457
3458
3459
3460
3461
3462

3463
3464

3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485


3486
3487

3488
3489
3490
3491
3492

3493
3494

3495
3496
3497

3498
3499

3500
3501
3502
3503
3504
3505
3506
3392
3393
3394
3395
3396
3397
3398

3399
3400
3401



3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415


3416
3417
3418
3419
3420


3421
3422
3423
3424



3425
3426
3427
3428
3429
3430
3431

3432
3433
3434
3435
3436
3437
3438

3439
3440
3441
3442
3443
3444
3445


3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456

3457
3458

3459
3460
3461
3462
3463
3464
3465
3466

3467
3468

3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488


3489
3490
3491

3492
3493
3494
3495
3496

3497
3498

3499
3500
3501

3502
3503

3504
3505
3506
3507
3508
3509
3510
3511







-
+


-
-
-
+
+
+











-
-
+
+



-
-
+
+


-
-
-
+
+
+




-
+






-
+






-
-
+
+









-
+

-
+







-
+

-
+



















-
-
+
+

-
+




-
+

-
+


-
+

-
+







}

###########################
# Editor for ::Pref(regsub)
###########################

proc EditPrefRegsubOk {top w} {
    set exa $::diff($top,prefregexa)
    set exa $::eskil($top,prefregexa)

    set result {}
    for {set t 1} {[info exists ::diff($top,prefregexp$t)]} {incr t} {
        set RE $::diff($top,prefregexp$t)
        set Sub $::diff($top,prefregsub$t)
    for {set t 1} {[info exists ::eskil($top,prefregexp$t)]} {incr t} {
        set RE $::eskil($top,prefregexp$t)
        set Sub $::eskil($top,prefregsub$t)
        if {$RE eq ""} continue

        if {[catch {regsub -all -- $RE $exa $Sub _} err]} {
            return
        }
        lappend result $RE $Sub
    }

    set ::Pref(regsub) $result
    destroy $w

    array unset ::diff $top,prefregexp*
    array unset ::diff $top,prefregsub*
    array unset ::eskil $top,prefregexp*
    array unset ::eskil $top,prefregsub*
}

proc EditPrefRegsubUpdate {top args} {
    set exa $::diff($top,prefregexa)
    set exa2 $::diff($top,prefregexa2)
    set exa $::eskil($top,prefregexa)
    set exa2 $::eskil($top,prefregexa2)
    set ok $::widgets($top,prefRegsubOk)

    for {set t 1} {[info exists ::diff($top,prefregexp$t)]} {incr t} {
        set RE $::diff($top,prefregexp$t)
        set Sub $::diff($top,prefregsub$t)
    for {set t 1} {[info exists ::eskil($top,prefregexp$t)]} {incr t} {
        set RE $::eskil($top,prefregexp$t)
        set Sub $::eskil($top,prefregsub$t)

        if {$RE eq ""} continue

        if {[catch {regsub -all -- $RE $exa $Sub result} err]} {
            set ::diff($top,prefregresult) "$t ERROR: $err"
            set ::eskil($top,prefregresult) "$t ERROR: $err"
            $ok configure -state disabled
            return
        } else {
            set exa $result
        }
        if {[catch {regsub -all -- $RE $exa2 $Sub result} err]} {
            set ::diff($top,prefregresult2) "$t ERROR: $err"
            set ::eskil($top,prefregresult2) "$t ERROR: $err"
            $ok configure -state disabled
            return
        } else {
            set exa2 $result
        }
    }
    set ::diff($top,prefregresult2) $exa2
    set ::diff($top,prefregresult) $exa
    set ::eskil($top,prefregresult2) $exa2
    set ::eskil($top,prefregresult) $exa
    $ok configure -state normal
}

proc AddPrefRegsub {top parent} {
    for {set t 1} {[winfo exists $parent.fr$t]} {incr t} {
        #Empty
    }
    set w [ttk::frame $parent.fr$t -borderwidth 2 -relief groove -padding 3]
    ttk::label $w.l1 -text "Regexp:" -anchor "w"
    ttk::entryX $w.e1 -textvariable ::diff($top,prefregexp$t) -width 60
    ttk::entryX $w.e1 -textvariable ::eskil($top,prefregexp$t) -width 60
    ttk::label $w.l2 -text "Subst:" -anchor "w"
    ttk::entryX $w.e2 -textvariable ::diff($top,prefregsub$t)
    ttk::entryX $w.e2 -textvariable ::eskil($top,prefregsub$t)

    grid $w.l1 $w.e1 -sticky we -padx 3 -pady 3
    grid $w.l2 $w.e2 -sticky we -padx 3 -pady 3
    grid columnconfigure $w 1 -weight 1

    pack $w -side "top" -fill x -padx 3 -pady 3

    trace add variable ::diff($top,prefregexp$t) write \
    trace add variable ::eskil($top,prefregexp$t) write \
            [list EditPrefRegsubUpdate $top]
    trace add variable ::diff($top,prefregsub$t) write \
    trace add variable ::eskil($top,prefregsub$t) write \
            [list EditPrefRegsubUpdate $top]
}

# Editor for ::Pref(regsub)
proc EditPrefRegsub {top} {
    set w $top.prefregsub

    if {[winfo exists $w] && [winfo toplevel $w] eq $w} {
        wm deiconify $w
        raise $w
        focus $w
    } else {
        toplevel $w -padx 3 -pady 3
        wm title $w "Preferences: Preprocess"
    }

    ttk::button $w.b -text "Add" -command [list AddPrefRegsub $top $w]

    # Result example part
    if {![info exists ::diff($top,prefregexa)]} {
        set ::diff($top,prefregexa) \
    if {![info exists ::eskil($top,prefregexa)]} {
        set ::eskil($top,prefregexa) \
                "An example TextString FOR_REGSUB /* Comment */"
        set ::diff($top,prefregexa2) \
        set ::eskil($top,prefregexa2) \
                "An example TextString FOR_REGSUB /* Comment */"
    }
    ttk::labelframe $w.res -text "Preprocessing result" -padding 3
    ttk::label $w.res.l3 -text "Example 1:" -anchor "w"
    ttk::entryX $w.res.e3 -textvariable ::diff($top,prefregexa) -width 60
    ttk::entryX $w.res.e3 -textvariable ::eskil($top,prefregexa) -width 60
    ttk::label $w.res.l4 -text "Result 1:" -anchor "w"
    ttk::label $w.res.e4 -textvariable ::diff($top,prefregresult) \
    ttk::label $w.res.e4 -textvariable ::eskil($top,prefregresult) \
            -anchor "w" -width 10
    ttk::label $w.res.l5 -text "Example 2:" -anchor "w"
    ttk::entryX $w.res.e5 -textvariable ::diff($top,prefregexa2)
    ttk::entryX $w.res.e5 -textvariable ::eskil($top,prefregexa2)
    ttk::label $w.res.l6 -text "Result 2:" -anchor "w"
    ttk::label $w.res.e6 -textvariable ::diff($top,prefregresult2) \
    ttk::label $w.res.e6 -textvariable ::eskil($top,prefregresult2) \
            -anchor "w" -width 10

    grid $w.res.l3 $w.res.e3 -sticky we -padx 3 -pady 3
    grid $w.res.l4 $w.res.e4 -sticky we -padx 3 -pady 3
    grid $w.res.l5 $w.res.e5 -sticky we -padx 3 -pady 3
    grid $w.res.l6 $w.res.e6 -sticky we -padx 3 -pady 3
    grid columnconfigure $w.res 1 -weight 1
3521
3522
3523
3524
3525
3526
3527
3528
3529


3530
3531
3532
3533
3534
3535

3536
3537

3538
3539
3540
3541
3542
3543
3544
3526
3527
3528
3529
3530
3531
3532


3533
3534
3535
3536
3537
3538
3539

3540
3541

3542
3543
3544
3545
3546
3547
3548
3549







-
-
+
+





-
+

-
+








    # Fill in existing or an empty line
    if {[llength $::Pref(regsub)] == 0} {
        AddPrefRegsub $top $w
    } else {
        set t 1
        foreach {RE Sub} $::Pref(regsub) {
            set ::diff($top,prefregexp$t) $RE
            set ::diff($top,prefregsub$t) $Sub
            set ::eskil($top,prefregexp$t) $RE
            set ::eskil($top,prefregsub$t) $Sub
            AddPrefRegsub $top $w
            incr t
        }
    }

    trace add variable ::diff($top,prefregexa) write \
    trace add variable ::eskil($top,prefregexa) write \
            [list EditPrefRegsubUpdate $top]
    trace add variable ::diff($top,prefregexa2) write \
    trace add variable ::eskil($top,prefregexa2) write \
            [list EditPrefRegsubUpdate $top]
    EditPrefRegsubUpdate $top
}

proc defaultGuiOptions {} {
    catch {package require griffin}

3997
3998
3999
4000
4001
4002
4003
4004

4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017





4018
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031
4032
4033
4034

4035
4036
4037
4038
4039
4040
4041
4042

4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066




4067
4068
4069
4070
4071
4072



4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090




4091
4092
4093
4094
4095
4096




4097
4098
4099
4100
4101
4102
4103
4104


4105
4106

4107
4108

4109
4110
4111
4112

4113
4114
4115
4116
4117
4118


4119
4120
4121
4122
4123
4124
4125
4002
4003
4004
4005
4006
4007
4008

4009
4010
4011
4012
4013
4014
4015
4016
4017





4018
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038

4039
4040
4041
4042
4043
4044
4045
4046

4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067




4068
4069
4070
4071
4072
4073
4074



4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091




4092
4093
4094
4095
4096
4097




4098
4099
4100
4101
4102
4103
4104
4105
4106
4107


4108
4109
4110

4111
4112

4113
4114
4115
4116

4117
4118
4119
4120
4121


4122
4123
4124
4125
4126
4127
4128
4129
4130







-
+








-
-
-
-
-
+
+
+
+
+
















-
+







-
+




















-
-
-
-
+
+
+
+



-
-
-
+
+
+














-
-
-
-
+
+
+
+


-
-
-
-
+
+
+
+






-
-
+
+

-
+

-
+



-
+




-
-
+
+







    }

    # Ok, we have a normal diff
    set top [makeDiffWin]
    update
    # Copy the previously collected options
    foreach {item val} [array get opts] {
        set ::diff($top,$item) $val
        set ::eskil($top,$item) $val
    }

    # It is preferable to see the end if the rev string is too long
    $::widgets($top,rev1) xview end
    $::widgets($top,rev2) xview end

    if {$doreview} {
        set rev [detectRevSystem "" $preferedRev]
        set ::diff($top,modetype) $rev
        set ::diff($top,mode) "patch"
        set ::diff($top,patchFile) ""
        set ::diff($top,patchData) ""
        set ::diff($top,reviewFiles) $files
        set ::eskil($top,modetype) $rev
        set ::eskil($top,mode) "patch"
        set ::eskil($top,patchFile) ""
        set ::eskil($top,patchData) ""
        set ::eskil($top,reviewFiles) $files
        set ::Pref(toolbar) 1
        after idle [list doDiff $top]
        return $top
    }
    if {$len == 1 || $foreach} {
        set ReturnAfterLoop 0
        set first 1
        foreach file $files {
            if {$first} {
                set first 0
            } else {
                # Create new window for other files
                set top [makeDiffWin]
                update
                # Copy the previously collected options
                foreach {item val} [array get opts] {
                    set ::diff($top,$item) $val
                    set ::eskil($top,$item) $val
                }
                # It is preferable to see the end if the rev string is too long
                $::widgets($top,rev1) xview end
                $::widgets($top,rev2) xview end
            }
            set fullname $file
            set fulldir [file dirname $fullname]
            if {$::diff($top,mode) eq "conflict"} {
            if {$::eskil($top,mode) eq "conflict"} {
                startConflictDiff $top $fullname
                after idle [list doDiff $top]
                set ReturnAfterLoop 1
                continue
            }
            if {!$autobrowse && !$dopatch} {
                # Check for revision control
                set rev [detectRevSystem $fullname $preferedRev]
                if {$rev ne ""} {
                    startRevMode $top $rev $fullname
                    if {$noautodiff} {
                        enableRedo $top
                    } else {
                        after idle [list doDiff $top]
                    }
                    set ReturnAfterLoop 1
                    continue
                }
            }
            # No revision control. Is it a patch file?
            set ::diff($top,leftDir) $fulldir
            set ::diff($top,leftFile) $fullname
            set ::diff($top,leftLabel) $fullname
            set ::diff($top,leftOK) 1
            set ::eskil($top,leftDir) $fulldir
            set ::eskil($top,leftFile) $fullname
            set ::eskil($top,leftLabel) $fullname
            set ::eskil($top,leftOK) 1
            if {$dopatch                                 || \
                    [regexp {\.(diff|patch)$} $fullname] || \
                    $fullname eq "-"} {
                set ::diff($top,mode) "patch"
                set ::diff($top,patchFile) $fullname
                set ::diff($top,patchData) ""
                set ::eskil($top,mode) "patch"
                set ::eskil($top,patchFile) $fullname
                set ::eskil($top,patchData) ""
                set autobrowse 0
                if {$noautodiff} {
                    enableRedo $top
                } else {
                    after idle [list doDiff $top]
                }
                set ReturnAfterLoop 1
                continue
            }
        }
        if {$ReturnAfterLoop} {return $top}
    } elseif {$len >= 2} {
        set fullname [file join [pwd] [lindex $files 0]]
        set fulldir [file dirname $fullname]
        set ::diff($top,leftDir) $fulldir
        set ::diff($top,leftFile) $fullname
        set ::diff($top,leftLabel) $fullname
        set ::diff($top,leftOK) 1
        set ::eskil($top,leftDir) $fulldir
        set ::eskil($top,leftFile) $fullname
        set ::eskil($top,leftLabel) $fullname
        set ::eskil($top,leftOK) 1
        set fullname [file join [pwd] [lindex $files 1]]
        set fulldir [file dirname $fullname]
        set ::diff($top,rightDir) $fulldir
        set ::diff($top,rightFile) $fullname
        set ::diff($top,rightLabel) $fullname
        set ::diff($top,rightOK) 1
        set ::eskil($top,rightDir) $fulldir
        set ::eskil($top,rightFile) $fullname
        set ::eskil($top,rightLabel) $fullname
        set ::eskil($top,rightOK) 1
        if {$noautodiff} {
            enableRedo $top
        } else {
            after idle [list doDiff $top]
        }
    }
    if {$autobrowse && (!$::diff($top,leftOK) || !$::diff($top,rightOK))} {
        if {!$::diff($top,leftOK) && !$::diff($top,rightOK)} {
    if {$autobrowse && (!$::eskil($top,leftOK) || !$::eskil($top,rightOK))} {
        if {!$::eskil($top,leftOK) && !$::eskil($top,rightOK)} {
            openBoth $top 0
        } elseif {!$::diff($top,leftOK)} {
        } elseif {!$::eskil($top,leftOK)} {
            openLeft $top
        } elseif {!$::diff($top,rightOK)} {
        } elseif {!$::eskil($top,rightOK)} {
            openRight $top
        }
        # If we cancel the second file and detect CVS, ask about it.
        if {$::diff($top,leftOK) && !$::diff($top,rightOK) && \
        if {$::eskil($top,leftOK) && !$::eskil($top,rightOK) && \
                [llength [glob -nocomplain [file join $fulldir CVS]]]} {

            if {[tk_messageBox -title Diff -icon question \
                    -message "Do CVS diff?" -type yesno] eq "yes"} {
                set fullname $::diff($top,leftFile)
                set ::diff($top,leftOK) 0
                set fullname $::eskil($top,leftFile)
                set ::eskil($top,leftOK) 0
                startRevMode $top "CVS" $fullname
                after idle [list doDiff $top]
            }
        }
    }
    return $top
}
4221
4222
4223
4224
4225
4226
4227
4228

4229
4230
4231
4232
4233
4234
4235
4226
4227
4228
4229
4230
4231
4232

4233
4234
4235
4236
4237
4238
4239
4240







-
+








    # Store default preferences, to filter saved preferences
    array set ::DefaultPref [array get Pref]

    # Backward compatibilty option
    set Pref(onlydiffs) -1

    set ::diff(filter) ""
    set ::eskil(filter) ""

    if {![info exists ::eskil_testsuite] && [file exists "~/.eskilrc"]} {
        safeLoad "~/.eskilrc" Pref
    }

    if {$Pref(editor) ne ""} {
        set ::util(editor) $Pref(editor)