texbuilder-0.1.3.0: TexBuilder/TexBuilder.hs
module TexBuilder.TexBuilder
( texBuilder
, StatePolicy(..)
, Forced(..)
, UseEngine(..)
, UseLatexMk(..) )
where
import TexBuilder.Utils.File
import TexBuilder.Utils.Inotify
import TexBuilder.Utils.BinSem
import TexBuilder.Utils.Hashing
import TexBuilder.Engine
import TexBuilder.ChooseEngine
import TexBuilder.Watches
import TexBuilder.CompileThread
import TexBuilder.ViewThread
import TexBuilder.FileFilters
import qualified Text.PrettyPrint.ANSI.Leijen as PP
import Control.Applicative
import Control.Monad
import Control.Monad.Extra
-- import Data.Semigroup
import Data.Monoid
import Data.Maybe
import qualified Data.Map as M
import Numeric.Natural
import Options.Applicative
import Options.Applicative.Builder
import System.Directory
import System.FilePath
import System.IO.Temp
import Control.Concurrent
import Control.Concurrent.MVar
data StatePolicy = Pure | Stateful | Persistent
newtype Forced = Forced Bool
texBuilder :: FilePath
-> Maybe FilePath
-> Exts
-> Natural
-> StatePolicy
-> Forced
-> UseEngine
-> UseLatexMk
-> Natural
-> [String]
-> IO ()
texBuilder
texfile mbPdfFile exts depth statePolicy
forced useEngine useLatexmk nrecomp extraArgs
= do
engine <- chooseEngine useEngine useLatexmk
let runRaw = compile engine nrecomp texfile pdffile extraArgs
withModRunAction statePolicy texDir listSrcFiles runRaw
$ \run -> do
assertFileEx texfile
-- ^ Assert that the tex file exists
initialCompile forced pdffile run
-- ^ Do an initial compile run if appropriate
sem <- newBinSem
-- ^ Signaling semaphore connecting the threads
withInitialHashes listSrcFiles $ \hashes -> do
watchMVar <- newEmptyMVar
wtid <- forkIO $
setupWatches depth texDir fileFilter watchMVar
ctid <- forkIO $
compileThread run sem watchMVar hashes
-- ^ The thread which compiles the tex code
onFileEx pdffile ( mupdfView pdffile sem )
-- ^ Enter the main thread which updates the pdf view
putStrLn "mupdf exited, terminating"
killThread wtid
killThread ctid
where
fileFilter = extFilter exts
texDir = takeDirectory texfile
listSrcFiles = listSourceFiles depth texDir fileFilter
pdffile = fromMaybe (texfile -<.> "pdf") mbPdfFile
initialCompile :: Forced -> FilePath -> IO PP.Doc -> IO ()
initialCompile (Forced f) pdffile run
| f = comp "Initial compilation forced, compiling."
| True = unlessM (doesFileExist pdffile)
$ comp "No ouput file detected, compiling."
where
comp msg = putStrLn msg >> run >>= PP.putDoc
listSourceFiles :: Natural
-> FilePath
-> ( FilePath -> Bool )
-> IO [FilePath]
listSourceFiles depth texDir fileFilter =
listSubdirs depth texDir
>>= searchFilesWith fileFilter
withInitialHashes :: IO [FilePath]
-> ( M.Map FilePath (Digest MD5) -> IO b)
-> IO b
withInitialHashes listSrc k = do
files <- listSrc
withHashes files $ k . M.fromList . zip files
withDirSetup :: FilePath
-> FilePath
-> IO [FilePath]
-> ( FilePath -> IO a ) -> IO a
withDirSetup wdir texDir listSrc k = do
files <- listSrc
forM_ files $ copyRelative texDir wdir
k wdir
withModRunAction :: StatePolicy
-> FilePath
-> IO [FilePath]
-> ( FilePath -> IO PP.Doc )
-> ( IO PP.Doc -> IO a ) -> IO a
withModRunAction statePolicy texDir listSrc run k =
case statePolicy of
Pure -> k $ withTmp $ \tmpdir -> runIn tmpdir
-- ^ Create fresh temporary directory every time
Stateful-> withTmp $ \tmpdir -> k $ runIn tmpdir
-- ^ Run in stateful temporary directory
Persistent -> getCurrentDirectory >>= \wdir -> k $ runIn wdir
-- ^ Run in persistent working directory
where
withTmp = withSystemTempDirectory "texbuilder"
runIn wdir = withDirSetup wdir texDir listSrc run