Index: src/dirdiff.tcl ================================================================== --- src/dirdiff.tcl +++ src/dirdiff.tcl @@ -1364,10 +1364,16 @@ if {$rev2 ne ""} { .dirdiffX.l2 configure -text "and rev $rev2..." update set d2 [eskil::rev::${type}::mount $fullname $rev2] set ::dirdiff(rightDir) $d2 + } + # VcsVfs mounts are thread local. Transfer them to any worker thread + foreach tid $::eskil(threads) { + .dirdiffX.l2 configure -text "and rev $rev2... (+thread)" + update + vcsvfs::transfer $tid } destroy .dirdiffX } } Index: src/eskil.syntax ================================================================== --- src/eskil.syntax +++ src/eskil.syntax @@ -41,10 +41,17 @@ ##nagelfar syntax vfs::filesystem\ posixerror x ##nagelfar syntax vfs::matchDirectories x ##nagelfar syntax vfs::matchFiles x ##nagelfar syntax vfs::accessMode x ##nagelfar package known vfs + +##nagelfar syntax thread::create o* +##nagelfar syntax thread::send x x* +##nagelfar package known Thread + +##nagelfar syntax starkit::startup 0 +##nagelfar package known starkit ##nagelfar syntax pdf4tcl::getPaperSize x ##nagelfar syntax pdf4tcl::getPaperSizeList ##nagelfar syntax pdf4tcl::loadBaseType1Font 3 ##nagelfar syntax pdf4tcl::loadBaseTrueTypeFont r 2 3 Index: src/eskil.tcl ================================================================== --- src/eskil.tcl +++ src/eskil.tcl @@ -1462,12 +1462,12 @@ set dFile2 $::eskil($top,rightFileDiff) } else { set dFile2 $::eskil($top,rightFile) } - set differr [catch {DiffUtil::diffFiles {*}$opts \ - $dFile1 $dFile2} diffres] + set cmd [list DiffUtil::diffFiles {*}$opts $dFile1 $dFile2] + set differr [catch {SubEval $cmd} 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 {$::eskil($top,mode) eq "conflict" && $::eskil($top,modetype) eq "Pure"} { @@ -2945,10 +2945,11 @@ } # Runtime disable of C version of DiffUtil proc DisableDiffUtilC {} { uplevel \#0 [list source $::eskil(thisDir)/../lib/diffutil/tcl/diffutil.tcl] + SubEval [list source $::eskil(thisDir)/../lib/diffutil/tcl/diffutil.tcl] } # Add a debug menu to a toplevel window proc AddDebugMenu {top} { set dMenu [DebugMenu $top.m] Index: src/help.tcl ================================================================== --- src/help.tcl +++ src/help.tcl @@ -56,10 +56,14 @@ $w.t insert end "\nTcl version: [info patchlevel]\n" set du $::DiffUtil::version append du " ($::DiffUtil::implementation)" $w.t insert end "DiffUtil version: $du\n" + + set du [SubEval {set ::DiffUtil::version}] + append du " ([SubEval {set ::DiffUtil::implementation}])" + $w.t insert end "(sub) DiffUtil version: $du\n" # Provide debug info to help when DiffUtil does not load. if {[info exists ::DiffUtil::DebugLibFile]} { set lf $::DiffUtil::DebugLibFile set exist [file exists $lf] Index: src/rev.tcl ================================================================== --- src/rev.tcl +++ src/rev.tcl @@ -1227,29 +1227,37 @@ if {$sts} { tk_messageBox -icon error -title "GIT revert error" -message $gitmsg \ -parent $top } } + +# Common helper function to handle the mount command +proc eskil::rev::mount {args} { + set res [{*}$args] + # Also mount it in the sub interpreter, unless it is already there + SubEval [list if "!\[[list file isdir $res]\]" $args] + return $res +} # Mount a directory revision as a VFS, and return the mount point proc eskil::rev::FOSSIL::mount {dir rev} { - return [vcsvfs::fossil::mount $dir $rev] + return [eskil::rev::mount vcsvfs::fossil::mount $dir $rev] } # Mount a directory revision as a VFS, and return the mount point proc eskil::rev::SVN::mount {dir rev} { - return [vcsvfs::svn::mount $dir $rev] + return [eskil::rev::mount vcsvfs::svn::mount $dir $rev] } # Mount a directory revision as a VFS, and return the mount point proc eskil::rev::HG::mount {dir rev} { - return [vcsvfs::hg::mount $dir $rev] + return [eskil::rev::mount vcsvfs::hg::mount $dir $rev] } # Mount a directory revision as a VFS, and return the mount point proc eskil::rev::GIT::mount {dir rev} { - return [vcsvfs::git::mount $dir $rev] + return [eskil::rev::mount vcsvfs::git::mount $dir $rev] } # View log between displayed versions proc eskil::rev::CVS::viewLog {top filename revs} { set cmd [list exec cvs -q log -N] Index: src/startup.tcl ================================================================== --- src/startup.tcl +++ src/startup.tcl @@ -79,18 +79,44 @@ if {[file exists $::eskil(thisDir)/../version.txt]} { set ch [open $::eskil(thisDir)/../version.txt] set ::eskil(diffver) [string trim [read $ch 100]] close $ch } + + ##nagelfar syntax SubEval c + set ::eskil(threads) {} + if {[catch {package require Thread}]} { + interp create _tinterp_ + interp alias {} SubEval _tinterp_ eval + } else { + set tid [thread::create -preserved] + interp alias {} SubEval {} thread::send $tid + lappend ::eskil(threads) $tid + } + SubEval [list set ::auto_path $::auto_path] + SubEval [list set ::argv0 $::argv0] + SubEval [list namespace eval ::starkit {}] + SubEval [list set ::starkit::topdir $::starkit::topdir] + SubEval { + if {![file isdir $::starkit::topdir]} { + vfs::mk4::Mount $::starkit::topdir $::starkit::topdir + } + } + SubEval [list array set ::eskil [array get ::eskil]] + SubEval [list proc InitReSource {} [info body InitReSource]] + SubEval {package require snit} + SubEval {InitReSource} # Get all other source files InitReSource # Diff functionality is in the DiffUtil package. package require DiffUtil + SubEval {package require DiffUtil} # Help DiffUtil to find a diff executable, if needed catch {DiffUtil::LocateDiffExe $::eskil(thisScript)} + SubEval [list catch [list DiffUtil::LocateDiffExe $::eskil(thisScript)]] # Create font for PDF if {$::Pref(printFont) eq ""} { set fontfile $::eskil(thisDir)/embedfont.ttf } else { Index: src/vcsvfs.tcl ================================================================== --- src/vcsvfs.tcl +++ src/vcsvfs.tcl @@ -1,15 +1,15 @@ #---------------------------------------------------------------------- # Virtual File System for Version Control Systems # -# Copyright (c) 2014-2015, Peter Spjuth +# Copyright (c) 2014-2016, Peter Spjuth # # License for vcsvfs package: Same as for Tcl #---------------------------------------------------------------------- package require vfs -package provide vcsvfs 0.2 +package provide vcsvfs 0.3 namespace eval vcsvfs { variable DataRefChan variable mpoints {} namespace eval fossil {} @@ -749,10 +749,42 @@ } } vfs::filesystem posixerror $::vfs::posix(EACCES) return -code error $::vfs::posix(EACCES) } + +# Transfer VcsVfs mount point(s) to another Thread. +# TclVfs (which VcsVfs is based on) mounts are thread local +# +# threadId: Thread id as created by Thread package +# mountpoint: Mount point to transfer. +# If no mount point is given, tranfer all current mount points +# +# Returns: None +proc vcsvfs::transfer {threadId {mountpoint {}}} { + variable mpoints + thread::send -async $threadId "package require vcsvfs" + if {$mountpoint eq ""} { + set data $mpoints + } else { + set data [dict create $mountpoint [dict get $mpoints $mountpoint]] + } + # Data might be large. Is that a problem? Is there a more efficient way? + thread::send -async $threadId [list vcsvfs::Receive $data] +} + +# Create mount(s) from received data +proc vcsvfs::Receive {data} { + variable mpoints + foreach mountpoint [dict keys $data] { + # Avoid duplicates + if {![dict exists $mpoints $mountpoint]} { + dict set mpoints $mountpoint [dict get $data $mountpoint] + vfs::filesystem mount $mountpoint [list vcsvfs::Vfs] + } + } +} ################################################################## # Test structure ################################################################## if 0 {