{-# LANGUAGE FlexibleInstances, UndecidableInstances, MultiParamTypeClasses, AllowAmbiguousTypes, OverloadedStrings, BangPatterns #-}

module SMCDEL.Internal.TexDisplay where
import Control.Monad
import Data.List
import Control.Concurrent (threadDelay)
import qualified Data.Text.Lazy as T
import System.Directory (findExecutable)
import System.IO (hGetContents)
import System.IO.Temp
import System.IO.Unsafe (unsafePerformIO)
import System.Process
import Data.GraphViz
import Data.GraphViz.Types.Generalised
import Data.GraphViz.Types.Monadic
import Data.Time.Clock.POSIX

begintab, endtab, newline :: String
begintab :: String
begintab  = String
"\\\\begin{tabular}{c}"
endtab :: String
endtab    = String
"\\\\end{tabular}"
newline :: String
newline   = String
" \\\\\\\\[0pt] "

removeDoubleSpaces :: String -> String
removeDoubleSpaces :: String -> String
removeDoubleSpaces (Char
' ':Char
' ':String
rest) = String -> String
removeDoubleSpaces (Char
' 'Char -> String -> String
forall a. a -> [a] -> [a]
:String
rest)
removeDoubleSpaces (Char
x  : String
xs     ) = Char
x Char -> String -> String
forall a. a -> [a] -> [a]
: String -> String
removeDoubleSpaces String
xs
removeDoubleSpaces [            ] = [ ]

class TexAble a where
  tex :: a -> String
  texTo :: a -> String -> IO ()
  texTo !a
x String
filename = String -> String -> IO ()
writeFile (String
filenameString -> String -> String
forall a. [a] -> [a] -> [a]
++String
".tex") (a -> String
forall a. TexAble a => a -> String
tex a
x)
  texDocumentTo :: a -> String -> IO ()
  texDocumentTo !a
x String
filename =
    String -> String -> IO ()
writeFile (String
filenameString -> String -> String
forall a. [a] -> [a] -> [a]
++String
".tex") (String
pre String -> String -> String
forall a. [a] -> [a] -> [a]
++ a -> String
forall a. TexAble a => a -> String
tex a
x String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
post) where
      pre :: String
pre = [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [ String
"\\documentclass{standalone}"
                   , String
"\\usepackage[utf8]{inputenc}"
                   , String
"\\usepackage{tikz,fontenc,graphicx}"
                   , String
"\\usepackage[pdftex]{hyperref}"
                   , String
"\\hypersetup{pdfborder={0 0 0},breaklinks=true}"
                   , String
"\\begin{document}"
                   ]
      post :: String
post= String
"\\end{document}"
  pdfTo :: a -> String -> IO ()
  pdfTo !a
x String
filename = do
    a -> String -> IO ()
forall a. TexAble a => a -> String -> IO ()
texDocumentTo a
x String
filename
    String -> IO ()
runAndWait (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"cd " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
filename String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"/../; /usr/bin/pdflatex -interaction=nonstopmode "String -> String -> String
forall a. [a] -> [a] -> [a]
++String
filenameString -> String -> String
forall a. [a] -> [a] -> [a]
++String
".tex"
  disp :: a -> IO ()
  disp !a
x = String -> (String -> IO ()) -> IO ()
forall (m :: * -> *) a.
(MonadIO m, MonadMask m) =>
String -> (String -> m a) -> m a
withSystemTempDirectory String
"smcdel" ((String -> IO ()) -> IO ()) -> (String -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \String
tmpdir -> do
    Int
ts <- POSIXTime -> Int
forall b. Integral b => POSIXTime -> b
forall a b. (RealFrac a, Integral b) => a -> b
round (POSIXTime -> Int) -> IO POSIXTime -> IO Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO POSIXTime
getPOSIXTime
    let filename :: String
filename = String
tmpdir String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"/disp-" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show (Int
ts :: Int)
    a -> String -> IO ()
forall a. TexAble a => a -> String -> IO ()
pdfTo a
x String
filename
    String -> IO ()
runIgnoreAndWait (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"open " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
filename String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
".pdf"
    Int -> IO ()
threadDelay Int
5000000 -- give viewer five seconds before deleting tmpdir
  svgViaTex :: a -> String
  svgViaTex !a
x = IO String -> String
forall a. IO a -> a
unsafePerformIO (IO String -> String) -> IO String -> String
forall a b. (a -> b) -> a -> b
$ String -> (String -> IO String) -> IO String
forall (m :: * -> *) a.
(MonadIO m, MonadMask m) =>
String -> (String -> m a) -> m a
withSystemTempDirectory String
"smcdel" ((String -> IO String) -> IO String)
-> (String -> IO String) -> IO String
forall a b. (a -> b) -> a -> b
$ \String
tmpdir -> do
    Int
ts <- POSIXTime -> Int
forall b. Integral b => POSIXTime -> b
forall a b. (RealFrac a, Integral b) => a -> b
round (POSIXTime -> Int) -> IO POSIXTime -> IO Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO POSIXTime
getPOSIXTime
    let filename :: String
filename = String
tmpdir String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"/svgViaTex-" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show (Int
ts :: Int)
    a -> String -> IO ()
forall a. TexAble a => a -> String -> IO ()
pdfTo a
x String
filename
    String -> IO ()
runAndWait (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"pdftocairo -nocrop -svg "String -> String -> String
forall a. [a] -> [a] -> [a]
++String
filenameString -> String -> String
forall a. [a] -> [a] -> [a]
++String
".pdf "String -> String -> String
forall a. [a] -> [a] -> [a]
++String
filenameString -> String -> String
forall a. [a] -> [a] -> [a]
++String
".svg"
    String -> IO String
readFile (String
filename String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
".svg")

instance TexAble String where
  tex :: String -> String
tex String
i = String
" \\text{" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
i String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"} "

instance TexAble Int where
  tex :: Int -> String
tex = Int -> String
forall a. Show a => a -> String
show

-- | TeXing assignments as sets
instance TexAble a => TexAble [(a,Bool)] where
  tex :: [(a, Bool)] -> String
tex [(a, Bool)]
ass = case ((a, Bool) -> Bool) -> [(a, Bool)] -> [(a, Bool)]
forall a. (a -> Bool) -> [a] -> [a]
filter (a, Bool) -> Bool
forall a b. (a, b) -> b
snd [(a, Bool)]
ass of
    [] -> String
""
    [(a, Bool)]
ps -> String
"$" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
"," (((a, Bool) -> String) -> [(a, Bool)] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (a -> String
forall a. TexAble a => a -> String
tex(a -> String) -> ((a, Bool) -> a) -> (a, Bool) -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(a, Bool) -> a
forall a b. (a, b) -> a
fst) [(a, Bool)]
ps) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"$"

runAndWait :: String -> IO ()
runAndWait :: String -> IO ()
runAndWait String
command = do
  (Handle
_inp,Handle
_out,Handle
err,ProcessHandle
pid) <- String -> IO (Handle, Handle, Handle, ProcessHandle)
runInteractiveCommand String
command
  ExitCode
_ <- ProcessHandle -> IO ExitCode
waitForProcess ProcessHandle
pid
  Handle -> IO String
hGetContents Handle
err IO String -> (String -> IO ()) -> IO ()
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (\String
x -> Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (String -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
x) (String -> IO ()
putStrLn String
x))
  () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()

runIgnoreAndWait :: String -> IO ()
runIgnoreAndWait :: String -> IO ()
runIgnoreAndWait String
command = do
  (Handle
_inp,Handle
_out,Handle
_err,ProcessHandle
pid) <- String -> IO (Handle, Handle, Handle, ProcessHandle)
runInteractiveCommand String
command
  ExitCode
_ <- ProcessHandle -> IO ExitCode
waitForProcess ProcessHandle
pid
  () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()

class KripkeLike a where
  getNodes :: a -> [(String,String)] -- nid,nlabel
  getEdges :: a -> [(String,String,String)] -- elabel,from,to
  getActuals :: a -> [String] -- nid
  getActuals = [String] -> a -> [String]
forall a b. a -> b -> a
const []
  directed :: a -> Bool
  directed = Bool -> a -> Bool
forall a b. a -> b -> a
const Bool
True
  nodeAts :: a -> Bool -> Attributes
  nodeAts a
_ Bool
True  = [Shape -> Attribute
shape Shape
DoubleCircle]
  nodeAts a
_ Bool
False = [Shape -> Attribute
shape Shape
Circle]
  toGraph :: a -> Data.GraphViz.Types.Generalised.DotGraph String
  toGraph a
x = (if a -> Bool
forall a. KripkeLike a => a -> Bool
directed a
x then DotM String () -> DotGraph String
forall n a. DotM n a -> DotGraph n
digraph' else DotM String () -> DotGraph String
forall n a. DotM n a -> DotGraph n
graph') (DotM String () -> DotGraph String)
-> DotM String () -> DotGraph String
forall a b. (a -> b) -> a -> b
$ do
    let nodes :: [(String, String)]
nodes = a -> [(String, String)]
forall a. KripkeLike a => a -> [(String, String)]
getNodes a
x
    let actuals :: [(String, String)]
actuals = ((String, String) -> Bool)
-> [(String, String)] -> [(String, String)]
forall a. (a -> Bool) -> [a] -> [a]
filter (\(String, String)
n -> (String, String) -> String
forall a b. (a, b) -> a
fst (String, String)
n String -> [String] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` a -> [String]
forall a. KripkeLike a => a -> [String]
getActuals a
x) [(String, String)]
nodes
    ((String, String) -> DotM String ())
-> [(String, String)] -> DotM String ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_
      (\(String
nid,String
nlabel) -> String -> Attributes -> DotM String ()
forall n. n -> Attributes -> Dot n
node String
nid (String -> Attribute
forall a. Labellable a => a -> Attribute
toLabel String
nlabel Attribute -> Attributes -> Attributes
forall a. a -> [a] -> [a]
: a -> Bool -> Attributes
forall a. KripkeLike a => a -> Bool -> Attributes
nodeAts a
x Bool
True))
      [(String, String)]
actuals
    ((String, String) -> DotM String ())
-> [(String, String)] -> DotM String ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_
      (\(String
nid,String
nlabel) -> String -> Attributes -> DotM String ()
forall n. n -> Attributes -> Dot n
node String
nid (String -> Attribute
forall a. Labellable a => a -> Attribute
toLabel String
nlabel Attribute -> Attributes -> Attributes
forall a. a -> [a] -> [a]
: a -> Bool -> Attributes
forall a. KripkeLike a => a -> Bool -> Attributes
nodeAts a
x Bool
False))
      ([(String, String)]
nodes [(String, String)] -> [(String, String)] -> [(String, String)]
forall a. Eq a => [a] -> [a] -> [a]
\\ [(String, String)]
actuals)
    ((String, String, String) -> DotM String ())
-> [(String, String, String)] -> DotM String ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_
      (\(String
elabel,String
from,String
to) -> String -> String -> Attributes -> DotM String ()
forall n. n -> n -> Attributes -> Dot n
edge String
from String
to [String -> Attribute
forall a. Labellable a => a -> Attribute
toLabel String
elabel])
      (a -> [(String, String, String)]
forall a. KripkeLike a => a -> [(String, String, String)]
getEdges a
x)
  dispDot :: a -> IO ()
  dispDot a
x = GraphvizCommand -> DotGraph String -> GraphvizCanvas -> IO ()
forall (dg :: * -> *) n.
PrintDotRepr dg n =>
GraphvizCommand -> dg n -> GraphvizCanvas -> IO ()
runGraphvizCanvas GraphvizCommand
Dot (a -> DotGraph String
forall a. KripkeLike a => a -> DotGraph String
toGraph a
x) GraphvizCanvas
Xlib
  textDot :: a -> T.Text
  textDot = Text -> [Text] -> Text
T.intercalate Text
" " ([Text] -> Text) -> (a -> [Text]) -> a -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> [Text]
T.lines (Text -> [Text]) -> (a -> Text) -> a -> [Text]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. DotGraph String -> Text
forall (dg :: * -> *) n. PrintDotRepr dg n => dg n -> Text
printDotGraph (DotGraph String -> Text) -> (a -> DotGraph String) -> a -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> DotGraph String
forall a. KripkeLike a => a -> DotGraph String
toGraph
  svg :: a -> String
  svg a
x = IO String -> String
forall a. IO a -> a
unsafePerformIO (IO String -> String) -> IO String -> String
forall a b. (a -> b) -> a -> b
$
    String -> (String -> IO String) -> IO String
forall (m :: * -> *) a.
(MonadIO m, MonadMask m) =>
String -> (String -> m a) -> m a
withSystemTempDirectory String
"smcdel" ((String -> IO String) -> IO String)
-> (String -> IO String) -> IO String
forall a b. (a -> b) -> a -> b
$ \String
tmpdir -> do
      String
_ <- GraphvizCommand
-> DotGraph String -> GraphvizOutput -> String -> IO String
forall (dg :: * -> *) n.
PrintDotRepr dg n =>
GraphvizCommand -> dg n -> GraphvizOutput -> String -> IO String
runGraphvizCommand GraphvizCommand
Dot (a -> DotGraph String
forall a. KripkeLike a => a -> DotGraph String
toGraph a
x) GraphvizOutput
Svg (String
tmpdir String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"/temp.svg")
      String -> IO String
readFile (String
tmpdir String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"/temp.svg")

newtype ViaDot a = ViaDot a
  deriving (ViaDot a -> ViaDot a -> Bool
(ViaDot a -> ViaDot a -> Bool)
-> (ViaDot a -> ViaDot a -> Bool) -> Eq (ViaDot a)
forall a. Eq a => ViaDot a -> ViaDot a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: forall a. Eq a => ViaDot a -> ViaDot a -> Bool
== :: ViaDot a -> ViaDot a -> Bool
$c/= :: forall a. Eq a => ViaDot a -> ViaDot a -> Bool
/= :: ViaDot a -> ViaDot a -> Bool
Eq,Eq (ViaDot a)
Eq (ViaDot a) =>
(ViaDot a -> ViaDot a -> Ordering)
-> (ViaDot a -> ViaDot a -> Bool)
-> (ViaDot a -> ViaDot a -> Bool)
-> (ViaDot a -> ViaDot a -> Bool)
-> (ViaDot a -> ViaDot a -> Bool)
-> (ViaDot a -> ViaDot a -> ViaDot a)
-> (ViaDot a -> ViaDot a -> ViaDot a)
-> Ord (ViaDot a)
ViaDot a -> ViaDot a -> Bool
ViaDot a -> ViaDot a -> Ordering
ViaDot a -> ViaDot a -> ViaDot a
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall a. Ord a => Eq (ViaDot a)
forall a. Ord a => ViaDot a -> ViaDot a -> Bool
forall a. Ord a => ViaDot a -> ViaDot a -> Ordering
forall a. Ord a => ViaDot a -> ViaDot a -> ViaDot a
$ccompare :: forall a. Ord a => ViaDot a -> ViaDot a -> Ordering
compare :: ViaDot a -> ViaDot a -> Ordering
$c< :: forall a. Ord a => ViaDot a -> ViaDot a -> Bool
< :: ViaDot a -> ViaDot a -> Bool
$c<= :: forall a. Ord a => ViaDot a -> ViaDot a -> Bool
<= :: ViaDot a -> ViaDot a -> Bool
$c> :: forall a. Ord a => ViaDot a -> ViaDot a -> Bool
> :: ViaDot a -> ViaDot a -> Bool
$c>= :: forall a. Ord a => ViaDot a -> ViaDot a -> Bool
>= :: ViaDot a -> ViaDot a -> Bool
$cmax :: forall a. Ord a => ViaDot a -> ViaDot a -> ViaDot a
max :: ViaDot a -> ViaDot a -> ViaDot a
$cmin :: forall a. Ord a => ViaDot a -> ViaDot a -> ViaDot a
min :: ViaDot a -> ViaDot a -> ViaDot a
Ord,Int -> ViaDot a -> String -> String
[ViaDot a] -> String -> String
ViaDot a -> String
(Int -> ViaDot a -> String -> String)
-> (ViaDot a -> String)
-> ([ViaDot a] -> String -> String)
-> Show (ViaDot a)
forall a. Show a => Int -> ViaDot a -> String -> String
forall a. Show a => [ViaDot a] -> String -> String
forall a. Show a => ViaDot a -> String
forall a.
(Int -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
$cshowsPrec :: forall a. Show a => Int -> ViaDot a -> String -> String
showsPrec :: Int -> ViaDot a -> String -> String
$cshow :: forall a. Show a => ViaDot a -> String
show :: ViaDot a -> String
$cshowList :: forall a. Show a => [ViaDot a] -> String -> String
showList :: [ViaDot a] -> String -> String
Show)

dot2tex :: String -> IO ()
dot2tex :: String -> IO ()
dot2tex String
args = do
  Maybe String
haveDot2tex <- String -> IO (Maybe String)
findExecutable String
"dot2tex"
  case Maybe String
haveDot2tex of
    Maybe String
Nothing -> String -> IO ()
forall a. HasCallStack => String -> a
error String
"Please install dot2tex which is needed to show this."
    Just String
d2t -> String -> IO ()
runAndWait (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
d2t String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
args

dot2texDefaultArgs :: String
dot2texDefaultArgs :: String
dot2texDefaultArgs = String
" -ftikz -traw -p --autosize -w --usepdflatex "

instance (Ord a, Show a, KripkeLike a) => TexAble (ViaDot a) where
  tex :: ViaDot a -> String
tex (ViaDot a
x) = IO String -> String
forall a. IO a -> a
unsafePerformIO (IO String -> String) -> IO String -> String
forall a b. (a -> b) -> a -> b
$
    String -> (String -> IO String) -> IO String
forall (m :: * -> *) a.
(MonadIO m, MonadMask m) =>
String -> (String -> m a) -> m a
withSystemTempDirectory String
"smcdel" ((String -> IO String) -> IO String)
-> (String -> IO String) -> IO String
forall a b. (a -> b) -> a -> b
$ \String
tmpdir -> do
      String
_ <- DotGraph String -> GraphvizOutput -> String -> IO String
forall (dg :: * -> *) n.
PrintDotRepr dg n =>
dg n -> GraphvizOutput -> String -> IO String
runGraphviz (a -> DotGraph String
forall a. KripkeLike a => a -> DotGraph String
toGraph a
x) GraphvizOutput
DotOutput (String
tmpdir String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"/temp.dot")
      String -> IO ()
dot2tex (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
dot2texDefaultArgs String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" --figonly " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
tmpdir String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"/temp.dot | sed '/^$/d' > " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
tmpdir String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"/temp.tex;"
      String -> IO String
readFile (String
tmpdir String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"/temp.tex")
  texTo :: ViaDot a -> String -> IO ()
texTo (ViaDot a
x) String
filename = do
    String
_ <- DotGraph String -> GraphvizOutput -> String -> IO String
forall (dg :: * -> *) n.
PrintDotRepr dg n =>
dg n -> GraphvizOutput -> String -> IO String
runGraphviz (a -> DotGraph String
forall a. KripkeLike a => a -> DotGraph String
toGraph a
x) GraphvizOutput
DotOutput (String
filename String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
".dot")
    String -> IO ()
dot2tex (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
dot2texDefaultArgs String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" --figonly " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
filename String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
".dot | sed '/^$/d' > " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
filename String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
".tex;"
  texDocumentTo :: ViaDot a -> String -> IO ()
texDocumentTo (ViaDot a
x) String
filename = do
    String
_ <- DotGraph String -> GraphvizOutput -> String -> IO String
forall (dg :: * -> *) n.
PrintDotRepr dg n =>
dg n -> GraphvizOutput -> String -> IO String
runGraphviz (a -> DotGraph String
forall a. KripkeLike a => a -> DotGraph String
toGraph a
x) GraphvizOutput
DotOutput (String
filename String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
".dot")
    String -> IO ()
dot2tex (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
dot2texDefaultArgs String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
filename String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
".dot -o " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
filename String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
".tex;"