Index: Changes ================================================================== --- Changes +++ Changes @@ -1,5 +1,39 @@ +Release 2.6.1 + +2011-11-01 + Fixed bug where copy button in directory diff picked the wrong file. + Use a custom Toolbutton layout to get a small toolbutton in directory diff. + +Release 2.6 + +2011-10-27 + Rebuilt rev-detection to handle any dir depth. + Detect .fos as fossil indicator. + +2011-10-15 + Added Show in plugin dialog. Added sort plugin. [FR 3735] + +2011-10-15 + Added procedure editor to debug menu. + +2011-10-15 + Corrected search of plugins to find them in VFS. [Bug 18395] + +2011-10-05 + Respect block parse setting when showing a patch. [Bug 18147] + +2011-10-04 + Fall back to Tcl-dialog when accessing a vfs. [Bug 18371] + +2011-05-09 + Use mouse dragging to set alignment. + +2011-05-09 + Rewritten directory diff to use tablelist. + Redesigned appearance of directory diff. + 2011-04-30 Improved three-way merge. Highlight conflicts and navigate directly between conflicts. Include status for each merge chunk to see the descision made. Added Goto menu in merge window to get fewer toolbar buttons. DELETED Eskil.html Index: Eskil.html ================================================================== --- Eskil.html +++ /dev/null @@ -1,181 +0,0 @@ - - - - Eskil - A graphical frontend to Diff - - - - - BerliOS Developer Logo -

-

Bug tracker and mailing list can be found at the -Project page -

-

Eskil: A graphical frontend to Diff

-Download -Features -Screenshots -Changes -

-

About Eskil

-The first major application I wrote in Tcl/Tk was this tool (somewhere around -1997). Writing it is what made me learn and enjoy Tcl. (I already liked Tk -but still found Tcl annoying at the time.)
-I have used it a lot during the years and lately it has received enough -polish to grant a public release. -

-Pronunciation: The E is short, like in "set", the rest is like "skill". -

-Any feedback, good or bad, can be sent to -<peter dot spjuth at gmail dot com> -

-It is similar but unrelated to TkDiff. - -

Features

- - - -

Download

- -Version 2.5:
-Is available from the -Project page -both as a Starkit and as Starpacks for Windows, Linux and Solaris. -

-The license for the application source is GPL but the bundled packages -are under the same license as Tcl. - -

More information about Starkits -and Starpacks. - -

Screenshots

- - -

-A "zoom" feature for long lines.

-
- -

Changes

-Changes in v2.5 (2011-04-01):
- -Changes in v2.4 (2009-01-08):
- -Changes in v2.3 (2007-12-05):
- -Changes in v2.2 (2007-04-05):
- -
-Changes in v2.1 (2006-06-02):
- -
-Changes in v2.0.7 (2004-12-14):
- -
-Changes in v2.0.6 (2004-10-19):
- -
-Changes in v2.0.5 (2004-08-20):
- -
-Changes in v2.0.4 (2004-06-17):
- -
-Changes in v2.0.3 (2004-05-26):
- -
-Changes in v2.0.2 (2004-05-03):
- -
-Changes in v2.0.1 (2004-02-10):
- -
-First public release v2.0 (2004-01-30):
-
- - - Index: Makefile ================================================================== --- Makefile +++ Makefile @@ -1,10 +1,10 @@ #---------------------------------------------------------------------- # Make file for Eskil #---------------------------------------------------------------------- -VERSION = 26 +VERSION = 261 # Path to the TclKits used for creating StarPacks. TCLKIT = /home/peter/tclkit/v85 TCLKIT_LINUX = $(TCLKIT)/tclkit-8.5.8 TCLKIT_SOLARIS = $(TCLKIT)/tclkit-solaris-sparc @@ -28,11 +28,11 @@ NAGELFAR = nagelfar all: setup SRCFILES = src/eskil.tcl src/clip.tcl src/dirdiff.tcl src/help.tcl src/map.tcl \ - src/print.tcl src/registry.tcl src/rev.tcl \ + src/print.tcl src/registry.tcl src/rev.tcl src/debug.tcl \ src/compare.tcl src/merge.tcl src/printobj.tcl src/plugin.tcl #---------------------------------------------------------------- # Setup symbolic links from the VFS to the real files #---------------------------------------------------------------- @@ -117,25 +117,28 @@ check: eskil_h.syntax @echo Checking... @for i in $(SRCFILES); do $(NAGELFAR) $(NAGELFARFLAGS) eskil_h.syntax $$i ; done test: - @./tests/all.tcl + @./tests/all.tcl $(TESTFLAGS) + +run: + $(TCLKIT_LINUX) eskil.vfs/main.tcl #---------------------------------------------------------------- # Coverage #---------------------------------------------------------------- # Source files for code coverage -COVFILES = src/rev.tcl src/eskil.tcl +COVFILES = eskil.vfs/main.tcl eskil.vfs/src/rev.tcl eskil.vfs/src/eskil.tcl eskil.vfs/src/merge.tcl IFILES = $(COVFILES:.tcl=.tcl_i) LOGFILES = $(COVFILES:.tcl=.tcl_log) MFILES = $(COVFILES:.tcl=.tcl_m) # Instrument source file for code coverage -%.tcl_i: %.tcl - @$(NAGELFAR) -instrument $< +%.tcl_i: %.tcl eskil_h.syntax + @$(NAGELFAR) -instrument eskil_h.syntax $< # Target to prepare for code coverage run. Makes sure log file is clear. instrument: $(IFILES) @rm -f $(LOGFILES) Index: doc/revision.txt ================================================================== --- doc/revision.txt +++ doc/revision.txt @@ -31,11 +31,11 @@
hg diff | eskil -
git diff -p --diff-filter=M master | eskil -
-If the command line option -review is used. Eskil will generate a patch +If the command line option -review is used, Eskil will generate a patch for the current tree and display it as in patch mode. E.g. in a Mercurial directory, these show the same thing:
eskil -preview
hg diff | eskil -
@@ -53,13 +53,20 @@ For Git -r is passed to show, as in "git show :". +
git config --global merge.tool eskil
+
git config --global mergetool.eskil.cmd 'eskil -fine -a $BASE -o $MERGED $REMOTE $LOCAL'
+
git config --global diff.tool eskil
+
git config --global difftool.eskil.cmd 'eskil $LOCAL $REMOTE'
+
    Fossil
For Fossil -r is passed to finfo, as in "fossil finfo -p -r ". + +
fossil settings gmerge-command 'eskil -fine -a "%baseline" "%merge" "%original" -o "%output"' -global
    Mercurial
For Mercurial -r works as in "hg cat -r". DELETED eskil.vfs/COPYING Index: eskil.vfs/COPYING ================================================================== --- eskil.vfs/COPYING +++ /dev/null @@ -1,1 +0,0 @@ -../COPYING DELETED eskil.vfs/doc Index: eskil.vfs/doc ================================================================== --- eskil.vfs/doc +++ /dev/null @@ -1,1 +0,0 @@ -../doc DELETED eskil.vfs/examples Index: eskil.vfs/examples ================================================================== --- eskil.vfs/examples +++ /dev/null @@ -1,1 +0,0 @@ -../examples Index: eskil.vfs/lib/psballoon/psballoon.tcl ================================================================== --- eskil.vfs/lib/psballoon/psballoon.tcl +++ eskil.vfs/lib/psballoon/psballoon.tcl @@ -68,11 +68,14 @@ } proc psballoon::createBalloon {w mx my} { variable balloon if {$balloon(created) == 0} { - set font [$w cget -font] + # Figure out widget's font + if {[catch {set font [$w cget -font]}]} { + set font [ttk::style lookup [winfo class $w] -font] + } set ww [winfo width $w] set ih [winfo height $w] set ix 0 set iy 0 set create 1 DELETED eskil.vfs/plugins Index: eskil.vfs/plugins ================================================================== --- eskil.vfs/plugins +++ /dev/null @@ -1,1 +0,0 @@ -../plugins DELETED eskil.vfs/src/clip.tcl Index: eskil.vfs/src/clip.tcl ================================================================== --- eskil.vfs/src/clip.tcl +++ /dev/null @@ -1,1 +0,0 @@ -../../src/clip.tcl DELETED eskil.vfs/src/compare.tcl Index: eskil.vfs/src/compare.tcl ================================================================== --- eskil.vfs/src/compare.tcl +++ /dev/null @@ -1,1 +0,0 @@ -../../src/compare.tcl DELETED eskil.vfs/src/dirdiff.tcl Index: eskil.vfs/src/dirdiff.tcl ================================================================== --- eskil.vfs/src/dirdiff.tcl +++ /dev/null @@ -1,1 +0,0 @@ -../../src/dirdiff.tcl DELETED eskil.vfs/src/eskil.tcl Index: eskil.vfs/src/eskil.tcl ================================================================== --- eskil.vfs/src/eskil.tcl +++ /dev/null @@ -1,1 +0,0 @@ -../../src/eskil.tcl DELETED eskil.vfs/src/help.tcl Index: eskil.vfs/src/help.tcl ================================================================== --- eskil.vfs/src/help.tcl +++ /dev/null @@ -1,1 +0,0 @@ -../../src/help.tcl DELETED eskil.vfs/src/map.tcl Index: eskil.vfs/src/map.tcl ================================================================== --- eskil.vfs/src/map.tcl +++ /dev/null @@ -1,1 +0,0 @@ -../../src/map.tcl DELETED eskil.vfs/src/merge.tcl Index: eskil.vfs/src/merge.tcl ================================================================== --- eskil.vfs/src/merge.tcl +++ /dev/null @@ -1,1 +0,0 @@ -../../src/merge.tcl DELETED eskil.vfs/src/plugin.tcl Index: eskil.vfs/src/plugin.tcl ================================================================== --- eskil.vfs/src/plugin.tcl +++ /dev/null @@ -1,1 +0,0 @@ -../../src/plugin.tcl DELETED eskil.vfs/src/print.tcl Index: eskil.vfs/src/print.tcl ================================================================== --- eskil.vfs/src/print.tcl +++ /dev/null @@ -1,1 +0,0 @@ -../../src/print.tcl DELETED eskil.vfs/src/printobj.tcl Index: eskil.vfs/src/printobj.tcl ================================================================== --- eskil.vfs/src/printobj.tcl +++ /dev/null @@ -1,1 +0,0 @@ -../../src/printobj.tcl DELETED eskil.vfs/src/registry.tcl Index: eskil.vfs/src/registry.tcl ================================================================== --- eskil.vfs/src/registry.tcl +++ /dev/null @@ -1,1 +0,0 @@ -../../src/registry.tcl DELETED eskil.vfs/src/rev.tcl Index: eskil.vfs/src/rev.tcl ================================================================== --- eskil.vfs/src/rev.tcl +++ /dev/null @@ -1,1 +0,0 @@ -../../src/rev.tcl ADDED htdocs/changes.html Index: htdocs/changes.html ================================================================== --- /dev/null +++ htdocs/changes.html @@ -0,0 +1,136 @@ + + + + Eskil - A graphical frontend to Diff + + + + +

Eskil: A graphical frontend to Diff

+Download +Features +Screenshots +Changes +Fossil Repository +Bug Tracker +

Changes

+Changes in v2.6 (2011-10-30):
+
    +
  • Support commit in Git and Fossil.
  • +
  • Support commit, list of files and revisions with -review.
  • +
  • Added Paste Patch command.
  • +
  • New -pluginlist option. New GUI for plugin selection.
  • +
  • Added three-way merge.
  • +
  • Autodetect line endings in ancestor file to select merge output.
  • +
  • Fully rewritten directory diff with new design.
  • +
  • Set alignment with drag & drop.
  • +
+Changes in v2.5 (2011-04-01):
+
    +
  • Requires Tcl 8.5.
  • +
  • Plugins: Added dump, better documentation.
  • +
  • Dir diff: Added step down.
  • +
  • Dir diff: Redesigned to display less.
  • +
  • Support for Perforce and Fossil.
  • +
  • Allow zero lines of context.
  • +
  • Detect and display annotation in patch view.
  • +
  • Select colors for PDF print. Command line options for PDF.
  • +
  • Removed support for Postscript output.
  • +
  • Support File Drop with TkDnd.
  • +
  • Handle line endings in conflict and merge.
  • +
+Changes in v2.4 (2009-01-08):
+
    +
  • Completely redesigned directory diff.
  • +
  • Added a log viewer in revision mode.
  • +
  • Added color option for unchanged text.
  • +
  • Plugins support.
  • +
  • Support for Subversion, Mercurial and Bazaar.
  • +
  • Support commit in Subversion.
  • +
  • Added -review for displaying all changes in a tree.
  • +
  • Support command line "-" to read a patch from std input.
  • +
+Changes in v2.3 (2007-12-05):
+
    +
  • Added -printpdf command line option.
  • +
  • Fixed line numbering in PDF with big line numbers.
  • +
  • Started on GIT support.
  • +
  • Anything on the command line is checked for a starkit. + Kits are mounted and treated as directories.
  • +
+Changes in v2.2 (2007-04-05):
+
    +
  • Added experimental -nonewline command option.
  • +
  • Added -close command option.
  • +
  • Added experimental PDF print.
  • +
  • Added dirdiff preferences and filters.
  • +
  • Smarter save in merge. [FR 2957]
  • +
  • Added commit button for CVS. [FR 2780]
  • +
  • Bug fixes include: Kits are mounted readonly, + fixed dir diff window menu, + improved patch file parsing.
  • +
+
+Changes in v2.1 (2006-06-02):
+
    +
  • Added -preprocess command line option.
  • +
  • Added -foreach command line option.
  • +
  • Added -context command line option.
  • +
  • Handle starkits as directories in dir diff.
  • +
  • Support relative -r with CVS.
  • +
+
+Changes in v2.0.7 (2004-12-14):
+
    +
  • Added regsub preprocessing option.
  • +
  • Added -prefix command line option.
  • +
  • Improved merge window.
  • +
  • Added ignore keyword option to directory diff.
  • +
+
+Changes in v2.0.6 (2004-10-19):
+
    +
  • Added Ignore Digit option.
  • +
  • Fixed bug in -r for ClearCase.
  • +
  • Edit Mode made more robust.
  • +
+
+Changes in v2.0.5 (2004-08-20):
+
    +
  • Option -r can now be used with ClearCase diff.
  • +
  • Edit Mode allows simple editing in the diff display and saving.
  • +
+
+Changes in v2.0.4 (2004-06-17):
+
    +
  • Added ignore case option.
  • +
  • Improved alignment function.
  • +
+
+Changes in v2.0.3 (2004-05-26):
+
    +
  • Added context options for "Diffs only" mode.
  • +
  • Rewrote how "Separate Diff" and "Align" works. The latter now only happens after a "Redo Diff".
  • +
  • Added scroll map and some more context menu options in Directory Diff.
  • +
+
+Changes in v2.0.2 (2004-05-03):
+
    +
  • Fixed a bug in ClearCase support.
  • +
  • Improved enscipt usage in print command.
  • +
  • Added "mark file" in dirdiff context menu.
  • +
+
+Changes in v2.0.1 (2004-02-10):
+
    +
  • Added preference for width and height.
  • +
  • Added Tools menu to directory diff window.
  • +
  • Made it simpler to save a conflict in the same file.
  • +
+
+First public release v2.0 (2004-01-30):
+
+ + + ADDED htdocs/download.html Index: htdocs/download.html ================================================================== --- /dev/null +++ htdocs/download.html @@ -0,0 +1,34 @@ + + + + Eskil - A graphical frontend to Diff + + + + +

Eskil: A graphical frontend to Diff

+Download +Features +Screenshots +Changes +Fossil Repository +Bug Tracker +

+

Download

+ +Download page is currently being reorganised, not files here yet.
+ +Version 2.5:
+Is available from the +Fossil Repository +both as a Starkit and as Starpacks for Windows, Linux and Solaris. +

+The license for the application source is GPL but the bundled packages +are under the same license as Tcl. + +

More information about Starkits +and Starpacks. + + + ADDED htdocs/eskil1.png Index: htdocs/eskil1.png ================================================================== --- /dev/null +++ htdocs/eskil1.png cannot compute difference between binary files ADDED htdocs/eskil2.png Index: htdocs/eskil2.png ================================================================== --- /dev/null +++ htdocs/eskil2.png cannot compute difference between binary files ADDED htdocs/eskil3.png Index: htdocs/eskil3.png ================================================================== --- /dev/null +++ htdocs/eskil3.png cannot compute difference between binary files ADDED htdocs/index.html Index: htdocs/index.html ================================================================== --- /dev/null +++ htdocs/index.html @@ -0,0 +1,61 @@ + + + + Eskil - A graphical frontend to Diff + + + + +

Eskil: A graphical frontend to Diff

+Download +Features +Screenshots +Changes +Fossil Repository +Bug Tracker +

+

About Eskil

+The first major application I wrote in Tcl/Tk was this tool (somewhere around +1997). Writing it is what made me learn and enjoy Tcl. (I already liked Tk +but still found Tcl annoying at the time.)
+I have used it a lot during the years and lately it has received enough +polish to grant a public release. +

+Pronunciation: The E is short, like in "set", the rest is like "skill". +

+Any feedback, good or bad, can be sent to +<peter dot spjuth at gmail dot com> +

+It is similar but unrelated to TkDiff. + +

Features

+ +
    +
  • Highlights changes within a line.
  • +
  • Matches similar lines within a changed block to better show changed +lines that are adjacent to added/removed lines.
  • +
  • Recursive directory diff.
  • +
  • CVS/RCS/ClearCase/GIT/SVN/BZR/HG/Perforce/Fossil diff.
  • +
  • Conflict merge and three-way merge.
  • +
  • Commit changes directly from Eskil.
  • +
  • View patch, from file or clipboard.
  • +
  • Print to PDF.
  • +
  • "Clip diff"
  • +
  • Plugins for preprocessing files.
  • +
  • Alignment and block diff functions for tricky diffs.
  • +
  • Edit and Save file from diff window.
  • +
  • Starkit browsing.
  • +
+ +

Screenshots

+ + +

+A "zoom" feature for long lines.

+
+

Directory Diff.

+
+ + + ADDED mergetest-fossil.sh Index: mergetest-fossil.sh ================================================================== --- /dev/null +++ mergetest-fossil.sh @@ -0,0 +1,20 @@ +#!/bin/sh +# Build up a merge conflict in fossil +fossil init apa.fossil +mkdir apa_fossil +cd apa_fossil +fossil open ../apa.fossil +fossil settings gmerge-command 'eskil -fine -a "%baseline" "%merge" "%original" -o "%output"' +cp ../tests/ancestor.txt a.txt +fossil add a.txt +fossil commit -m a +fossil branch new b trunk +fossil update b +cp ../tests/right.txt a.txt +fossil commit -m r +fossil update trunk +cp ../tests/left.txt a.txt +fossil commit -m l +fossil update b +#fossil merge trunk +#fossil commit -m "Merge from trunk" ADDED mergetest-git.sh Index: mergetest-git.sh ================================================================== --- /dev/null +++ mergetest-git.sh @@ -0,0 +1,18 @@ +#!/bin/sh +# Build up a merge conflict in git +mkdir apa_git +cd apa_git +git init +cp ../tests/ancestor.txt a.txt +git add a.txt +git commit -m a +git checkout -b b +cp ../tests/right.txt a.txt +git commit -am r +git checkout master +cp ../tests/left.txt a.txt +git commit -am l +git checkout b +#git merge master +#git mergetool +#git commit -am m ADDED plugins/sort.tcl Index: plugins/sort.tcl ================================================================== --- /dev/null +++ plugins/sort.tcl @@ -0,0 +1,30 @@ +##Eskil Plugin : Compare files after sorting lines + +# Example file for a plugin. +# A plugin must start exactly like this one. +# The text after : is the summary you can get at the command line + +# This plugin compares the set of words in files. + +# A plugin must define this procedure to do the job. +# side: left or right +# chi: An input channel for reading the original file. +# cho: An output channel for writing the processed file. +proc PreProcess {side chi cho} { + set data [read $chi] + set endingNewLine 0 + if {[string index $data end] eq "\n"} { + set data [string range $data 0 end-1] + set endingNewLine 1 + } + set lines [split $data \n] + # Allow sort parameters in info + set lines [lsort -dictionary {*}$::Info $lines] + puts -nonewline $cho [join $lines \n] + if {$endingNewLine} { + puts $cho "" + } + # Signal that the file after processing should be used both + # for comparison and for displaying. + return 1 +} Index: src/clip.tcl ================================================================== --- src/clip.tcl +++ src/clip.tcl @@ -31,17 +31,17 @@ proc DoClipDiff {} { set f1 [tmpFile] set f2 [tmpFile] set ch [open $f1 w] - set data1 [$::diff(wClip1) get 1.0 end] + set data1 [$::eskil(wClip1) get 1.0 end] set data1 [ClipClean $data1] puts $ch $data1 close $ch set ch [open $f2 w] - set data2 [$::diff(wClip2) get 1.0 end] + set data2 [$::eskil(wClip2) get 1.0 end] set data2 [ClipClean $data2] puts $ch $data2 close $ch #set line1 [split $data1 \n] @@ -64,11 +64,11 @@ $::widgets($top,wLine2) configure -height 1 } } proc ArmCatch {} { - if {$::diff(armcatch)} { + if {$::eskil(armcatch)} { bind .clipdiff { if {[string equal %W .clipdiff]} { after 50 CatchFromWin } } @@ -76,11 +76,11 @@ bind .clipdiff {} } } proc CatchFromWin {} { - set ::diff(armcatch) 0 + set ::eskil(armcatch) 0 ArmCatch set win [twapi::get_foreground_window] if {$win eq ""} { #puts "No fg window" return @@ -110,22 +110,22 @@ lassign [twapi::get_window_coordinates $win] x1 y1 x2 y2 if {[catch {clipboard get} text]} continue if {$text eq ""} continue lappend capturedData [list $x1 $text] } - $::diff(wClip1) delete 1.0 end - $::diff(wClip2) delete 1.0 end + $::eskil(wClip1) delete 1.0 end + $::eskil(wClip2) delete 1.0 end if {[llength $capturedData] == 0} return # Set it up left-to-right set capturedData [lsort -index 0 -integer $capturedData] if {[llength $capturedData] >= 1} { set text [lindex $capturedData 0 1] - $::diff(wClip1) insert end $text + $::eskil(wClip1) insert end $text } if {[llength $capturedData] >= 2} { set text [lindex $capturedData 1 1] - $::diff(wClip2) insert end $text + $::eskil(wClip2) insert end $text after idle DoClipDiff } } proc makeClipDiffWin {} { @@ -144,12 +144,12 @@ set t1 [Scroll both \ text $top.t1 -width 60 -height 35 -font myfont] set t2 [Scroll both \ text $top.t2 -width 60 -height 35 -font myfont] - set ::diff(wClip1) $t1 - set ::diff(wClip2) $t2 + set ::eskil(wClip1) $t1 + set ::eskil(wClip2) $t2 bind $t1 [list focus $t2] bind $t2 [list focus $t1] ttk::frame $top.f @@ -183,11 +183,11 @@ grid columnconfigure $top.f {0 3 5 8} -weight 1 grid columnconfigure $top.f 8 -minsize [winfo reqwidth $top.f.mf] if {![catch {package require twapi}]} { ttk::checkbutton $top.f.b6 -text "Capture" -command ArmCatch \ - -underline 0 -variable ::diff(armcatch) + -underline 0 -variable ::eskil(armcatch) bind $top [list $top.f.b6 invoke] #raise $top.f.b6 place $top.f.b6 -anchor e -relx 1.0 -rely 0.5 } ADDED src/debug.tcl Index: src/debug.tcl ================================================================== --- /dev/null +++ src/debug.tcl @@ -0,0 +1,134 @@ +# debug.tcl +# +# Helpers for debugging. +# +# +proc testme {x y z} { + puts "In Testme $x $y $z" + list [lindex $x 0] [lindex $y 0] +} + +proc debugTRenter {cmd op} { + set fr [info frame -2] + puts "Line [dict get $fr line] Enter: '$cmd'" +} +proc debugTRenterstep {cmd op} { + set fr [info frame -2] + #puts "$fr" + puts "Line [dict get $fr line] Enterstep: '$cmd'" +} +proc debugTRleave {cmd core res op} { + puts "Leave: '$res'" +} +proc debugTRleavestep {cmd code res op} { + puts "Leavestep: '$res'" +} + +proc debugTR {cmd} { + trace add execution $cmd enter debugTRenter + trace add execution $cmd leave debugTRleave + trace add execution $cmd enterstep debugTRenterstep + trace add execution $cmd leavestep debugTRleavestep +} + +proc DebugMenu {m} { + $m add cascade -label "Debug" -menu $m.debug -underline 0 + menu $m.debug + + if {$::tcl_platform(platform) eq "windows"} { + $m.debug add checkbutton -label "Console" -variable consolestate \ + -onvalue show -offvalue hide -command {console $consolestate} \ + -underline 0 + $m.debug add separator + } + + $m.debug add command -label "Edit" -command ProcEditor -underline 0 + return $m.debug +} + +proc ProcEditorUpdate {a k} { + # Only update on keys generating characters + if {$a eq ""} return + #puts "Key '$a' '$k'" + set p [info procs $::ProcEditor(proc)] + if {$p eq "" && $::ProcEditor(proc) ne ""} { + # Try prefix matching + set p [info procs $::ProcEditor(proc)*] + } + set p [lsort -dictionary $p] + $::ProcEditor(procW) configure -values $p + # Keep the first + set p [lindex $p 0] + + if {$p eq ""} { + set ::ProcEditor(args) "" + $::ProcEditor(bodyW) delete 1.0 end + return + } + if {$p ne $::ProcEditor(proc)} { + after idle [list set ::ProcEditor(proc) $p] + after idle [list $::ProcEditor(procW) selection range insert end] + } + + after idle ProcEditorSelected +} + +proc ProcEditorSelected {} { + set p [info procs $::ProcEditor(proc)] + if {$p eq ""} { + set ::ProcEditor(args) "" + $::ProcEditor(bodyW) delete 1.0 end + return + } + set arglist {} + foreach i [info args $p] { + if {[info default $p $i value]} { + lappend arglist [list $i $value] + } else { + lappend arglist [list $i] + } + } + set body [info body $p] + + set ::ProcEditor(args) $arglist + $::ProcEditor(bodyW) delete 1.0 end + $::ProcEditor(bodyW) insert end $body +} + +proc ProcEditorRedefine {} { + set body [$::ProcEditor(bodyW) get 1.0 end] + set body [string trimright $body] + + ##nagelfar ignore Non constant argument to proc + proc $::ProcEditor(proc) $::ProcEditor(args) $body +} + +proc ProcEditor {} { + set top .proceditor + destroy $top + toplevel $top -padx 3 -pady 3 + ttk::frame $top.bgf + place $top.bgf -x 0 -y 0 -relwidth 1.0 -relheight 1.0 -anchor nw + wm title $top "Proc Editor" + + ttk::label $top.l1 -text "Proc" -anchor w + ttk::combobox $top.e1 -textvariable ::ProcEditor(proc) -values "" + set ::ProcEditor(procW) $top.e1 + bind $top.e1 {ProcEditorUpdate %A %K} + bind $top.e1 <> ProcEditorSelected + #trace add variable ::ProcEditor(proc) write "ProcEditorUpdate" + ttk::label $top.l2 -text "Args" -anchor w + ttk::entry $top.e2 -textvariable ::ProcEditor(args) + set ::ProcEditor(bodyW) [text $top.t -yscrollcommand "$top.sby set"] + ttk::scrollbar $top.sby -orient vertical -command "$top.t yview" + + ttk::button $top.b -text "Redefine" -command ProcEditorRedefine + + grid $top.l1 $top.e1 - -padx 3 -pady 3 -sticky we + grid $top.l2 $top.e2 - -padx 3 -pady 3 -sticky we + grid $top.t - $top.sby -padx 3 -pady 3 -sticky news + grid $top.b - - -padx 3 -pady 3 + + grid columnconfigure $top 1 -weight 1 + grid rowconfigure $top 2 -weight 1 +} Index: src/dirdiff.tcl ================================================================== --- src/dirdiff.tcl +++ src/dirdiff.tcl @@ -20,12 +20,10 @@ # #---------------------------------------------------------------------- # $Revision$ #---------------------------------------------------------------------- -package require tablelist_tile - # Compare file names proc FStrCmp {s1 s2} { # Equality is based on platform's standard # Order is dictionary order @@ -267,11 +265,10 @@ variable IdleQueueArr variable leftMark "" variable rightMark "" variable leftDir "" variable rightDir "" - variable img constructor {args} { variable color install tree using tablelist::tablelist $win.tree -height 20 \ -movablecolumns no -setgrid no -showseparators yes \ @@ -282,21 +279,10 @@ install vsb using scrollbar $win.vsb -orient vertical \ -command "$tree yview" install hsb using scrollbar $win.hsb -orient horizontal \ -command "$tree xview" - # Use demo images from Tablelist - set dir $::eskil(thisDir)/../lib/tablelist/demos - 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]] - # 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 AfterId "" set IdleQueue {} $tree configure -yscrollcommand "$vsb set" -xscrollcommand "$hsb set" @@ -395,11 +381,11 @@ if {$d1 eq $d2} { $tree cellconfigure $topIndex,structure -text $d1 } else { $tree cellconfigure $topIndex,structure -text "$d1 vs $d2" } - $tree cellconfigure $topIndex,structure -image $img(open) + $tree cellconfigure $topIndex,structure -image $::img(open) $tree rowattrib $topIndex type directory $self SetNodeStatus $topIndex empty $tree rowattrib $topIndex leftfull $leftDir $tree rowattrib $topIndex rightfull $rightDir @@ -406,16 +392,16 @@ $self UpdateDirNode $topIndex } method expandCmd {tbl row} { if {[$tree childcount $row] != 0} { - $tree cellconfigure $row,0 -image $img(open) + $tree cellconfigure $row,0 -image $::img(open) } } method collapseCmd {tbl row} { - $tree cellconfigure $row,0 -image $img(clsd) + $tree cellconfigure $row,0 -image $::img(clsd) } # Format a time stamp for display proc FormatDate {date} { clock format $date -format "%Y-%m-%d %H:%M:%S" @@ -776,13 +762,13 @@ $tree rowattrib $id status unknown $tree rowattrib $id leftfull $df1 $tree rowattrib $id rightfull $df2 if {$type ne "directory"} { if {$type eq "link"} { - $tree cellconfigure $id,structure -image $img(link) + $tree cellconfigure $id,structure -image $::img(link) } else { - $tree cellconfigure $id,structure -image $img(file) + $tree cellconfigure $id,structure -image $::img(file) $tree cellconfigure $id,command -window [mymethod addCmdCol] } } if {$type eq "directory"} { @@ -790,11 +776,11 @@ $tree collapse $id #$tree insertchild $id end dummy ;# a dummy $tree cellconfigure $id,structure -text $name/ $self SetNodeStatus $id empty $self AddNodeToIdle $id - $tree cellconfigure $id,structure -image $img(clsd) + $tree cellconfigure $id,structure -image $::img(clsd) } elseif {$size1 == $size2 && \ $time1 == $time2} { $self SetNodeStatus $id equal } elseif {$size1 == ""} { $self SetNodeStatus $id new @@ -806,22 +792,23 @@ } return [$tree rowattrib $id status] } method addCmdCol {tbl row col w} { + set key [$tree getfullkeys $row] set status [$tree rowattrib $row status] set type [$tree rowattrib $row type] set lf [$tree rowattrib $row leftfull] set rf [$tree rowattrib $row rightfull] set bg [$tbl cget -background] ttk::style configure Apa.TFrame -background $bg - ttk::style configure Apa.Toolbutton -background $bg + ttk::style configure Apa.My.Toolbutton -background $bg ttk::frame $w -style Apa.TFrame - ttk::button $w.bl -image $img(left) -style Apa.Toolbutton \ - -command [mymethod CopyFile $row right] - ttk::button $w.br -image $img(right) -style Apa.Toolbutton \ - -command [mymethod CopyFile $row left] + ttk::button $w.bl -image $::img(left) -style Apa.My.Toolbutton \ + -command [mymethod CopyFile $key right] + ttk::button $w.br -image $::img(right) -style Apa.My.Toolbutton \ + -command [mymethod CopyFile $key left] pack $w.bl $w.br -side left -fill y if {$lf eq ""} { $w.br configure -state disabled } if {$rf eq ""} { @@ -921,18 +908,10 @@ constructor {args} { eskilRegisterToplevel $win wm title $win "Eskil Dir" wm protocol $win WM_DELETE_WINDOW [list cleanupAndExit $win] - set dir $::eskil(thisDir)/images - set img(open) [image create photo -file [file join $dir folderopen1.gif]] - set img(up) [image create photo -file [file join $dir arrow_up.gif]] - set h [image height $img(up)] - set w [image width $img(up)] - set img(upup) [image create photo -height $h -width [expr {2 * $w}]] - $img(upup) copy $img(up) -to 0 0 [expr {2 * $w - 1}] [expr {$h - 1}] - install tree using DirCompareTree $win.dc \ -leftdirvariable ::dirdiff(leftDir) \ -rightdirvariable ::dirdiff(rightDir) \ -statusvar [myvar statusVar] @@ -1001,28 +980,33 @@ -command {EskilRereadSource} $win.m.md add separator $win.m.md add command -label "Redraw Window" -command {makeDirDiffWin 1} } - ttk::button $win.bu -image $img(upup) -command [mymethod UpDir] \ + ttk::button $win.bu -image $::img(upup) -command [mymethod UpDir] \ -underline 0 + addBalloon $win.bu "Up in both." bind $win "$win.bu invoke" #catch {font delete myfont} #font create myfont -family $Pref(fontfamily) -size $Pref(fontsize) ttk::entryX $win.e1 -textvariable dirdiff(leftDir) -width 30 - ttk::button $win.bu1 -image $img(up) -command [mymethod UpDir 1] - ttk::button $win.bb1 -image $img(open) \ + ttk::button $win.bu1 -image $::img(up) -command [mymethod UpDir 1] + addBalloon $win.bu1 "Up in left." + ttk::button $win.bb1 -image $::img(browse) \ -command "[list BrowseDir dirdiff(leftDir) $win.e1] [mymethod DoDirCompare]" + addBalloon $win.bb1 "Browse left." after 50 [list after idle [list $win.e1 xview end]] ttk::entryX $win.e2 -textvariable dirdiff(rightDir) -width 30 - ttk::button $win.bu2 -image $img(up) -command [mymethod UpDir 2] - ttk::button $win.bb2 -image $img(open) \ + ttk::button $win.bu2 -image $::img(up) -command [mymethod UpDir 2] + addBalloon $win.bu2 "Up in right." + ttk::button $win.bb2 -image $::img(browse) \ -command "[list BrowseDir dirdiff(rightDir) $win.e2] [mymethod DoDirCompare]" + addBalloon $win.bb2 "Browse right." after 50 [list after idle [list $win.e2 xview end]] bind $win.e1 [mymethod DoDirCompare] bind $win.e2 [mymethod DoDirCompare] ttk::label $win.sl -anchor w -textvariable [myvar statusVar] Index: src/eskil.tcl ================================================================== --- src/eskil.tcl +++ src/eskil.tcl @@ -35,11 +35,11 @@ set ::eskil(argc) $::argc set ::argv {} set ::argc 0 set ::eskil(debug) 0 -set ::eskil(diffver) "Version 2.5+ 2011-05-06" +set ::eskil(diffver) "Version 2.6.1 2011-11-01" set ::eskil(thisScript) [file join [pwd] [info script]] namespace import tcl::mathop::+ namespace import tcl::mathop::- namespace import tcl::mathop::* @@ -50,10 +50,11 @@ 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 { @@ -69,31 +70,19 @@ set tmplink [file normalize [file join $::eskil(thisDir) $tmplink]] set ::eskil(thisDir) [file dirname $tmplink] } # Get all other source files - source $::eskil(thisDir)/clip.tcl - source $::eskil(thisDir)/compare.tcl - source $::eskil(thisDir)/map.tcl - source $::eskil(thisDir)/merge.tcl - source $::eskil(thisDir)/registry.tcl - 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 + InitReSource # 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" @@ -161,10 +150,52 @@ } } } 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]] + }]} 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]] + # Create a double up arrow + set ih [image height $::img(up)] + set iw [image width $::img(up)] + set ::img(upup) [image create photo -height $ih -width [expr {2 * $iw}]] + $::img(upup) copy $::img(up) -to 0 0 [expr {2 * $iw - 1}] [expr {$ih - 1}] + + EskilThemeInit +} + +proc InitReSource {} { + # Get all other source files + source $::eskil(thisDir)/clip.tcl + source $::eskil(thisDir)/compare.tcl + source $::eskil(thisDir)/map.tcl + source $::eskil(thisDir)/merge.tcl + source $::eskil(thisDir)/registry.tcl + 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 + source $::eskil(thisDir)/debug.tcl } # Debug function to be able to reread the source even when wrapped in a kit. proc EskilRereadSource {} { set this $::eskil(thisScript) @@ -188,10 +219,38 @@ } } } puts "Resourcing $this" uplevel \#0 [list source $this] + # Get all other source files + InitReSource +} + +# Initialize Ttk style settings +proc EskilThemeInit {} { + # Import the 'default' theme border element. + catch { ttk::style element create plain.border from default } + catch { ttk::style element create plain.padding from default } + catch { ttk::style element create plain.label from default } + + # Create a new style using the imported element. + ttk::style layout My.Toolbutton { + My.Toolbutton.plain.border -sticky nswe -children { + My.Toolbutton.padding -sticky nswe -children { + My.Toolbutton.label -sticky nswe + } + } + } + # Configure our new style. + ttk::style configure My.Toolbutton {*}[ttk::style configure Toolbutton] \ + -padding {1 1} + ttk::style map My.Toolbutton {*}[ttk::style map Toolbutton] \ + -relief {disabled flat selected sunken pressed sunken active raised} + # Re-do if the user changes theme. + if {[lsearch -exact [bind . <>] EskilThemeInit] == -1} { + bind . <> +EskilThemeInit + } } # This function is called when a toplevel is closed. # If it is the last remaining toplevel, the application quits. # If top = "all" it means quit. @@ -199,24 +258,24 @@ 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 \ @@ -230,11 +289,11 @@ } # 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"} @@ -251,11 +310,11 @@ } 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 @@ -306,20 +365,20 @@ # 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} @@ -450,19 +509,62 @@ return [expr {-($n1 > $n2 ? $n1 : $n2)}] } } # Insert two blocks of lines in the compare windows. -proc insertMatchingBlocks {top block1 block2 line1 line2 details} { +# No extra parsing at all. +proc insertMatchingBlocksNoParse {top block1 block2 line1 line2 details} { global doingLine1 doingLine2 - # A large block may take time. Give a small warning. + set n1 [llength $block1] + set n2 [llength $block2] + # Is this a change block, a delete block or an insert block? + if {$n1 == 0} {set tag2 new2} else {set tag2 change} + if {$n2 == 0} {set tag1 new1} else {set tag1 change} + + foreach line $block1 { + insertLine $top 1 $doingLine1 $line $tag1 + incr doingLine1 + } + foreach line $block2 { + insertLine $top 2 $doingLine2 $line $tag2 + incr doingLine2 + } + if {$n1 <= $n2} { + for {set t $n1} {$t < $n2} {incr t} { + emptyLine $top 1 + } + addChange $top $n2 $tag2 $line1 $n1 $line2 $n2 + nextHighlight $top + } elseif {$n2 < $n1} { + for {set t $n2} {$t < $n1} {incr t} { + emptyLine $top 2 + } + addChange $top $n1 $tag1 $line1 $n1 $line2 $n2 + nextHighlight $top + } +} + +# Insert two blocks of lines in the compare windows. +proc insertMatchingBlocks {top block1 block2 line1 line2 details} { + global doingLine1 doingLine2 Pref + set n1 [llength $block1] set n2 [llength $block2] - if {$n1 * $n2 > 1000} { + + set large [expr {$n1 * $n2 > 1000}] + + if {$n1 == 0 || $n2 == 0 || $Pref(parse) < 2 || \ + ($large && $Pref(parse) < 3)} { + # No extra parsing at all. + insertMatchingBlocksNoParse $top $block1 $block2 $line1 $line2 $details + return + } + + # A large block may take time. Give a small warning. + if {$large} { set ::widgets($top,eqLabel) "!" - #puts "Eskil warning: Analyzing a large block. ($size1 $size2)" update idletasks } # Detect if only newlines has changed within the block, e.g. # when rearranging newlines. @@ -484,29 +586,29 @@ # 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 } } } @@ -609,12 +711,12 @@ 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} @@ -637,11 +739,11 @@ if {$limit >= 0 && $t >= $limit} break } return } - # Is this a change block, a delete block or a insert block? + # Is this a change block, a delete block or an insert block? if {$n1 == 0} {set tag2 new2} else {set tag2 change} if {$n2 == 0} {set tag1 new1} else {set tag1 change} # Display all equal lines before next diff # If only diff is on, only skip a section if the blank @@ -674,12 +776,12 @@ } } 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} { @@ -701,57 +803,29 @@ 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 && \ - ($n1 * $n2 < 1000 || $Pref(parse) == 3)} { - # Full block parsing - set block1 {} - for {set t 0} {$t < $n1} {incr t} { - gets $ch1 apa - lappend block1 $apa - } - set block2 {} - for {set t 0} {$t < $n2} {incr t} { - gets $ch2 apa - lappend block2 $apa - } - insertMatchingBlocks $top $block1 $block2 $line1 $line2 1 - } else { - # No extra parsing at all. - for {set t 0} {$t < $n1} {incr t} { - gets $ch1 apa - insertLine $top 1 $doingLine1 $apa $tag1 - incr doingLine1 - } - for {set t 0} {$t < $n2} {incr t} { - gets $ch2 apa - insertLine $top 2 $doingLine2 $apa $tag2 - incr doingLine2 - } - if {$n1 <= $n2} { - for {set t $n1} {$t < $n2} {incr t} { - emptyLine $top 1 - } - addChange $top $n2 $tag2 $line1 $n1 $line2 $n2 - nextHighlight $top - } elseif {$n2 < $n1} { - for {set t $n2} {$t < $n1} {incr t} { - emptyLine $top 2 - } - addChange $top $n1 $tag1 $line1 $n1 $line2 $n2 - nextHighlight $top - } - } + # Collect blocks + set block1 {} + for {set t 0} {$t < $n1} {incr t} { + gets $ch1 apa + lappend block1 $apa + } + set block2 {} + for {set t 0} {$t < $n2} {incr t} { + gets $ch2 apa + lappend block2 $apa + } + insertMatchingBlocks $top $block1 $block2 $line1 $line2 1 } # Empty return value return } @@ -794,18 +868,18 @@ ##################################### # 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 @@ -813,29 +887,29 @@ # 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 ch1 [open $::diff($top,leftFile) w] - set ch2 [open $::diff($top,rightFile) w] - set ch [open $::diff($top,conflictFile) r] - - set ::diff($top,conflictDiff) {} + set ::eskil($top,leftFile) [tmpFile] + set ::eskil($top,rightFile) [tmpFile] + + set ch1 [open $::eskil($top,leftFile) w] + set ch2 [open $::eskil($top,rightFile) w] + set ch [open $::eskil($top,conflictFile) r] + + set ::eskil($top,conflictDiff) {} set leftLine 1 set rightLine 1 set state both set rightName "" set leftName "" @@ -850,11 +924,11 @@ 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 @@ -871,25 +945,25 @@ 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 @@ -997,24 +1071,24 @@ # 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 "" @@ -1180,34 +1254,34 @@ # 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 @@ -1238,17 +1312,17 @@ } } # 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" } @@ -1257,11 +1331,11 @@ # 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 } @@ -1283,20 +1357,20 @@ 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 @@ -1306,46 +1380,46 @@ # 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) - } else { - set dFile1 $::diff($top,leftFile) - } - if {[info exists ::diff($top,rightFileDiff)]} { - set dFile2 $::diff($top,rightFileDiff) - } else { - set dFile2 $::diff($top,rightFile) + if {[info exists ::eskil($top,leftFileDiff)]} { + set dFile1 $::eskil($top,leftFileDiff) + } else { + set dFile1 $::eskil($top,leftFile) + } + if {[info exists ::eskil($top,rightFileDiff)]} { + set dFile2 $::eskil($top,rightFileDiff) + } else { + 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 @@ -1362,18 +1436,18 @@ 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} { @@ -1389,18 +1463,18 @@ 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 } } @@ -1437,13 +1511,13 @@ # 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" } @@ -1467,20 +1541,20 @@ 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 @@ -1492,11 +1566,11 @@ # 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} { @@ -1512,38 +1586,38 @@ } } # 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) \ - -background {} - $::widgets($top,wLine2) tag configure hl$::diff($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)] - } else { - $::widgets($top,wLine1) tag configure hl$::diff($top,currHighLight) \ - -background yellow - $::widgets($top,wLine2) 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$::eskil($top,currHighLight) \ + -background {} + } + set ::eskil($top,currHighLight) $n + if {$::eskil($top,currHighLight) < 0} { + set ::eskil($top,currHighLight) -1 + } elseif {$::eskil($top,currHighLight) >= [llength $::eskil($top,changes)]} { + set ::eskil($top,currHighLight) [llength $::eskil($top,changes)] + } else { + $::widgets($top,wLine1) tag configure hl$::eskil($top,currHighLight) \ + -background yellow + $::widgets($top,wLine2) tag configure hl$::eskil($top,currHighLight) \ -background yellow } } # Highlight a diff and scroll windows to it. proc showDiff {top num} { 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 @@ -1567,12 +1641,12 @@ # 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) } @@ -1581,11 +1655,11 @@ 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 {} } @@ -1595,22 +1669,22 @@ 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 @@ -1625,15 +1699,15 @@ } } } 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] @@ -1647,63 +1721,63 @@ # 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} { @@ -1859,15 +1933,15 @@ 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 @@ -1934,13 +2008,20 @@ return [file isdirectory $file] } # A wrapper for tk_getOpenFile proc myOpenFile {args} { - # When in tutorial mode, make sure the Tcl file dialog is used + array set opts $args + set isVfs 0 + if {[info exists opts(-initialdir)]} { + if {[string match tclvfs* [file system $opts(-initialdir)]]} { + set isVfs 1 + } + } + # When in a vfs, 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 {$isVfs} { # 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 @@ -1949,82 +2030,82 @@ } 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} { @@ -2035,25 +2116,25 @@ } 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. @@ -2061,39 +2142,39 @@ 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 } } } @@ -2110,26 +2191,26 @@ } 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) "" - } - if {$::diff($top,leftOK) && $::diff($top,rightOK)} { + 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 {$::eskil($top,leftOK) && $::eskil($top,rightOK)} { doDiff $top } } ##################################### @@ -2197,54 +2278,58 @@ } # 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 ::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)]} { - set level 2 - 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 + return 0 } - set level 3 } - lappend ::diff($top,aligns) $::diff($top,align1) $::diff($top,align2) + lappend ::eskil($top,aligns) $::eskil($top,align1) $::eskil($top,align2) enableAlign $top - unset ::diff($top,align1) - unset ::diff($top,align2) - unset ::diff($top,aligntext1) - unset ::diff($top,aligntext2) + NoMarkAlign $top + return 1 } + return 0 } # Called by popup menus over row numbers to add command for alignment. # Returns 1 if nothing was added. proc alignMenu {m top n x y} { @@ -2252,25 +2337,26 @@ set w $::widgets($top,wLine$n) set index [$w index @$x,$y] set row [lindex [split $index "."] 0] set data [$w get $row.0 $row.end] + # Must be a line number if {![regexp {\d+} $data line]} { return 1 } set text [$::widgets($top,wDiff$n) get $row.0 $row.end] set other [expr {$n == 1 ? 2 : 1}] set cmd [list markAlign $top $n $line $text] - if {![info exists ::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" @@ -2281,10 +2367,122 @@ $m add command -label $label -command $cmd return 0 } + +# Set up bindings to allow setting alignment using drag +proc SetupAlignDrag {top left right} { + bind $left [list startAlignDrag $top 1 %x %y %X %Y]\;break + bind $left [list motionAlignDrag $top 1 0 %x %y %X %Y]\;break + bind $left [list motionAlignDrag $top 1 1 %x %y %X %Y]\;break + bind $left [list endAlignDrag $top 1 %x %y %X %Y]\;break + bind $left break + bind $right [list startAlignDrag $top 2 %x %y %X %Y]\;break + bind $right [list motionAlignDrag $top 2 0 %x %y %X %Y]\;break + bind $right [list motionAlignDrag $top 2 1 %x %y %X %Y]\;break + bind $right [list endAlignDrag $top 2 %x %y %X %Y]\;break + bind $right break +} + +# Button has been pressed over line window +proc startAlignDrag {top n x y X Y} { + # Get the row that was clicked + set w $::widgets($top,wLine$n) + set index [$w index @$x,$y] + set row [lindex [split $index "."] 0] + + set data [$w get $row.0 $row.end] + set ::eskil($top,alignDrag,state) none + # Must be a line number + if {![regexp {\d+} $data line]} { + return 1 + } + # Set up information about start of drag + set text [$::widgets($top,wDiff$n) get $row.0 $row.end] + set other [expr {$n == 1 ? 2 : 1}] + set ::eskil($top,alignDrag,X) $X + set ::eskil($top,alignDrag,Y) $Y + set ::eskil($top,alignDrag,from) $n + set ::eskil($top,alignDrag,line$n) $line + set ::eskil($top,alignDrag,text$n) $text + set ::eskil($top,alignDrag,line$other) "?" + set ::eskil($top,alignDrag,state) press +} + +# Mouse moves with button down +proc motionAlignDrag {top n shift x y X Y} { + if {$::eskil($top,alignDrag,state) eq "press"} { + # Have we moved enough to call it dragging? + set dX [expr {abs($X - $::eskil($top,alignDrag,X))}] + set dY [expr {abs($Y - $::eskil($top,alignDrag,Y))}] + if {$dX + $dY > 3} { + # Start a drag action + set w $top.alignDrag + destroy $w + toplevel $w + wm overrideredirect $w 1 + label $w.l -borderwidth 1 -relief solid -justify left + pack $w.l + set ::eskil($top,alignDrag,W) $w + set ::eskil($top,alignDrag,state) "drag" + } + } + if {$::eskil($top,alignDrag,state) eq "drag"} { + set w $::eskil($top,alignDrag,W) + # Move drag label with cursor + wm geometry $w +[expr {$X + 1}]+[expr {$Y + 1}] + + set n $::eskil($top,alignDrag,from) + set other [expr {$n == 1 ? 2 : 1}] + set w2 $::widgets($top,wLine$other) + # Are we over the other line window? + if {[winfo containing $X $Y] eq $w2} { + set x [expr {$X - [winfo rootx $w2]}] + set y [expr {$Y - [winfo rooty $w2]}] + set index [$w2 index @$x,$y] + set row [lindex [split $index "."] 0] + set data [$w2 get $row.0 $row.end] + if {![regexp {\d+} $data line]} { + set ::eskil($top,alignDrag,line$other) "?" + } else { + set ::eskil($top,alignDrag,line$other) $line + set text [$::widgets($top,wDiff$other) get $row.0 $row.end] + set ::eskil($top,alignDrag,text$other) $text + } + } else { + set ::eskil($top,alignDrag,line$other) "?" + } + 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 {$::eskil($top,alignDrag,state) eq "drag"} { + destroy $::eskil($top,alignDrag,W) + # Are both line numbers valid? I.e. is this a full align operation? + if {$::eskil($top,alignDrag,line1) ne "?" && \ + $::eskil($top,alignDrag,line2) ne "?"} { + NoMarkAlign $top + markAlign $top 1 $::eskil($top,alignDrag,line1) \ + $::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 ::eskil($top,alignDrag,state) none +} ################### # Diff highlighting ################### @@ -2291,21 +2489,21 @@ 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 @@ -2314,36 +2512,36 @@ # 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 @@ -2353,31 +2551,31 @@ .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] @@ -2387,13 +2585,13 @@ # 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} { @@ -2519,11 +2717,11 @@ # 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) @@ -2583,36 +2781,36 @@ } } # 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 @@ -2622,16 +2820,16 @@ # 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,*] { + foreach item [array names ::eskil $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 @@ -2655,12 +2853,12 @@ 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 @@ -2846,17 +3044,17 @@ $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 [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 [list redoDiff $top] ttk::button $top.bcm -text Commit -command [list revCommit $top] \ -state disabled -underline 0 @@ -2876,12 +3074,12 @@ bind $top [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 @@ -2952,10 +3150,11 @@ } foreach w [list $top.ft1.tl $top.ft2.tl] { $w tag configure align -underline 1 bind $w "rowPopup %W %X %Y %x %y" } + SetupAlignDrag $top $top.ft1.tl $top.ft2.tl grid $top.l1 $top.le - $top.l2 -row 1 -sticky news grid $top.ft1 $map $top.sby $top.ft2 -row 2 -sticky news grid $top.sbx1 $top.ls - $top.sbx2 -row 3 -sticky news grid columnconfigure $top {0 3} -weight 1 @@ -2977,37 +3176,30 @@ $top.er2 $top.lr2 $top.er1 $top.lr1 \ -in $top.f -side right -padx 3 pack $top.bfn $top.bfp $top.bcm -ipadx 15 if {$::eskil(debug) == 1} { - $top.m add cascade -label "Debug" -menu $top.m.md -underline 0 - menu $top.m.md - if {$tcl_platform(platform) eq "windows"} { - $top.m.md add checkbutton -label "Console" -variable consolestate \ - -onvalue show -offvalue hide \ - -command {console $consolestate} - $top.m.md add separator - } - $top.m.md add checkbutton -label "Wrap" -variable wrapstate \ + set dMenu [DebugMenu $top.m] + $dMenu 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}} - $top.m.md add separator - $top.m.md add command -label "Reread Source" -underline 0 \ + $dMenu add command -label "Date Filter" \ + -command {set ::eskil(filter) {^Date}} + $dMenu add separator + $dMenu add command -label "Reread Source" -underline 0 \ -command {EskilRereadSource} - $top.m.md add separator - $top.m.md add command -label "Redraw Window" \ + $dMenu add separator + $dMenu add command -label "Redraw Window" \ -command [list makeDiffWin $top] - $top.m.md add separator - $top.m.md add command -label "Normal Cursor" \ + $dMenu add separator + $dMenu add command -label "Normal Cursor" \ -command [list normalCursor $top] - $top.m.md add separator - $top.m.md add command -label "Evalstats" -command {evalstats} - $top.m.md add command -label "_stats" -command {parray _stats} - $top.m.md add command -label "Nuisance" -command [list makeNuisance \ + $dMenu add separator + $dMenu add command -label "Evalstats" -command {evalstats} + $dMenu add command -label "_stats" -command {parray _stats} + $dMenu add command -label "Nuisance" -command [list makeNuisance \ $top "It looks like you are trying out the debug menu."] } initDiffData $top return $top @@ -3173,11 +3365,11 @@ } 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 } @@ -3212,12 +3404,12 @@ -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" @@ -3252,16 +3444,16 @@ ########################### # 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 } @@ -3269,64 +3461,64 @@ } 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} { @@ -3342,26 +3534,26 @@ } 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 @@ -3386,20 +3578,20 @@ 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 {} { @@ -3862,24 +4054,24 @@ # 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} { @@ -3892,19 +4084,19 @@ # 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 } @@ -3921,20 +4113,20 @@ 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] @@ -3945,42 +4137,42 @@ } 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] } } } @@ -4086,11 +4278,11 @@ 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 } Index: src/help.tcl ================================================================== --- src/help.tcl +++ src/help.tcl @@ -216,11 +216,10 @@ tk_messageBox -icon error -title "Eskil Error" -message \ "Could not locate examples directory." \ -type ok return } - #set ::diff(tutorial) 1 # Start up a dirdiff in the examples directory set ::dirdiff(leftDir) [file join [pwd] dir1] set ::dirdiff(rightDir) [file join [pwd] dir2] makeDirDiffWin Index: src/map.tcl ================================================================== --- src/map.tcl +++ src/map.tcl @@ -42,51 +42,51 @@ return $w } proc clearMap {top} { - set ::diff($top,changes) {} - set ::diff($top,mapMax) 0 + set ::eskil($top,changes) {} + set ::eskil($top,mapMax) 0 drawMap $top -1 } proc addChange {top n tag line1 n1 line2 n2} { if {$tag ne ""} { - lappend ::diff($top,changes) [list $::diff($top,mapMax) $n \ + lappend ::eskil($top,changes) [list $::eskil($top,mapMax) $n \ $tag $line1 $n1 $line2 $n2] } - incr ::diff($top,mapMax) $n + incr ::eskil($top,mapMax) $n } proc addMapLines {top n} { - incr ::diff($top,mapMax) $n + incr ::eskil($top,mapMax) $n } proc drawMap {top newh} { global Pref set oldh [map$top cget -height] if {$oldh == $newh} return map$top blank - if {![info exists ::diff($top,changes)] || \ - [llength $::diff($top,changes)] == 0} return + if {![info exists ::eskil($top,changes)] || \ + [llength $::eskil($top,changes)] == 0} return set w [winfo width $top.c_map] set h [winfo height $top.c_map] set x2 [expr {$w - ($Pref(wideMap) ? 5 : 1)}] if {$x2 < 0} { set x2 0 } map$top configure -width $w -height $h incr h -1 set y0 0 - foreach change $::diff($top,changes) { + foreach change $::eskil($top,changes) { lassign $change start length type - set y1 [expr {$start * $h / $::diff($top,mapMax) + 1}] + set y1 [expr {$start * $h / $::eskil($top,mapMax) + 1}] if {!$y0} { set y0 $y1 } ;# Record first occurance if {$y1 < 1} {set y1 1} if {$y1 > $h} {set y1 $h} - set y2 [expr {($start + $length) * $h / $::diff($top,mapMax) + 1}] + set y2 [expr {($start + $length) * $h / $::eskil($top,mapMax) + 1}] if {$y2 < 1} {set y2 1} if {$y2 <= $y1} {set y2 [expr {$y1 + 1}]} if {$y2 > $h} {set y2 $h} incr y2 map$top put $Pref(color$type) -to 1 $y1 $x2 $y2 Index: src/merge.tcl ================================================================== --- src/merge.tcl +++ src/merge.tcl @@ -20,28 +20,28 @@ # #---------------------------------------------------------------------- # Get all data from the files to merge proc collectMergeData {top} { - global diff - - set diff($top,leftMergeData) {} - set diff($top,rightMergeData) {} - set diff($top,mergeSelection,AnyConflict) 0 - - if {![info exists ::diff($top,changes)]} { - set ::diff($top,changes) {} + global eskil + + set eskil($top,leftMergeData) {} + set eskil($top,rightMergeData) {} + set eskil($top,mergeSelection,AnyConflict) 0 + + if {![info exists eskil($top,changes)]} { + set eskil($top,changes) {} } prepareFiles $top - set ch1 [open $::diff($top,leftFile) r] - set ch2 [open $::diff($top,rightFile) r] + set ch1 [open $eskil($top,leftFile) r] + set ch2 [open $eskil($top,rightFile) r] set doingLine1 1 set doingLine2 1 set changeNo 0 - foreach change $::diff($top,changes) { + foreach change $eskil($top,changes) { lassign $change start length type line1 n1 line2 n2 set data1 {} set data2 {} while {$doingLine1 < $line1} { gets $ch1 apa @@ -51,12 +51,12 @@ while {$doingLine2 < $line2} { gets $ch2 apa append data2 $apa\n incr doingLine2 } - lappend diff($top,leftMergeData) $data1 - lappend diff($top,rightMergeData) $data2 + lappend eskil($top,leftMergeData) $data1 + lappend eskil($top,rightMergeData) $data2 set data1 {} set data2 {} for {set t 0} {$t < $n1} {incr t} { gets $ch1 apa @@ -66,18 +66,18 @@ for {set t 0} {$t < $n2} {incr t} { gets $ch2 apa append data2 $apa\n incr doingLine2 } - lappend diff($top,leftMergeData) $data1 - lappend diff($top,rightMergeData) $data2 - set diff($top,mergeSelection,$changeNo) \ + lappend eskil($top,leftMergeData) $data1 + lappend eskil($top,rightMergeData) $data2 + set eskil($top,mergeSelection,$changeNo) \ [WhichSide $top $line1 $n1 $line2 $n2 conflict comment] - set diff($top,mergeSelection,Conflict,$changeNo) $conflict - set diff($top,mergeSelection,Comment,$changeNo) $comment + set eskil($top,mergeSelection,Conflict,$changeNo) $conflict + set eskil($top,mergeSelection,Comment,$changeNo) $comment if {$conflict} { - set diff($top,mergeSelection,AnyConflict) 1 + set eskil($top,mergeSelection,AnyConflict) 1 } incr changeNo } set data1 {} set data2 {} @@ -87,43 +87,43 @@ } while {[gets $ch2 apa] != -1} { append data2 $apa\n incr doingLine2 } - lappend diff($top,leftMergeData) $data1 - lappend diff($top,rightMergeData) $data2 + lappend eskil($top,leftMergeData) $data1 + lappend eskil($top,rightMergeData) $data2 close $ch1 close $ch2 cleanupFiles $top } # Fill up the merge window with the initial version of merged files. proc fillMergeWindow {top} { - global diff + global eskil set w $top.merge.t $w delete 1.0 end set marks {} set t 0 set firstConflict -1 - foreach {commLeft diffLeft} $diff($top,leftMergeData) \ - {commRight diffRight} $diff($top,rightMergeData) { + foreach {commLeft diffLeft} $eskil($top,leftMergeData) \ + {commRight diffRight} $eskil($top,rightMergeData) { $w insert end $commRight - if {![info exists diff($top,mergeSelection,$t)]} continue + if {![info exists eskil($top,mergeSelection,$t)]} continue $w mark set merges$t insert $w mark gravity merges$t left - switch $diff($top,mergeSelection,$t) { + switch $eskil($top,mergeSelection,$t) { 1 { $w insert end $diffLeft merge$t } 2 { $w insert end $diffRight merge$t } 12 { $w insert end $diffLeft merge$t $w insert end $diffRight merge$t } 21 { $w insert end $diffRight merge$t $w insert end $diffLeft merge$t } } - if {$diff($top,mergeSelection,Conflict,$t)} { + if {$eskil($top,mergeSelection,Conflict,$t)} { $w tag configure merge$t -background grey if {$firstConflict == -1} { set firstConflict $t } } @@ -142,99 +142,100 @@ set showFirst 0 if {$firstConflict != -1} { set showFirst $firstConflict } - set diff($top,curMerge) $showFirst - set diff($top,curMergeSel) $diff($top,mergeSelection,$showFirst) + set eskil($top,curMerge) $showFirst + set eskil($top,curMergeSel) $eskil($top,mergeSelection,$showFirst) $w tag configure merge$showFirst -foreground red showDiff $top $showFirst update # If there is any diff, show the first if {$t > 0} { seeText $w merges$showFirst mergee$showFirst # Show status for first chunk - set diff($top,mergeStatus) \ - $diff($top,mergeSelection,Comment,$showFirst) - } -} - -# Move to and highlight another diff. -proc nextMerge {top delta} { - global diff - - set w $top.merge.t - $w tag configure merge$diff($top,curMerge) -foreground "" - - set last [expr {[llength $diff($top,leftMergeData)] / 2 - 1}] - - if {$delta == -1000} { - # Search backward for conflict - for {set t [expr {$diff($top,curMerge) - 1}]} {$t >= 0} {incr t -1} { - if {$diff($top,mergeSelection,Conflict,$t)} { - set delta [expr {$t - $diff($top,curMerge)}] - break - } - } - } elseif {$delta == 1000} { - # Search forward for conflict - for {set t [expr {$diff($top,curMerge) + 1}]} {$t <= $last} {incr t} { - if {$diff($top,mergeSelection,Conflict,$t)} { - set delta [expr {$t - $diff($top,curMerge)}] - break - } - } - } - - set diff($top,curMerge) [expr {$diff($top,curMerge) + $delta}] - if {$diff($top,curMerge) < 0} {set diff($top,curMerge) 0} - if {$diff($top,curMerge) > $last} { - set diff($top,curMerge) $last - } - set diff($top,curMergeSel) $diff($top,mergeSelection,$diff($top,curMerge)) - $w tag configure merge$diff($top,curMerge) -foreground red - showDiff $top $diff($top,curMerge) - seeText $w merges$diff($top,curMerge) mergee$diff($top,curMerge) - - set diff($top,mergeStatus) \ - $diff($top,mergeSelection,Comment,$diff($top,curMerge)) -} - -# Select a merge setting for all diffs. -proc selectMergeAll {top new} { - global diff - set end [expr {[llength $diff($top,leftMergeData)] / 2}] - for {set t 0} {$t < $end} {incr t} { - selectMerge2 $top $t $new - } - set diff($top,curMergeSel) $new - set w $top.merge.t - seeText $w merges$diff($top,curMerge) mergee$diff($top,curMerge) -} - -# Change merge setting fo current diff. -proc selectMerge {top} { - global diff - - set w $top.merge.t - selectMerge2 $top $diff($top,curMerge) $diff($top,curMergeSel) - seeText $w merges$diff($top,curMerge) mergee$diff($top,curMerge) -} - -# Change merge setting for a diff. -proc selectMerge2 {top no new} { - global diff - - set w $top.merge.t - # Delete current string - $w delete merges$no mergee$no - - set diff($top,mergeSelection,$no) $new - - set i [expr {$no * 2 + 1}] - set diffLeft [lindex $diff($top,leftMergeData) $i] - set diffRight [lindex $diff($top,rightMergeData) $i] + set eskil($top,mergeStatus) \ + $eskil($top,mergeSelection,Comment,$showFirst) + } +} + +# Move to and highlight another diff. +proc nextMerge {top delta} { + global eskil + + set w $top.merge.t + $w tag configure merge$eskil($top,curMerge) -foreground "" + + set last [expr {[llength $eskil($top,leftMergeData)] / 2 - 1}] + + if {$delta == -1000} { + # Search backward for conflict + for {set t [expr {$eskil($top,curMerge) - 1}]} {$t >= 0} {incr t -1} { + if {$eskil($top,mergeSelection,Conflict,$t)} { + set delta [expr {$t - $eskil($top,curMerge)}] + break + } + } + } elseif {$delta == 1000} { + # Search forward for conflict + for {set t [expr {$eskil($top,curMerge) + 1}]} {$t <= $last} {incr t} { + if {$eskil($top,mergeSelection,Conflict,$t)} { + set delta [expr {$t - $eskil($top,curMerge)}] + break + } + } + } + + set eskil($top,curMerge) [expr {$eskil($top,curMerge) + $delta}] + if {$eskil($top,curMerge) < 0} {set eskil($top,curMerge) 0} + if {$eskil($top,curMerge) > $last} { + set eskil($top,curMerge) $last + } + set eskil($top,curMergeSel) $eskil($top,mergeSelection,$eskil($top,curMerge)) + $w tag configure merge$eskil($top,curMerge) -foreground red + showDiff $top $eskil($top,curMerge) + seeText $w merges$eskil($top,curMerge) mergee$eskil($top,curMerge) + + set eskil($top,mergeStatus) \ + $eskil($top,mergeSelection,Comment,$eskil($top,curMerge)) +} + +# Select a merge setting for all diffs. +proc selectMergeAll {top new} { + global eskil + + set end [expr {[llength $eskil($top,leftMergeData)] / 2}] + for {set t 0} {$t < $end} {incr t} { + selectMerge2 $top $t $new + } + set eskil($top,curMergeSel) $new + set w $top.merge.t + seeText $w merges$eskil($top,curMerge) mergee$eskil($top,curMerge) +} + +# Change merge setting fo current diff. +proc selectMerge {top} { + global eskil + + set w $top.merge.t + selectMerge2 $top $eskil($top,curMerge) $eskil($top,curMergeSel) + seeText $w merges$eskil($top,curMerge) mergee$eskil($top,curMerge) +} + +# Change merge setting for a diff. +proc selectMerge2 {top no new} { + global eskil + + set w $top.merge.t + # Delete current string + $w delete merges$no mergee$no + + set eskil($top,mergeSelection,$no) $new + + set i [expr {$no * 2 + 1}] + set diffLeft [lindex $eskil($top,leftMergeData) $i] + set diffRight [lindex $eskil($top,rightMergeData) $i] # Temporarily switch surrounding marks # Two steps are enough since there can't be consecutive empty areas # The one before and/or the one after the one being switch might # be empty. @@ -241,17 +242,17 @@ $w mark gravity mergee[expr {$no - 2}] left $w mark gravity mergee[expr {$no - 1}] left $w mark gravity merges[expr {$no + 1}] right $w mark gravity merges[expr {$no + 2}] right - if {$diff($top,mergeSelection,$no) == 12} { + if {$eskil($top,mergeSelection,$no) == 12} { $w insert merges$no $diffLeft$diffRight merge$no - } elseif {$diff($top,mergeSelection,$no) == 21} { + } elseif {$eskil($top,mergeSelection,$no) == 21} { $w insert merges$no $diffRight$diffLeft merge$no - } elseif {$diff($top,mergeSelection,$no) == 1} { + } elseif {$eskil($top,mergeSelection,$no) == 1} { $w insert merges$no $diffLeft merge$no - } elseif {$diff($top,mergeSelection,$no) == 2} { + } elseif {$eskil($top,mergeSelection,$no) == 2} { $w insert merges$no $diffRight merge$no } # Switch back surrounding marks $w mark gravity mergee[expr {$no - 2}] right $w mark gravity mergee[expr {$no - 1}] right @@ -261,113 +262,113 @@ # Save the merge result. proc saveMerge {top} { set w $top.merge.t - if {$::diff($top,mergeFile) eq "" && $::diff($top,mode) eq "conflict"} { + if {$::eskil($top,mergeFile) eq "" && $::eskil($top,mode) eq "conflict"} { set apa [tk_messageBox -parent $top.merge -icon question \ -title "Save merge file" -type yesno -message \ "Do you want to overwrite the original conflict file?"] if {$apa == "yes"} { - set ::diff($top,mergeFile) $::diff($top,conflictFile) + set ::eskil($top,mergeFile) $::eskil($top,conflictFile) } } - if {$::diff($top,mergeFile) eq ""} { + if {$::eskil($top,mergeFile) eq ""} { # Ask user which file set buttons {} set text "Overwrite file or Browse?" - if {[file exists $::diff($top,leftFile)] && \ - $::diff($top,leftFile) eq $::diff($top,leftLabel)} { + if {[file exists $::eskil($top,leftFile)] && \ + $::eskil($top,leftFile) eq $::eskil($top,leftLabel)} { lappend buttons Left - append text "\nLeft: $::diff($top,leftFile)" + append text "\nLeft: $::eskil($top,leftFile)" } - if {[file exists $::diff($top,rightFile)] && \ - $::diff($top,rightFile) eq $::diff($top,rightLabel)} { + if {[file exists $::eskil($top,rightFile)] && \ + $::eskil($top,rightFile) eq $::eskil($top,rightLabel)} { lappend buttons Right - append text "\nRight: $::diff($top,rightFile)" + append text "\nRight: $::eskil($top,rightFile)" } lappend buttons Browse Cancel if {[llength $buttons] > 2} { set apa [tk_dialog .savemerge "Save merge file" \ $text \ questhead -1 {*}$buttons] if {$apa < 0} return set apa [lindex $buttons $apa] if {$apa eq "Left"} { - set ::diff($top,mergeFile) $::diff($top,leftFile) + set ::eskil($top,mergeFile) $::eskil($top,leftFile) } elseif {$apa eq "Right"} { - set ::diff($top,mergeFile) $::diff($top,rightFile) + set ::eskil($top,mergeFile) $::eskil($top,rightFile) } elseif {$apa eq "Cancel"} { return } } - if {$::diff($top,mergeFile) eq ""} { + if {$::eskil($top,mergeFile) eq ""} { # Browse - if {[info exists ::diff($top,rightDir)]} { - set initDir $::diff($top,rightDir) - } elseif {[info exists ::diff($top,leftDir)]} { - set initDir $::diff($top,leftDir) + if {[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 [tk_getSaveFile -title "Save merge file" -initialdir $initDir \ -parent $top.merge] if {$apa eq ""} return - set ::diff($top,mergeFile) $apa + set ::eskil($top,mergeFile) $apa } } - set ch [open $::diff($top,mergeFile) "w"] - fconfigure $ch -translation $::diff($top,mergetranslation) + set ch [open $::eskil($top,mergeFile) "w"] + fconfigure $ch -translation $::eskil($top,mergetranslation) puts -nonewline $ch [$w get 1.0 end-1char] close $ch # Detect if this is a GIT merge, and possibly add it to the index # after save (i.e. git add file) - if {[detectRevSystem $::diff($top,mergeFile)] eq "GIT"} { + if {[detectRevSystem $::eskil($top,mergeFile)] eq "GIT"} { set apa [tk_messageBox -parent $top.merge -icon info -type yesno \ -title "Diff" \ - -message "Saved merge to file $::diff($top,mergeFile).\nAdd\ + -message "Saved merge to file $::eskil($top,mergeFile).\nAdd\ it to GIT index?"] if {$apa eq "yes"} { - eskil::rev::GIT::add $::diff($top,mergeFile) + eskil::rev::GIT::add $::eskil($top,mergeFile) } } else { tk_messageBox -parent $top.merge -icon info -type ok -title "Diff" \ - -message "Saved merge to file $::diff($top,mergeFile)." + -message "Saved merge to file $::eskil($top,mergeFile)." } } # Close merge window and clean up. proc closeMerge {top} { - global diff + global eskil destroy $top.merge - set diff($top,leftMergeData) {} - set diff($top,rightMergeData) {} - array unset diff $top,mergeSelection,* + set eskil($top,leftMergeData) {} + set eskil($top,rightMergeData) {} + array unset eskil $top,mergeSelection,* } # Create a window to display merge result. proc makeMergeWin {top} { collectMergeData $top - if {![info exists ::diff($top,mergetranslation)]} { + if {![info exists ::eskil($top,mergetranslation)]} { if {$::tcl_platform(platform) eq "windows"} { - set ::diff($top,mergetranslation) crlf + set ::eskil($top,mergetranslation) crlf } else { - set ::diff($top,mergetranslation) lf + set ::eskil($top,mergetranslation) lf } } set w $top.merge if {![winfo exists $w]} { toplevel $w } else { destroy {*}[winfo children $w] } - set anyC $::diff($top,mergeSelection,AnyConflict) + set anyC $::eskil($top,mergeSelection,AnyConflict) wm title $w "Merge result: [TitleTail $top]" menu $w.m $w configure -menu $w.m @@ -378,17 +379,17 @@ $w.m.mf add command -label "Close" -underline 0 -command "closeMerge $top" $w.m add cascade -label "Select" -underline 0 -menu $w.m.ms menu $w.m.ms $w.m.ms add radiobutton -label "Left+Right" -value 12 \ - -variable diff($top,curMergeSel) -command "selectMerge $top" + -variable ::eskil($top,curMergeSel) -command "selectMerge $top" $w.m.ms add radiobutton -label "Left" -underline 0 -value 1 \ - -variable diff($top,curMergeSel) -command "selectMerge $top" + -variable ::eskil($top,curMergeSel) -command "selectMerge $top" $w.m.ms add radiobutton -label "Right" -underline 0 -value 2 \ - -variable diff($top,curMergeSel) -command "selectMerge $top" + -variable ::eskil($top,curMergeSel) -command "selectMerge $top" $w.m.ms add radiobutton -label "Right+Left" -value 21 \ - -variable diff($top,curMergeSel) -command "selectMerge $top" + -variable ::eskil($top,curMergeSel) -command "selectMerge $top" $w.m.ms add separator $w.m.ms add command -label "All Left" -command "selectMergeAll $top 1" $w.m.ms add command -label "All Right" -command "selectMergeAll $top 2" $w.m add cascade -label "Goto" -underline 0 -menu $w.m.mg @@ -404,34 +405,34 @@ } $w.m add cascade -label "Config" -underline 0 -menu $w.m.mc menu $w.m.mc - $w.m.mc add radiobutton -label "Line end LF" -value lf -variable diff($top,mergetranslation) - $w.m.mc add radiobutton -label "Line end CRLF" -value crlf -variable diff($top,mergetranslation) - if {$::diff($top,mode) eq "conflict"} { + $w.m.mc add radiobutton -label "Line end LF" -value lf -variable ::eskil($top,mergetranslation) + $w.m.mc add radiobutton -label "Line end CRLF" -value crlf -variable ::eskil($top,mergetranslation) + if {$::eskil($top,mode) eq "conflict"} { $w.m.mc add separator - $w.m.mc add checkbutton -label "Pure" -variable diff($top,modetype) \ + $w.m.mc add checkbutton -label "Pure" -variable ::eskil($top,modetype) \ -onvalue "Pure" -offvalue "" -command {doDiff} } ttk::frame $w.f ttk::radiobutton $w.f.rb1 -text "LR" -value 12 \ - -variable diff($top,curMergeSel) \ + -variable ::eskil($top,curMergeSel) \ -command "selectMerge $top" ttk::radiobutton $w.f.rb2 -text "L" -value 1 \ - -variable diff($top,curMergeSel) \ + -variable ::eskil($top,curMergeSel) \ -command "selectMerge $top" ttk::radiobutton $w.f.rb3 -text "R" -value 2 \ - -variable diff($top,curMergeSel) \ + -variable ::eskil($top,curMergeSel) \ -command "selectMerge $top" ttk::radiobutton $w.f.rb4 -text "RL" -value 21 \ - -variable diff($top,curMergeSel) \ + -variable ::eskil($top,curMergeSel) \ -command "selectMerge $top" - bind $w "focus $w; set diff($top,curMergeSel) 1; selectMerge $top" - bind $w "focus $w; set diff($top,curMergeSel) 2; selectMerge $top" + bind $w "focus $w; set ::eskil($top,curMergeSel) 1; selectMerge $top" + bind $w "focus $w; set ::eskil($top,curMergeSel) 2; selectMerge $top" ttk::button $w.f.bl -text "Prev C" -command "nextMerge $top -1000" ttk::button $w.f.br -text "Next C" -command "nextMerge $top 1000" ttk::button $w.f.b1 -text "Prev" -command "nextMerge $top -1" @@ -461,11 +462,11 @@ scrollbar $w.sbx -orient horizontal -command "$w.t xview" scrollbar $w.sby -orient vertical -command "$w.t yview" bind $w.t [list focus $w] - ttk::label $w.ls -textvariable ::diff($top,mergeStatus) + ttk::label $w.ls -textvariable ::eskil($top,mergeStatus) # Prevent toplevel bindings on keys to fire while in the text widget. bindtags $w.t [list Text $w.t $w all] bind $w.t "break" bind $w.t "break" @@ -484,27 +485,27 @@ fillMergeWindow $top } # Compare each file against an ancestor file for three-way merge proc collectAncestorInfo {top dFile1 dFile2 opts} { - if {![info exists ::diff($top,mergetranslation)]} { + if {![info exists ::eskil($top,mergetranslation)]} { # Try to autodetect line endings in ancestor file - set ch [open $::diff($top,ancestorFile) rb] + set ch [open $::eskil($top,ancestorFile) 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 } } - array unset ::diff $top,ancestorLeft,* - array unset ::diff $top,ancestorRight,* + array unset ::eskil $top,ancestorLeft,* + array unset ::eskil $top,ancestorRight,* set differrA1 [catch {DiffUtil::diffFiles {*}$opts \ - $::diff($top,ancestorFile) $dFile1} diffresA1] + $::eskil($top,ancestorFile) $dFile1} diffresA1] set differrA2 [catch {DiffUtil::diffFiles {*}$opts \ - $::diff($top,ancestorFile) $dFile2} diffresA2] + $::eskil($top,ancestorFile) $dFile2} diffresA2] if {$differrA1 != 0 || $differrA2 != 0} { puts $diffresA1 puts $diffresA2 return } @@ -511,38 +512,38 @@ foreach i $diffresA1 { lassign $i line1 n1 line2 n2 if {$n1 == 0} { # Added lines for {set t $line2} {$t < $line2 + $n2} {incr t} { - set ::diff($top,ancestorLeft,$t) a + set ::eskil($top,ancestorLeft,$t) a } } elseif {$n2 == 0} { # Deleted lines # Mark the following line - set ::diff($top,ancestorLeft,d$line2) d + set ::eskil($top,ancestorLeft,d$line2) d } else { # Changed lines for {set t $line2} {$t < $line2 + $n2} {incr t} { - set ::diff($top,ancestorLeft,$t) c + set ::eskil($top,ancestorLeft,$t) c } } } foreach i $diffresA2 { lassign $i line1 n1 line2 n2 if {$n1 == 0} { # Added lines for {set t $line2} {$t < $line2 + $n2} {incr t} { - set ::diff($top,ancestorRight,$t) a + set ::eskil($top,ancestorRight,$t) a } } elseif {$n2 == 0} { # Deleted lines # Mark the following line - set ::diff($top,ancestorRight,d$line2) d + set ::eskil($top,ancestorRight,d$line2) d } else { # Changed lines for {set t $line2} {$t < $line2 + $n2} {incr t} { - set ::diff($top,ancestorRight,$t) c + set ::eskil($top,ancestorRight,$t) c } } } #parray ::diff $top,ancestor* } @@ -551,26 +552,26 @@ ##nagelfar syntax WhichSide x x x x x n n proc WhichSide {top line1 n1 line2 n2 conflictName commentName} { upvar 1 $conflictName conflict $commentName comment set conflict 0 set comment "" - if {$::diff($top,ancestorFile) eq ""} { + if {$::eskil($top,ancestorFile) eq ""} { # No ancestor info, just select right side return 2 } if {$n1 == 0} { # Only to the right - set delLeft [info exists ::diff($top,ancestorLeft,d$line1)] + set delLeft [info exists ::eskil($top,ancestorLeft,d$line1)] # Inserted to right : Keep right side if {!$delLeft} { set comment "Right: Add" return 2 } for {set t $line2} {$t < $line2 + $n2} {incr t} { - if {[info exists ::diff($top,ancestorRight,$t)]} { - set right($::diff($top,ancestorRight,$t)) 1 + if {[info exists ::eskil($top,ancestorRight,$t)]} { + set right($::eskil($top,ancestorRight,$t)) 1 } } # Deleted to left : Keep left side if {[array size right] == 0} { set comment "Left: Delete" @@ -581,20 +582,20 @@ set comment "*** Left: Delete, Right: Change" set conflict 1 return 2 } elseif {$n2 == 0} { # Only to the left, this can be: - set delRight [info exists ::diff($top,ancestorRight,d$line2)] + set delRight [info exists ::eskil($top,ancestorRight,d$line2)] # Inserted to left : Keep left side if {!$delRight} { set comment "Left: Add" return 1 } for {set t $line1} {$t < $line1 + $n1} {incr t} { - if {[info exists ::diff($top,ancestorLeft,$t)]} { - set left($::diff($top,ancestorLeft,$t)) 1 + if {[info exists ::eskil($top,ancestorLeft,$t)]} { + set left($::eskil($top,ancestorLeft,$t)) 1 } } # Deleted to right : Keep right side if {[array size left] == 0} { set comment "Right: Delete" @@ -608,12 +609,12 @@ } else { # Changed on both sides # Collect left side info for {set t $line1} {$t < $line1 + $n1} {incr t} { - if {[info exists ::diff($top,ancestorLeft,$t)]} { - set left($::diff($top,ancestorLeft,$t)) 1 + if {[info exists ::eskil($top,ancestorLeft,$t)]} { + set left($::eskil($top,ancestorLeft,$t)) 1 } } # No changes against ancestor on left side means it is just # changed to the right : Keep right @@ -622,12 +623,12 @@ return 2 } # Collect right side info for {set t $line2} {$t < $line2 + $n2} {incr t} { - if {[info exists ::diff($top,ancestorRight,$t)]} { - set right($::diff($top,ancestorRight,$t)) 1 + if {[info exists ::eskil($top,ancestorRight,$t)]} { + set right($::eskil($top,ancestorRight,$t)) 1 } } # No changes against ancestor on right side means it is just # changed to the left : Keep left Index: src/plugin.tcl ================================================================== --- src/plugin.tcl +++ src/plugin.tcl @@ -34,10 +34,11 @@ proc LocatePlugin {plugin} { set src "" set dirs [PluginSearchPath] foreach dir $dirs { + set dir [file normalize $dir] set files {} lappend files [file join $dir $plugin] lappend files [file join $dir $plugin.tcl] foreach file $files { if {![file exists $file]} continue @@ -92,10 +93,11 @@ proc listPlugins {} { set dirs [PluginSearchPath] foreach dir $dirs { + set dir [file normalize $dir] set files [glob -nocomplain [file join $dir *.tcl]] foreach file $files { set file [file normalize $file] if {[info exists done($file)]} continue if {![file exists $file]} continue @@ -109,11 +111,15 @@ if {[regexp {^\#\#Eskil Plugin :(.*?)(\n|$)} $data -> descr]} { set result([file rootname [file tail $file]]) $descr } } } - return [array get result] + set resultSort {} + foreach elem [lsort -dictionary [array names result]] { + lappend resultSort $elem $result($elem) + } + return $resultSort } proc printPlugins {} { set plugins [listPlugins] if {[llength $plugins] == 0} { @@ -127,62 +133,62 @@ } proc preparePlugin {top} { #FIXA: plugin miffo disallowEdit $top - $::diff($top,plugin) eval [list array set ::Pref [array get ::Pref]] + $::eskil($top,plugin) eval [list array set ::Pref [array get ::Pref]] set out1 [tmpFile] set out2 [tmpFile] - set chi [open $::diff($top,leftFile) r] + set chi [open $::eskil($top,leftFile) r] set cho [open $out1 w] - interp share {} $chi $::diff($top,plugin) - interp share {} $cho $::diff($top,plugin) - set usenew1 [$::diff($top,plugin) eval [list PreProcess left $chi $cho]] - $::diff($top,plugin) invokehidden close $chi - $::diff($top,plugin) invokehidden close $cho + interp share {} $chi $::eskil($top,plugin) + interp share {} $cho $::eskil($top,plugin) + set usenew1 [$::eskil($top,plugin) eval [list PreProcess left $chi $cho]] + $::eskil($top,plugin) invokehidden close $chi + $::eskil($top,plugin) invokehidden close $cho close $chi close $cho - set chi [open $::diff($top,rightFile) r] + set chi [open $::eskil($top,rightFile) r] set cho [open $out2 w] - interp share {} $chi $::diff($top,plugin) - interp share {} $cho $::diff($top,plugin) - set usenew2 [$::diff($top,plugin) eval [list PreProcess right $chi $cho]] - $::diff($top,plugin) invokehidden close $chi - $::diff($top,plugin) invokehidden close $cho + interp share {} $chi $::eskil($top,plugin) + interp share {} $cho $::eskil($top,plugin) + set usenew2 [$::eskil($top,plugin) eval [list PreProcess right $chi $cho]] + $::eskil($top,plugin) invokehidden close $chi + $::eskil($top,plugin) invokehidden close $cho close $chi close $cho if {$usenew1} { # The file after processing should be used both # for comparison and for displaying. - set ::diff($top,leftFileBak) $::diff($top,leftFile) - set ::diff($top,leftFile) $out1 + set ::eskil($top,leftFileBak) $::eskil($top,leftFile) + set ::eskil($top,leftFile) $out1 } else { - set ::diff($top,leftFileDiff) $out1 - #set ::diff($top,leftLabel) "$::diff($top,RevFile) $tag" + set ::eskil($top,leftFileDiff) $out1 + #set ::eskil($top,leftLabel) "$::eskil($top,RevFile) $tag" } if {$usenew2} { - set ::diff($top,rightFileBak) $::diff($top,rightFile) - set ::diff($top,rightFile) $out2 + set ::eskil($top,rightFileBak) $::eskil($top,rightFile) + set ::eskil($top,rightFile) $out2 } else { - set ::diff($top,rightFileDiff) $out2 - #set ::diff($top,rightLabel) $::diff($top,RevFile) + set ::eskil($top,rightFileDiff) $out2 + #set ::eskil($top,rightLabel) $::eskil($top,RevFile) } } proc cleanupPlugin {top} { - if {[info exists ::diff($top,leftFileBak)]} { - set ::diff($top,leftFile) $::diff($top,leftFileBak) + if {[info exists ::eskil($top,leftFileBak)]} { + set ::eskil($top,leftFile) $::eskil($top,leftFileBak) } - if {[info exists ::diff($top,rightFileBak)]} { - set ::diff($top,rightFile) $::diff($top,rightFileBak) + if {[info exists ::eskil($top,rightFileBak)]} { + set ::eskil($top,rightFile) $::eskil($top,rightFileBak) } unset -nocomplain \ - ::diff($top,leftFileBak) ::diff($top,rightFileBak) \ - ::diff($top,leftFileDiff) ::diff($top,rightFileDiff) + ::eskil($top,leftFileBak) ::eskil($top,rightFileBak) \ + ::eskil($top,leftFileDiff) ::eskil($top,rightFileDiff) } # GUI for plugin selection proc EditPrefPlugins {top} { set w $top.prefplugin @@ -196,51 +202,78 @@ set plugins [listPlugins] if {[llength $plugins] == 0} { grid [ttk::label $w.l -text "No plugins found."] - -padx 3 -pady 3 } - if {![info exists ::diff($top,pluginname)]} { - set ::diff($top,pluginname) "" - } - if {![info exists ::diff($top,plugininfo)]} { - set ::diff($top,plugininfo) "" - } - set ::diff($top,edit,pluginname) $::diff($top,pluginname) - set ::diff($top,edit,plugininfo) $::diff($top,plugininfo) + if {![info exists ::eskil($top,pluginname)]} { + set ::eskil($top,pluginname) "" + } + if {![info exists ::eskil($top,plugininfo)]} { + set ::eskil($top,plugininfo) "" + } + set ::eskil($top,edit,pluginname) $::eskil($top,pluginname) + set ::eskil($top,edit,plugininfo) $::eskil($top,plugininfo) set t 0 foreach {plugin descr} $plugins { - ttk::radiobutton $w.rb$t -variable ::diff($top,edit,pluginname) -value $plugin -text $plugin + ttk::radiobutton $w.rb$t -variable ::eskil($top,edit,pluginname) -value $plugin -text $plugin ttk::label $w.l$t -text $descr -anchor "w" grid $w.rb$t $w.l$t -sticky we -padx 3 -pady 3 incr t } - ttk::radiobutton $w.rb$t -variable ::diff($top,edit,pluginname) -value "" -text "No Plugin" + ttk::radiobutton $w.rb$t -variable ::eskil($top,edit,pluginname) -value "" -text "No Plugin" grid $w.rb$t -sticky we -padx 3 -pady 3 ttk::label $w.li -text "Info" -anchor "w" - ttk::entry $w.ei -textvariable ::diff($top,edit,plugininfo) + ttk::entry $w.ei -textvariable ::eskil($top,edit,plugininfo) grid $w.li $w.ei -sticky we -padx 3 -pady 3 ttk::frame $w.fb -padding 3 ttk::button $w.fb.b1 -text "Ok" -command [list EditPrefPluginsOk $top $w] - ttk::button $w.fb.b2 -text "Cancel" -command [list destroy $w] + ttk::button $w.fb.b2 -text "Show" \ + -command "ShowPlugin $w \$::eskil($top,edit,pluginname)" + ttk::button $w.fb.b3 -text "Cancel" -command [list destroy $w] set ::widgets($top,prefPluginsOk) $w.fb.b1 - grid $w.fb.b1 x $w.fb.b2 -sticky we - grid columnconfigure $w.fb {0 2} -uniform a - grid columnconfigure $w.fb 1 -weight 1 + grid $w.fb.b1 x $w.fb.b2 x $w.fb.b3 -sticky we + grid columnconfigure $w.fb {0 2 4} -uniform a + grid columnconfigure $w.fb {1 3} -weight 1 grid $w.fb - -sticky we grid columnconfigure $w 1 -weight 1 } proc EditPrefPluginsOk {top w} { destroy $w - set ::diff($top,pluginname) $::diff($top,edit,pluginname) - set ::diff($top,plugininfo) $::diff($top,edit,plugininfo) - if {$::diff($top,pluginname) ne ""} { - set pinterp [createPluginInterp $::diff($top,pluginname) $::diff($top,plugininfo)] + set ::eskil($top,pluginname) $::eskil($top,edit,pluginname) + set ::eskil($top,plugininfo) $::eskil($top,edit,plugininfo) + if {$::eskil($top,pluginname) ne ""} { + set pinterp [createPluginInterp $::eskil($top,pluginname) $::eskil($top,plugininfo)] } else { set pinterp "" } - set ::diff($top,plugin) $pinterp + set ::eskil($top,plugin) $pinterp +} + +proc ShowPlugin {parent plugin} { + set src [LocatePlugin $plugin] + if {$src eq ""} return + set ch [open $src] + set data [read $ch] + close $ch + set w $parent.plugin + if {[winfo exists $w]} { + wm deiconify $w + } else { + toplevel $w -padx 3 -pady 3 + } + destroy {*}[winfo children $w] + ttk::frame $w._bg + place $w._bg -x 0 -y 0 -relwidth 1.0 -relheight 1.0 -border outside + wm title $w "Plugin: $plugin" + + set t [Scroll both text $w.t -width 80 -height 20 -font myfont] + pack $w.t -fill both -expand 1 + bind $t "[list $t tag add sel 1.0 end];break" + + $t insert end $data } + Index: src/print.tcl ================================================================== --- src/print.tcl +++ src/print.tcl @@ -237,23 +237,23 @@ normalCursor $top } proc PdfPrint {top cpl cpln wraplines1 wraplines2} { - if {$::diff($top,printFile) != ""} { - set pdfFile $::diff($top,printFile) + if {$::eskil($top,printFile) != ""} { + set pdfFile $::eskil($top,printFile) } else { set pdfFile ~/eskil.pdf } - if {![regexp {^(.*)( \(.*?\))$} $::diff($top,leftLabel) -> lfile lrest]} { - set lfile $::diff($top,leftLabel) + if {![regexp {^(.*)( \(.*?\))$} $::eskil($top,leftLabel) -> lfile lrest]} { + set lfile $::eskil($top,leftLabel) set lrest "" } set lfile [file tail $lfile]$lrest - if {![regexp {^(.*)( \(.*?\))$} $::diff($top,rightLabel) -> rfile rrest]} { - set rfile $::diff($top,rightLabel) + if {![regexp {^(.*)( \(.*?\))$} $::eskil($top,rightLabel) -> rfile rrest]} { + set rfile $::eskil($top,rightLabel) set rrest "" } set rfile [file tail $rfile]$rrest set pdf [eskilprint %AUTO% -file $pdfFile -cpl $cpl -cpln $cpln \ @@ -291,31 +291,31 @@ # Count the length of a line during a text dump proc AccumulateMax {key value index} { set index [lindex [split $index "."] 1] set len [expr {[string length $value] + $index - 1}] - if {$len > $::diff(currentCharsPerLine)} { - set ::diff(currentCharsPerLine) $len + if {$len > $::eskil(currentCharsPerLine)} { + set ::eskil(currentCharsPerLine) $len } } # Count the longest line length in the current display proc CountCharsPerLine {top} { - set ::diff(currentCharsPerLine) 0 + set ::eskil(currentCharsPerLine) 0 $::widgets($top,wDiff1) dump -text -command AccumulateMax 1.0 end $::widgets($top,wDiff2) dump -text -command AccumulateMax 1.0 end - return $::diff(currentCharsPerLine) + return $::eskil(currentCharsPerLine) } proc BrowsePrintFileName {top entry} { - set prev $::diff($top,printFile) + set prev $::eskil($top,printFile) set dir [file dirname $prev] set apa [tk_getSaveFile -initialdir $dir -initialfile [file tail $prev] \ -parent [winfo toplevel $entry] -title "PDF file"] if {$apa ne ""} { - set ::diff($top,printFile) $apa + set ::eskil($top,printFile) $apa $entry xview end } } # Create a print dialog for PDF. @@ -403,16 +403,16 @@ grid .pr.cf.l3 .pr.cf.s3r .pr.cf.s3g .pr.cf.s3b -sticky w -padx 3 -pady 3 # File ttk::label .pr.fnl -anchor w -text "File name" - ttk::entryX .pr.fne -textvariable ::diff($top,printFile) -width 30 + ttk::entryX .pr.fne -textvariable ::eskil($top,printFile) -width 30 ttk::button .pr.fnb -text Browse \ -command [list BrowsePrintFileName $top .pr.fne] - if {$::diff($top,printFile) eq ""} { - set ::diff($top,printFile) "~/eskil.pdf" + if {$::eskil($top,printFile) eq ""} { + set ::eskil($top,printFile) "~/eskil.pdf" } ttk::frame .pr.fb ttk::button .pr.b1 -text "Print to File" \ -command "destroy .pr; update; PrintDiffs $top" Index: src/rev.tcl ================================================================== --- src/rev.tcl +++ src/rev.tcl @@ -102,36 +102,20 @@ } return 0 } proc eskil::rev::HG::detect {file} { - if {$file eq ""} { - set dir [pwd] - } else { - set dir [file dirname $file] - } - # HG, detect two steps down. Could be improved. FIXA - if {[file isdirectory [file join $dir .hg]] || - [file isdirectory [file join $dir .. .hg]] || - [file isdirectory [file join $dir .. .. .hg]]} { + if {[SearchUpwardsFromFile $file .hg]} { if {[auto_execok hg] ne ""} { return 1 } } return 0 } proc eskil::rev::BZR::detect {file} { - if {$file eq ""} { - set dir [pwd] - } else { - set dir [file dirname $file] - } - # HG, detect two steps down. Could be improved. FIXA - if {[file isdirectory [file join $dir .bzr]] || - [file isdirectory [file join $dir .. .bzr]] || - [file isdirectory [file join $dir .. .. .bzr]]} { + if {[SearchUpwardsFromFile $file .bzr]} { if {[auto_execok bzr] ne ""} { return 1 } } return 0 @@ -164,37 +148,20 @@ } return 0 } proc eskil::rev::GIT::detect {file} { - if {$file eq ""} { - set dir [pwd] - } else { - set dir [file dirname $file] - } - # Git, detect two steps down. Could be improved. FIXA - if {[file isdirectory [file join $dir .git]] || - [file isdirectory [file join $dir .. .git]] || - [file isdirectory [file join $dir .. .. .git]]} { + if {[SearchUpwardsFromFile $file .git]} { if {[auto_execok git] ne ""} { return 1 } } return 0 } proc eskil::rev::FOSSIL::detect {file} { - if {$file eq ""} { - set dir [pwd] - } else { - set dir [file dirname $file] - } - # Fossil, detect three steps down. Could be improved. FIXA - if {[file exists [file join $dir _FOSSIL_]] || - [file exists [file join $dir .. _FOSSIL_]] || - [file exists [file join $dir .. .. _FOSSIL_]] || - [file exists [file join $dir .. .. .. _FOSSIL_]]} { + if {[SearchUpwardsFromFile $file _FOSSIL_ .fos]} { if {[auto_execok fossil] ne ""} { return 1 } } return 0 @@ -941,19 +908,19 @@ } # Initialise revision control mode # The file name should be an absolute normalized path. proc startRevMode {top rev file} { - set ::diff($top,mode) "rev" - set ::diff($top,modetype) $rev - set ::diff($top,rightDir) [file dirname $file] - set ::diff($top,RevFile) $file - set ::diff($top,rightLabel) $file - set ::diff($top,rightFile) $file - set ::diff($top,rightOK) 1 - set ::diff($top,leftLabel) $rev - set ::diff($top,leftOK) 0 + set ::eskil($top,mode) "rev" + set ::eskil($top,modetype) $rev + set ::eskil($top,rightDir) [file dirname $file] + set ::eskil($top,RevFile) $file + set ::eskil($top,rightLabel) $file + set ::eskil($top,rightFile) $file + set ::eskil($top,rightOK) 1 + set ::eskil($top,leftLabel) $rev + set ::eskil($top,leftOK) 0 set ::Pref(toolbar) 1 } # Prepare for revision diff. Checkout copies of the versions needed. proc prepareRev {top} { @@ -960,28 +927,28 @@ global Pref $::widgets($top,commit) configure -state disabled $::widgets($top,log) configure -state disabled - set type $::diff($top,modetype) + set type $::eskil($top,modetype) set revs {} # Search for revision options - if {$::diff($top,doptrev1) != ""} { - lappend revs $::diff($top,doptrev1) + if {$::eskil($top,doptrev1) != ""} { + lappend revs $::eskil($top,doptrev1) } - if {$::diff($top,doptrev2) != ""} { - lappend revs $::diff($top,doptrev2) + if {$::eskil($top,doptrev2) != ""} { + lappend revs $::eskil($top,doptrev2) } - set revs [eskil::rev::${type}::ParseRevs $::diff($top,RevFile) $revs] + set revs [eskil::rev::${type}::ParseRevs $::eskil($top,RevFile) $revs] set revlabels {} foreach rev $revs { lappend revlabels [GetLastTwoPath $rev] } - set ::diff($top,RevRevs) $revs + set ::eskil($top,RevRevs) $revs if {[llength $revs] < 2} { # Compare local file with specified version. disallowEdit $top 1 if {[llength $revs] == 0} { @@ -989,16 +956,16 @@ set tag "($type)" } else { set r [lindex $revs 0] set tag "($type [lindex $revlabels 0])" } - set ::diff($top,leftFile) [tmpFile] - set ::diff($top,leftLabel) "$::diff($top,RevFile) $tag" - set ::diff($top,rightLabel) $::diff($top,RevFile) - set ::diff($top,rightFile) $::diff($top,RevFile) + set ::eskil($top,leftFile) [tmpFile] + set ::eskil($top,leftLabel) "$::eskil($top,RevFile) $tag" + set ::eskil($top,rightLabel) $::eskil($top,RevFile) + set ::eskil($top,rightFile) $::eskil($top,RevFile) - eskil::rev::${type}::get $::diff($top,RevFile) $::diff($top,leftFile) $r + eskil::rev::${type}::get $::eskil($top,RevFile) $::eskil($top,leftFile) $r if {[llength $revs] == 0} { if {[info commands eskil::rev::${type}::commitFile] ne ""} { $::widgets($top,commit) configure -state normal } } @@ -1005,19 +972,19 @@ } else { # Compare the two specified versions. disallowEdit $top set r1 [lindex $revs 0] set r2 [lindex $revs 1] - set ::diff($top,leftFile) [tmpFile] - set ::diff($top,rightFile) [tmpFile] - - set ::diff($top,leftLabel) \ - "$::diff($top,RevFile) ($type [lindex $revlabels 0])" - set ::diff($top,rightLabel) \ - "$::diff($top,RevFile) ($type [lindex $revlabels 1])" - eskil::rev::${type}::get $::diff($top,RevFile) $::diff($top,leftFile) $r1 - eskil::rev::${type}::get $::diff($top,RevFile) $::diff($top,rightFile) $r2 + set ::eskil($top,leftFile) [tmpFile] + set ::eskil($top,rightFile) [tmpFile] + + set ::eskil($top,leftLabel) \ + "$::eskil($top,RevFile) ($type [lindex $revlabels 0])" + set ::eskil($top,rightLabel) \ + "$::eskil($top,RevFile) ($type [lindex $revlabels 1])" + eskil::rev::${type}::get $::eskil($top,RevFile) $::eskil($top,leftFile) $r1 + eskil::rev::${type}::get $::eskil($top,RevFile) $::eskil($top,rightFile) $r2 } if {[llength $revs] > 0} { if {[info commands eskil::rev::${type}::viewLog] ne ""} { $::widgets($top,log) configure -state normal } @@ -1028,51 +995,51 @@ # Clean up after a revision diff. proc cleanupRev {top} { global Pref - clearTmp $::diff($top,rightFile) $::diff($top,leftFile) - set ::diff($top,rightFile) $::diff($top,RevFile) - set ::diff($top,leftFile) $::diff($top,RevFile) + clearTmp $::eskil($top,rightFile) $::eskil($top,leftFile) + set ::eskil($top,rightFile) $::eskil($top,RevFile) + set ::eskil($top,leftFile) $::eskil($top,RevFile) } proc revCommit {top} { if {[$::widgets($top,commit) cget -state] eq "disabled"} return - set type $::diff($top,modetype) - if {$::diff($top,mode) eq "patch"} { - set files $::diff($top,reviewFiles) + set type $::eskil($top,modetype) + if {$::eskil($top,mode) eq "patch"} { + set files $::eskil($top,reviewFiles) } else { - set files [list $::diff($top,RevFile)] + set files [list $::eskil($top,RevFile)] } eskil::rev::${type}::commitFile $top {*}$files } proc revLog {top} { if {[$::widgets($top,log) cget -state] eq "disabled"} return - set type $::diff($top,modetype) - eskil::rev::${type}::viewLog $top $::diff($top,RevFile) \ - $::diff($top,RevRevs) + set type $::eskil($top,modetype) + eskil::rev::${type}::viewLog $top $::eskil($top,RevFile) \ + $::eskil($top,RevRevs) } # Get a complete tree patch from this system. proc getFullPatch {top} { global Pref $::widgets($top,commit) configure -state disabled $::widgets($top,log) configure -state disabled - set type $::diff($top,modetype) - set files $::diff($top,reviewFiles) + set type $::eskil($top,modetype) + set files $::eskil($top,reviewFiles) set revs {} # Search for revision options - if {$::diff($top,doptrev1) != ""} { - lappend revs $::diff($top,doptrev1) + if {$::eskil($top,doptrev1) != ""} { + lappend revs $::eskil($top,doptrev1) } - if {$::diff($top,doptrev2) != ""} { - lappend revs $::diff($top,doptrev2) + if {$::eskil($top,doptrev2) != ""} { + lappend revs $::eskil($top,doptrev2) } set revs [eskil::rev::${type}::ParseRevs "" $revs] set revlabels {} foreach rev $revs { @@ -1089,10 +1056,33 @@ } ############################################################################## # Utilities ############################################################################## + +# Search upwards the directory structure for a file +proc SearchUpwardsFromFile {file args} { + if {$file eq ""} { + set dir [pwd] + } elseif {[file isdirectory $file]} { + set dir $file + } else { + set dir [file dirname $file] + } + while {[file readable $dir] && [file isdirectory $dir]} { + foreach candidate $args { + if {[file exists [file join $dir $candidate]]} { + return 1 + } + } + set parent [file dirname $dir] + # Make sure to stop if we reach a dead end + if {$parent eq $dir} break + set dir $parent + } + return 0 +} # Get the last two elements in a file path proc GetLastTwoPath {path} { set last [file tail $path] set penultimate [file tail [file dirname $path]] @@ -1108,22 +1098,22 @@ set w $top.logmsg destroy $w toplevel $w -padx 3 -pady 3 wm title $w "Commit log message for $target" - set ::diff($top,logdialogok) 0 + set ::eskil($top,logdialogok) 0 text $w.t -width 70 -height 10 - if {!$clean && [info exists ::diff(logdialog)]} { - $w.t insert end $::diff(logdialog) + if {!$clean && [info exists ::eskil(logdialog)]} { + $w.t insert end $::eskil(logdialog) $w.t tag add sel 1.0 end-1c $w.t mark set insert 1.0 } ttk::button $w.ok -width 10 -text "Commit" -underline 1 \ - -command "set ::diff($top,logdialogok) 1 ; \ - set ::diff(logdialog) \[$w.t get 1.0 end\] ; \ + -command "set ::eskil($top,logdialogok) 1 ; \ + set ::eskil(logdialog) \[$w.t get 1.0 end\] ; \ destroy $w" ttk::button $w.ca -width 10 -text "Cancel" -command "destroy $w" \ -underline 0 bind $w [list $w.ok invoke]\;break bind $w [list destroy $w]\;break @@ -1133,13 +1123,13 @@ grid $w.ok $w.ca -padx 3 -pady 3 tkwait visibility $w focus -force $w.t tkwait window $w - if {$::diff($top,logdialogok)} { - set res [string trim $::diff(logdialog)] - set ::diff(logdialog) $res + if {$::eskil($top,logdialogok)} { + set res [string trim $::eskil(logdialog)] + set ::eskil(logdialog) $res if {$res eq ""} { set res "No Log" } } else { set res "" Index: tests/all.tcl ================================================================== --- tests/all.tcl +++ tests/all.tcl @@ -13,21 +13,25 @@ package require tcltest 2.2 namespace import tcltest::* tcltest::configure -verbose "body error" #testConstraint knownbug 1 #tcltest::configure -match print-* + +if {$argc > 0} { + eval tcltest::configure $argv +} package require Tk wm withdraw . set ::eskil_testsuite 1 -if {[file exists src/eskil.tcl_i]} { +if {[file exists eskil.vfs/src/eskil.tcl_i]} { puts "Running with code coverage" - source src/eskil.tcl_i + source eskil.vfs/src/eskil.tcl_i } else { - source src/eskil.tcl + source eskil.vfs/src/eskil.tcl } Init # Helpers to temporarily stub things out set ::stubs {} @@ -45,10 +49,13 @@ rename _stub_$name $name } set ::stubs {} } +proc ExecEskil {args} { + return [exec ./eskil.kit {*}$args] +} puts "Running Tests" foreach test [glob -nocomplain $testDir/*.test] { source $test Index: tests/gui.test ================================================================== --- tests/gui.test +++ tests/gui.test @@ -23,21 +23,28 @@ exec xhost - } XauthSecure proc RestartClient {args} { - set ::clientfile ./eskil.kit + if {[file exists eskil.vfs/main.tcl_i]} { + puts "Starting gui instrumented" + set src eskil.vfs/main.tcl_i + } else { + set src eskil.vfs/main.tcl + } + set cmd [list tclkit $src] + #set ::clientfile ./eskil.kit #if {[file exists ${::clientfile}_i]} { # set ::clientfile ${::clientfile}_i #} if {![catch {send -async Eskil exit}]} { update after 500 } - set slavepid [exec $::clientfile -server {*}$args &] + set slavepid [exec {*}$cmd -server {*}$args &] after 1000 while {[catch {tktest::init Eskil}]} { after 500 } Index: tests/patch.test ================================================================== --- tests/patch.test +++ tests/patch.test @@ -2,12 +2,12 @@ #---------------------------------------------------------------------- # $Revision$ #---------------------------------------------------------------------- # Overload exec during these tests -set ::diff(gurka,patchFile) "" -set ::diff(gurka,patchData) "" +set ::eskil(gurka,patchFile) "" +set ::eskil(gurka,patchData) "" stub update args {} stub getFullPatch {top} { return $::testpatch } stub displayOnePatch {top leftLines rightLines leftLine rightLine} { Index: tests/print.test ================================================================== --- tests/print.test +++ tests/print.test @@ -35,11 +35,11 @@ puts $ch1 $data puts $ch2 $data close $ch1 close $ch2 } -body { - set res [exec ./eskil.kit -context 5 -printpdf $f3 $f1 $f2] + set res [ExecEskil -context 5 -printpdf $f3 $f1 $f2] puts $res set ch [open $f3 r] set data [read $ch] close $ch # Check that line numbers take up 7 chars @@ -49,27 +49,27 @@ tcltest::removeFile {} _test2 tcltest::removeFile {} _test3 } -result {1} test print-3.1 {Pdf, cmd line} -body { - set res [exec ./eskil.kit -printHeaderSize x] + set res [ExecEskil -printHeaderSize x] } -result {Argument -printHeaderSize must be a positive number} test print-3.2 {Pdf, cmd line} -body { - set res [exec ./eskil.kit -printCharsPerLine -5] + set res [ExecEskil -printCharsPerLine -5] } -result {Argument -printCharsPerLine must be a positive number} test print-3.3 {Pdf, cmd line} -body { - set res [exec ./eskil.kit -printPaper qx] + set res [ExecEskil -printPaper qx] } -match glob -result {Argument -printPaper must be a valid paper size*} test print-3.4 {Pdf, cmd line} -body { - set res [exec ./eskil.kit -printColorChange x] + set res [ExecEskil -printColorChange x] } -result {Argument -printColorChange must be a list of RBG values from 0.0 to 1.0} test print-3.5 {Pdf, cmd line} -body { - set res [exec ./eskil.kit -printColorOld "0 1 2"] + set res [ExecEskil -printColorOld "0 1 2"] } -result {Argument -printColorOld must be a list of RBG values from 0.0 to 1.0} test print-3.6 {Pdf, cmd line} -body { - set res [exec ./eskil.kit -printColorNew "0 -1 0.5"] + set res [ExecEskil -printColorNew "0 -1 0.5"] } -result {Argument -printColorNew must be a list of RBG values from 0.0 to 1.0} Index: tests/rev.test ================================================================== --- tests/rev.test +++ tests/rev.test @@ -9,11 +9,11 @@ switch -- $cmd { cleartool { # cleartool lshistory -short $filename # cleartool pwv -s # cleartool get -to $outfile $filerev - # cleartool ls $::diff($top,RevFile) + # cleartool ls $::eskil($top,RevFile) if {[lindex $args 1] eq "lshistory"} { return [join [list x@/Apa/Bepa/12 x@/Apa/Cepa/2 x@/Apa/22 x@/Apa] \n] } if {[lindex $args 1] eq "pwv"} { return $::ct_pwv