[Keith Vetter] 2003-11-07 : There's been a recent hue and cry for "a good diffs module" (see [There is a huge need for a diffs module!]. Here's something I've been using for half a year or so. You enter a wiki page number and it displays the revision history for that page. You then select any two entries, click a button and it will fetch those two revisions and run [tkdiff] on them (or if you prefer you can use ExamDiff [http://www.prestosoft.com/ps.asp?page=edp_examdiff]). This works reasonably well but with two flaws: first, the information in the wiki history seems to be a day behind the wiki itself, and second, wiki pages often contain very long lines which don't have good diff behavior. [WikiDiff] handle this second problem in a very clever way by doing a word level diff. ---- [RobertAbitbol] This sounds like a great idea. Can we try the code somwhere? Can you ask [JCW] to put it in the program so we could all try it? Thanks! [KPV] I don't understand, here's the code. Just grab it and run it. ---- ##+########################################################################## # # Wiki History Diff.tcl -- diffs back versions of the tcl Wiki pages # by Keith Vetter # # Revisions: # KPV Mar 11, 2003 - initial revision # KPV Nov 07, 2003 - some touch up work # package require Tk package require http set S(diffprog) tkdiff ;# Examdiff.exe works well too set S(title) "Wiki History Diff" set S(bg) "#9977cc" set S(pnum) "xx" set S(pnum2) "" # Stupid temp directory set S(tmp) [pwd] if {[file isdirectory "c:/temp"]} { set S(tmp) "c:/temp"} if {[file isdirectory "/tmp"]} { set S(tmp) "/tmp"} catch {set S(tmp) $env(TRASH_FOLDER)} ;# Macintosh(?) catch {set S(tmp) $env(TMPDIR)} catch {set S(tmp) $env(TMP)} catch {set S(tmp) $env(TEMP)} proc INFO {msg} {puts [set ::S(msg) $msg]} proc DoDisplay {} { global S wm title . "Wiki History Diff" wm protocol . WM_DELETE_WINDOW {Cleanup 1} label .msg -textvariable S(msg) pack .msg -side bottom -fill x button .about -text About -highlightthickness 0 -command About pack .about -in .msg -side right -padx .1i option add *Label.background $S(bg) option add *Label.foreground white option add *Button.background $S(bg) option add *Button.activeBackground $S(bg) option add *Button.foreground white option add *Button.activeForeground white frame .top -bg $S(bg) -relief groove -bd 2 frame .topl -bg $S(bg) button .topl.wiki -text "Wiki Page " -command DoWikiPage -relief flat entry .topl.ewiki -textvariable S(pnum2) -relief sunken -width 6 bind .topl.ewiki [list .topl.wiki invoke] label .top.title -textvariable S(title) -fg magenta trace variable S(pnum2) w tracer set font [font actual [.top.title cget -font]] .top.title config -font "$font -weight bold -size 18" frame .topr -bg $S(bg) label .topr.l0 -text "Version " label .topr.e0 -textvar S(0) -width 5 -relief sunken label .topr.v -text " vs. " label .topr.l1 -text "Version " label .topr.e1 -textvar S(1) -width 5 -relief sunken label .topr.= -text " => " button .topr.diff -text "Run $S(diffprog)" -command RunTKDiff -bd 5 pack .top -side top -fill x pack .topr -in .top -side right pack .topl -in .top -side left pack .top.title -side top -expand 1 eval pack [winfo child .topl] -side left eval pack [winfo child .topr] -side left pack config .topl.wiki -padx {.1i .05i} pack config .topr.diff -padx {0 .1i} pack [frame .mid -bd 4 -relief ridge] -side top -fill both -expand 1 foreach w {0 1} { listbox .l$w -exportselection 0 -width 63 -height 20 -bd 0 \ -font {courier 8} -yscrollcommand [list .sb$w set] bind .l$w <> [list ListboxSelect %W $w] bind .l$w <1> [list focus %W] scrollbar .sb$w -orient v -command [list .l$w yview] } grid .l0 .sb0 .l1 .sb1 -in .mid -sticky news grid rowconfigure .mid 0 -weight 1 grid columnconfigure .mid {0 2} -weight 1 option clear bind all {console show} focus .topl.ewiki } proc ListboxSelect {W who} { global S set row [$W curselection] set data [$W get $row] set S($who) [lindex $data 1] } proc tracer {var1 var2 op} { global S if {$S(pnum2) == $S(pnum)} { .topl.ewiki config -bg [lindex [.topl.ewiki config -bg] 3] .topl.wiki config -relief flat } else { .topl.ewiki config -bg red .topl.wiki config -relief raised } } proc ReInit {} { global S set S(cnt) 0 } proc GetVersionInfo {} { global S .l0 delete 0 end .l1 delete 0 end update GetTitle INFO "Getting history for page $S(pnum)" set url "http://mini.net/tclhist/$S(pnum)*" set token [::http::geturl $url] set data [::http::data $token] ::http::cleanup $token set S(cnt) 0 foreach {version tstamp who c1 c2} $data { set when [clock format $tstamp -gmt 1 -format "%e %b %Y %T %Z"] set txt [format " version %2s %16s %s $c1 $c2" $version $who $when] .l0 insert end $txt .l1 insert end $txt incr S(cnt) } set S(0) [set S(1) ""] if {$S(cnt) > 0} { foreach i {0 1} { set el [expr {$S(cnt) > 1 ? 1 - $i : 0}] .l$i selection clear 0 end .l$i selection set $el .l$i selection anchor $el event generate .l$i <> } } else { .l0 insert end .l1 insert end } set msg "Wiki page $S(pnum) has $S(cnt) version" if {$S(cnt) != 1} {append msg s} INFO $msg } proc GetTitle {} { global S INFO "Getting title for page $S(pnum)" set url "http://mini.net/tclhist/$S(pnum)" set token [::http::geturl $url] set data [::http::data $token] ::http::cleanup $token set S(title) "No Wiki History" regexp -line {Title:\s*(.*)} $data => S(title) set S(title) "\"$S(title)\"" } proc GetVersion {pnum ver} { set fname [file join $::S(tmp) "wiki.$pnum.$ver"] set fout [open $fname "w"] set url "http://mini.net/tclhist/$pnum.$ver" set token [::http::geturl $url -channel $fout] close $fout ::http::cleanup $token return $fname } proc RunTKDiff {} { global S Cleanup if {$S(0) == "" || $S(1) == ""} return set f1 [GetVersion $S(pnum) $S(0)] set f2 [GetVersion $S(pnum) $S(1)] exec $S(diffprog) $f1 $f2 & set ::TMPFILES($f1) 1 set ::TMPFILES($f2) 1 after 2000 ;# Pause to let tkdiff start } proc DoWikiPage {} { global S after 10 Cleanup .topl.ewiki icursor end if {! [string is integer -strict $S(pnum2)]} return if {$S(pnum) == $S(pnum2)} return set S(pnum) $S(pnum2) GetVersionInfo set S(pnum2) $S(pnum2) } proc Cleanup {{exit 0}} { global TMPFILES foreach fname [array names TMPFILES] { set n [catch {file delete $fname}] if {! $n} { unset TMPFILES($fname) } } if {$exit} exit } proc About {} { set msg "WikiDiff\nby Keith Vetter\nMarch 2003\n\n" append msg "Compares back revisions of a\nTcl'ers Wiki " append msg "page using tkdiff." tk_messageBox -title "About" -message $msg } DoDisplay set S(pnum2) [lindex $argv 0] .l0 insert end "Enter the number of a Wiki page to run diff on" ----- [Robert Abitbol] Thanks Keith but bear with me. I am not a TCL expert. I don't even have a TCL compiler. But hey if you can tell me where I can find a compiler, I'll be the happiest guy in the world and I'll definitely going to try it! Many thanks! Robert - maybe you have lost sight of the purpose of this wiki. It's about Tcl - an interpreted language. Surely you can use it to find the information you seek. Try google if you can't find it here. [Robert Abitbol] Sorry! I had no idea Tcl was an interpretable language and not a compilable one. I'll try to get or buy an interpreter so I can use your diffs and other programs. Thanks and sorry for the trouble. ---- ''Keith, FYI, on Mac OS X the above needs font "courier 10" to be readable (with X11). Also note that this works fine with the tkdiff starkit on [sdarchive]. Great utility! -[jcw]'' ---- ''This is probably a better place to write this than on the [Diffs Code Module in progress] page. --[PS]'' If anyone is interested, I have a port of wikidiff into wikit at [http://pascal.scheffers.net/software/wikit-hist.kit]. I have had it running for over a year now, sorry for not contributing sooner ;-). It still uses diff/patch from the filesystem, either the standard unix ones or cygwin versions, it should be easily changed to tcllib/diff (does it have patch too?). There are some bugs in the display code, but it *does* store the history in a chain of diffs either in wikit.tkd or a separate history.tkd flawlessly. Usage: tclkit wikit-hist.kit my-wikit.tkd -history internal or tclkit wikit-hist.kit my-wikit.tkd -history /somewhere/history.tkd To access the revision history, you need to run it as a CGI (no internal httpd in this version), you will find that the 'Updated on somedate' at the bottom of each wiki page is now augmented with a ''revision X'' link, click on that and you can get at the diffs. And you also need to set WIKIT_CSS=http://pascal.scheffers.net/pascal.css in your wiki.cgi file to have the colours in the diff show. -- [PS] ---- ''Yes, I'm interested (as you know!). Will have a look, thx. Another comment on Keith's code: it currently diffs against pages in history but not the last one, if it was changed very recently. There is an undocumented feature of this wiki: you can access raw pages as "NNN.txt" (e.g. [http://mini.net/tcl/10335.txt]). -[jcw]''