{-# LANGUAGE MultiParamTypeClasses, OverloadedStrings #-}

{- |
   Module      : Data.GraphViz.Commands
   Description : Functions to run Graphviz commands.
   Copyright   : (c) Matthew Sackman, Ivan Lazar Miljenovic
   License     : 3-Clause BSD-style
   Maintainer  : Ivan.Miljenovic@gmail.com

   This module defines functions to call the various Graphviz
   commands.

   Whilst various output formats are supported (see 'GraphvizOutput'
   for a complete list), it is not yet possible to choose a desired
   renderer and formatter.  Being able to determine which renderers
   and formatters are applicable for a specific 'GraphvizOutput' is
   not easy (there is no listing of available renderers or formatters
   on the Graphviz website), and for the most part the default ones do
   the job well.

   Please note that for 'GraphvizOutput' and 'GraphvizCanvas', you
   will see that they are instances of a @GraphvizResult@ class; this is
   an internal class that should not be visible outside this module, but
   Haddock is being too helpful for its own good.
-}
module Data.GraphViz.Commands
    ( -- * The different Graphviz tools available.
      GraphvizCommand(..)
    , dirCommand
    , undirCommand
    , commandFor
      -- * The possible outputs that Graphviz supports.
      -- $outputs
    , GraphvizOutput(..)
    , GraphvizCanvas(..)
      -- * Running Graphviz.
    , runGraphviz
    , runGraphvizCommand
    , addExtension
    , runGraphvizCanvas
    , runGraphvizCanvas'
    , graphvizWithHandle
      -- * Testing if Graphviz is installed
    , isGraphvizInstalled
    , quitWithoutGraphviz
    ) where

import Data.GraphViz.Types
-- This is here just for Haddock linking purposes.
import Data.GraphViz.Commands.Available
import Data.GraphViz.Commands.IO        (runCommand)
import Data.GraphViz.Exception

import           Control.Monad    (liftM, unless)
import qualified Data.ByteString  as SB
import           Data.Maybe       (isJust)
import           Data.Version     (Version (..), showVersion)
import           System.Directory (findExecutable)
import           System.Exit      (ExitCode (..), exitWith)
import           System.FilePath  ((<.>))
import           System.IO        (Handle, hPutStrLn, hSetBinaryMode, stderr)

-- -----------------------------------------------------------------------------

showCmd           :: GraphvizCommand -> String
showCmd :: GraphvizCommand -> String
showCmd GraphvizCommand
Dot       = String
"dot"
showCmd GraphvizCommand
Neato     = String
"neato"
showCmd GraphvizCommand
TwoPi     = String
"twopi"
showCmd GraphvizCommand
Circo     = String
"circo"
showCmd GraphvizCommand
Fdp       = String
"fdp"
showCmd GraphvizCommand
Sfdp      = String
"sfdp"
showCmd GraphvizCommand
Osage     = String
"osage"
showCmd GraphvizCommand
Patchwork = String
"patchwork"

-- | The default command for directed graphs.
dirCommand :: GraphvizCommand
dirCommand :: GraphvizCommand
dirCommand = GraphvizCommand
Dot

-- | The default command for undirected graphs.
undirCommand :: GraphvizCommand
undirCommand :: GraphvizCommand
undirCommand = GraphvizCommand
Neato

-- | The appropriate (default) Graphviz command for the given graph.
commandFor    :: (DotRepr dg n) => dg n -> GraphvizCommand
commandFor :: forall (dg :: * -> *) n. DotRepr dg n => dg n -> GraphvizCommand
commandFor dg n
dg = if forall (dg :: * -> *) n. DotRepr dg n => dg n -> Bool
graphIsDirected dg n
dg
                then GraphvizCommand
dirCommand
                else GraphvizCommand
undirCommand

-- -----------------------------------------------------------------------------

{- $outputs

   The list of output types supported by Graphviz is dependent upon
   how it is built on your system.  To determine which actual formats
   are available on your system, run @dot -T?@.  Trying to use an
   output type that is not supported by your installation of Graphviz
   will result in an error.

   The outputs defined here in 'GraphvizOutput' and 'GraphvizCanvas'
   are those from the default list of available outputs.  For more
   information, see:
     <http://graphviz.org/doc/info/output.html>

-}

-- | This class is for those data types that are valid options for the
--   Graphviz tools to use with the @-T@ argument.
class GraphvizResult o where
  outputCall :: o -> String

-- | The possible Graphviz output formats (that is, those that
--   actually produce a file).
data GraphvizOutput = Bmp       -- ^ Windows Bitmap Format.
                    | Canon     -- ^ Pretty-printed Dot output with no
                                --   layout performed.
                    | DotOutput -- ^ Reproduces the input along with
                                --   layout information.
                    | XDot (Maybe Version)
                      -- ^ As with 'DotOutput', but provides even more
                      --   information on how the graph is drawn.  The
                      --   optional 'Version' is the same as
                      --   specifying the @XDotVersion@ attribute.
                    | Eps       -- ^ Encapsulated PostScript.
                    | Fig       -- ^ FIG graphics language.
                    | Gd        -- ^ Internal GD library format.
                    | Gd2       -- ^ Compressed version of 'Gd'.
                    | Gif       -- ^ Graphics Interchange Format.
                    | Ico       -- ^ Icon image file format.
                    | Imap      -- ^ Server-side imagemap.
                    | Cmapx     -- ^ Client-side imagemap.
                    | ImapNP    -- ^ As for 'Imap', except only
                                --   rectangles are used as active
                                --   areas.
                    | CmapxNP   -- ^ As for 'Cmapx', except only
                                --   rectangles are used as active
                                --   areas.
                    | Jpeg      -- ^ The JPEG image format.
                    | Pdf       -- ^ Portable Document Format.
                    | Plain     -- ^ Simple text format.
                    | PlainExt  -- ^ As for 'Plain', but provides port
                                --   names on head and tail nodes when
                                --   applicable.
                    | Png       -- ^ Portable Network Graphics format.
                    | Ps        -- ^ PostScript.
                    | Ps2       -- ^ PostScript for PDF.
                    | Svg       -- ^ Scalable Vector Graphics format.
                    | SvgZ      -- ^ Compressed SVG format.
                    | Tiff      -- ^ Tagged Image File Format.
                    | Vml       -- ^ Vector Markup Language; 'Svg' is
                                --   usually preferred.
                    | VmlZ      -- ^ Compressed VML format; 'SvgZ' is
                                --   usually preferred.
                    | Vrml      -- ^ Virtual Reality Modeling Language
                                --   format; requires nodes to have a
                                --   third dimension set via the @Pos@
                                --   attribute (and with a @Dim@ value
                                --   of at least @3@).
                    | WBmp      -- ^ Wireless BitMap format;
                                --   monochrome format usually used
                                --   for mobile computing devices.
                    | WebP      -- ^ Google's WebP format; requires
                                --   Graphviz >= 2.29.0.
                    deriving (GraphvizOutput -> GraphvizOutput -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: GraphvizOutput -> GraphvizOutput -> Bool
$c/= :: GraphvizOutput -> GraphvizOutput -> Bool
== :: GraphvizOutput -> GraphvizOutput -> Bool
$c== :: GraphvizOutput -> GraphvizOutput -> Bool
Eq, Eq GraphvizOutput
GraphvizOutput -> GraphvizOutput -> Bool
GraphvizOutput -> GraphvizOutput -> Ordering
GraphvizOutput -> GraphvizOutput -> GraphvizOutput
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
min :: GraphvizOutput -> GraphvizOutput -> GraphvizOutput
$cmin :: GraphvizOutput -> GraphvizOutput -> GraphvizOutput
max :: GraphvizOutput -> GraphvizOutput -> GraphvizOutput
$cmax :: GraphvizOutput -> GraphvizOutput -> GraphvizOutput
>= :: GraphvizOutput -> GraphvizOutput -> Bool
$c>= :: GraphvizOutput -> GraphvizOutput -> Bool
> :: GraphvizOutput -> GraphvizOutput -> Bool
$c> :: GraphvizOutput -> GraphvizOutput -> Bool
<= :: GraphvizOutput -> GraphvizOutput -> Bool
$c<= :: GraphvizOutput -> GraphvizOutput -> Bool
< :: GraphvizOutput -> GraphvizOutput -> Bool
$c< :: GraphvizOutput -> GraphvizOutput -> Bool
compare :: GraphvizOutput -> GraphvizOutput -> Ordering
$ccompare :: GraphvizOutput -> GraphvizOutput -> Ordering
Ord, Int -> GraphvizOutput -> ShowS
[GraphvizOutput] -> ShowS
GraphvizOutput -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [GraphvizOutput] -> ShowS
$cshowList :: [GraphvizOutput] -> ShowS
show :: GraphvizOutput -> String
$cshow :: GraphvizOutput -> String
showsPrec :: Int -> GraphvizOutput -> ShowS
$cshowsPrec :: Int -> GraphvizOutput -> ShowS
Show, ReadPrec [GraphvizOutput]
ReadPrec GraphvizOutput
Int -> ReadS GraphvizOutput
ReadS [GraphvizOutput]
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [GraphvizOutput]
$creadListPrec :: ReadPrec [GraphvizOutput]
readPrec :: ReadPrec GraphvizOutput
$creadPrec :: ReadPrec GraphvizOutput
readList :: ReadS [GraphvizOutput]
$creadList :: ReadS [GraphvizOutput]
readsPrec :: Int -> ReadS GraphvizOutput
$creadsPrec :: Int -> ReadS GraphvizOutput
Read)

instance GraphvizResult GraphvizOutput where
  outputCall :: GraphvizOutput -> String
outputCall GraphvizOutput
Bmp       = String
"bmp"
  outputCall GraphvizOutput
Canon     = String
"canon"
  outputCall GraphvizOutput
DotOutput = String
"dot"
  outputCall (XDot Maybe Version
mv) = String
"xdot" forall a. [a] -> [a] -> [a]
++ forall b a. b -> (a -> b) -> Maybe a -> b
maybe String
"" Version -> String
showVersion Maybe Version
mv
  outputCall GraphvizOutput
Eps       = String
"eps"
  outputCall GraphvizOutput
Fig       = String
"fig"
  outputCall GraphvizOutput
Gd        = String
"gd"
  outputCall GraphvizOutput
Gd2       = String
"gd2"
  outputCall GraphvizOutput
Gif       = String
"gif"
  outputCall GraphvizOutput
Ico       = String
"ico"
  outputCall GraphvizOutput
Imap      = String
"imap"
  outputCall GraphvizOutput
Cmapx     = String
"cmapx"
  outputCall GraphvizOutput
ImapNP    = String
"imap_np"
  outputCall GraphvizOutput
CmapxNP   = String
"cmapx_np"
  outputCall GraphvizOutput
Jpeg      = String
"jpeg"
  outputCall GraphvizOutput
Pdf       = String
"pdf"
  outputCall GraphvizOutput
Plain     = String
"plain"
  outputCall GraphvizOutput
PlainExt  = String
"plain-ext"
  outputCall GraphvizOutput
Png       = String
"png"
  outputCall GraphvizOutput
Ps        = String
"ps"
  outputCall GraphvizOutput
Ps2       = String
"ps2"
  outputCall GraphvizOutput
Svg       = String
"svg"
  outputCall GraphvizOutput
SvgZ      = String
"svgz"
  outputCall GraphvizOutput
Tiff      = String
"tiff"
  outputCall GraphvizOutput
Vml       = String
"vml"
  outputCall GraphvizOutput
VmlZ      = String
"vmlz"
  outputCall GraphvizOutput
Vrml      = String
"vrml"
  outputCall GraphvizOutput
WBmp      = String
"wbmp"
  outputCall GraphvizOutput
WebP      = String
"webp"

-- | A default file extension for each 'GraphvizOutput'.
defaultExtension           :: GraphvizOutput -> String
defaultExtension :: GraphvizOutput -> String
defaultExtension GraphvizOutput
Bmp       = String
"bmp"
defaultExtension GraphvizOutput
Canon     = String
"gv"
defaultExtension GraphvizOutput
DotOutput = String
"gv"
defaultExtension XDot{}    = String
"gv"
defaultExtension GraphvizOutput
Eps       = String
"eps"
defaultExtension GraphvizOutput
Fig       = String
"fig"
defaultExtension GraphvizOutput
Gd        = String
"gd"
defaultExtension GraphvizOutput
Gd2       = String
"gd2"
defaultExtension GraphvizOutput
Gif       = String
"gif"
defaultExtension GraphvizOutput
Ico       = String
"ico"
defaultExtension GraphvizOutput
Imap      = String
"map"
defaultExtension GraphvizOutput
Cmapx     = String
"map"
defaultExtension GraphvizOutput
ImapNP    = String
"map"
defaultExtension GraphvizOutput
CmapxNP   = String
"map"
defaultExtension GraphvizOutput
Jpeg      = String
"jpg"
defaultExtension GraphvizOutput
Pdf       = String
"pdf"
defaultExtension GraphvizOutput
Plain     = String
"txt"
defaultExtension GraphvizOutput
PlainExt  = String
"txt"
defaultExtension GraphvizOutput
Png       = String
"png"
defaultExtension GraphvizOutput
Ps        = String
"ps"
defaultExtension GraphvizOutput
Ps2       = String
"ps"
defaultExtension GraphvizOutput
Svg       = String
"svg"
defaultExtension GraphvizOutput
SvgZ      = String
"svgz"
defaultExtension GraphvizOutput
Tiff      = String
"tif"
defaultExtension GraphvizOutput
Vml       = String
"vml"
defaultExtension GraphvizOutput
VmlZ      = String
"vmlz"
defaultExtension GraphvizOutput
Vrml      = String
"vrml"
defaultExtension GraphvizOutput
WBmp      = String
"wbmp"
defaultExtension GraphvizOutput
WebP      = String
"webp"

-- | Unlike 'GraphvizOutput', these items do not produce an output
--   file; instead, they directly draw a canvas (i.e. a window) with
--   the resulting image.
data GraphvizCanvas = Gtk | Xlib
                    deriving (GraphvizCanvas -> GraphvizCanvas -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: GraphvizCanvas -> GraphvizCanvas -> Bool
$c/= :: GraphvizCanvas -> GraphvizCanvas -> Bool
== :: GraphvizCanvas -> GraphvizCanvas -> Bool
$c== :: GraphvizCanvas -> GraphvizCanvas -> Bool
Eq, Eq GraphvizCanvas
GraphvizCanvas -> GraphvizCanvas -> Bool
GraphvizCanvas -> GraphvizCanvas -> Ordering
GraphvizCanvas -> GraphvizCanvas -> GraphvizCanvas
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
min :: GraphvizCanvas -> GraphvizCanvas -> GraphvizCanvas
$cmin :: GraphvizCanvas -> GraphvizCanvas -> GraphvizCanvas
max :: GraphvizCanvas -> GraphvizCanvas -> GraphvizCanvas
$cmax :: GraphvizCanvas -> GraphvizCanvas -> GraphvizCanvas
>= :: GraphvizCanvas -> GraphvizCanvas -> Bool
$c>= :: GraphvizCanvas -> GraphvizCanvas -> Bool
> :: GraphvizCanvas -> GraphvizCanvas -> Bool
$c> :: GraphvizCanvas -> GraphvizCanvas -> Bool
<= :: GraphvizCanvas -> GraphvizCanvas -> Bool
$c<= :: GraphvizCanvas -> GraphvizCanvas -> Bool
< :: GraphvizCanvas -> GraphvizCanvas -> Bool
$c< :: GraphvizCanvas -> GraphvizCanvas -> Bool
compare :: GraphvizCanvas -> GraphvizCanvas -> Ordering
$ccompare :: GraphvizCanvas -> GraphvizCanvas -> Ordering
Ord, GraphvizCanvas
forall a. a -> a -> Bounded a
maxBound :: GraphvizCanvas
$cmaxBound :: GraphvizCanvas
minBound :: GraphvizCanvas
$cminBound :: GraphvizCanvas
Bounded, Int -> GraphvizCanvas
GraphvizCanvas -> Int
GraphvizCanvas -> [GraphvizCanvas]
GraphvizCanvas -> GraphvizCanvas
GraphvizCanvas -> GraphvizCanvas -> [GraphvizCanvas]
GraphvizCanvas
-> GraphvizCanvas -> GraphvizCanvas -> [GraphvizCanvas]
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: GraphvizCanvas
-> GraphvizCanvas -> GraphvizCanvas -> [GraphvizCanvas]
$cenumFromThenTo :: GraphvizCanvas
-> GraphvizCanvas -> GraphvizCanvas -> [GraphvizCanvas]
enumFromTo :: GraphvizCanvas -> GraphvizCanvas -> [GraphvizCanvas]
$cenumFromTo :: GraphvizCanvas -> GraphvizCanvas -> [GraphvizCanvas]
enumFromThen :: GraphvizCanvas -> GraphvizCanvas -> [GraphvizCanvas]
$cenumFromThen :: GraphvizCanvas -> GraphvizCanvas -> [GraphvizCanvas]
enumFrom :: GraphvizCanvas -> [GraphvizCanvas]
$cenumFrom :: GraphvizCanvas -> [GraphvizCanvas]
fromEnum :: GraphvizCanvas -> Int
$cfromEnum :: GraphvizCanvas -> Int
toEnum :: Int -> GraphvizCanvas
$ctoEnum :: Int -> GraphvizCanvas
pred :: GraphvizCanvas -> GraphvizCanvas
$cpred :: GraphvizCanvas -> GraphvizCanvas
succ :: GraphvizCanvas -> GraphvizCanvas
$csucc :: GraphvizCanvas -> GraphvizCanvas
Enum, ReadPrec [GraphvizCanvas]
ReadPrec GraphvizCanvas
Int -> ReadS GraphvizCanvas
ReadS [GraphvizCanvas]
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [GraphvizCanvas]
$creadListPrec :: ReadPrec [GraphvizCanvas]
readPrec :: ReadPrec GraphvizCanvas
$creadPrec :: ReadPrec GraphvizCanvas
readList :: ReadS [GraphvizCanvas]
$creadList :: ReadS [GraphvizCanvas]
readsPrec :: Int -> ReadS GraphvizCanvas
$creadsPrec :: Int -> ReadS GraphvizCanvas
Read, Int -> GraphvizCanvas -> ShowS
[GraphvizCanvas] -> ShowS
GraphvizCanvas -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [GraphvizCanvas] -> ShowS
$cshowList :: [GraphvizCanvas] -> ShowS
show :: GraphvizCanvas -> String
$cshow :: GraphvizCanvas -> String
showsPrec :: Int -> GraphvizCanvas -> ShowS
$cshowsPrec :: Int -> GraphvizCanvas -> ShowS
Show)

instance GraphvizResult GraphvizCanvas where
  outputCall :: GraphvizCanvas -> String
outputCall GraphvizCanvas
Gtk       = String
"gtk"
  outputCall GraphvizCanvas
Xlib      = String
"xlib"

-- -----------------------------------------------------------------------------

-- | Run the recommended Graphviz command on this graph, saving the result
--   to the file provided (note: file extensions are /not/ checked).
runGraphviz    :: (PrintDotRepr dg n) => dg n -> GraphvizOutput -> FilePath
                  -> IO FilePath
runGraphviz :: forall (dg :: * -> *) n.
PrintDotRepr dg n =>
dg n -> GraphvizOutput -> String -> IO String
runGraphviz dg n
gr = forall (dg :: * -> *) n.
PrintDotRepr dg n =>
GraphvizCommand -> dg n -> GraphvizOutput -> String -> IO String
runGraphvizCommand (forall (dg :: * -> *) n. DotRepr dg n => dg n -> GraphvizCommand
commandFor dg n
gr) dg n
gr

-- | Run the chosen Graphviz command on this graph, saving the result
--   to the file provided (note: file extensions are /not/ checked).
runGraphvizCommand :: (PrintDotRepr dg n) => GraphvizCommand -> dg n
                      -> GraphvizOutput -> FilePath
                      -> IO FilePath
runGraphvizCommand :: forall (dg :: * -> *) n.
PrintDotRepr dg n =>
GraphvizCommand -> dg n -> GraphvizOutput -> String -> IO String
runGraphvizCommand GraphvizCommand
cmd dg n
gr GraphvizOutput
t String
fp
  = forall e a. Exception e => (e -> IO a) -> IO a -> IO a
handle (forall e a. Exception e => e -> IO a
throwIO forall b c a. (b -> c) -> (a -> b) -> a -> c
. GraphvizException -> GraphvizException
addExc) forall a b. (a -> b) -> a -> b
$ forall (dg :: * -> *) n a.
PrintDotRepr dg n =>
GraphvizCommand
-> dg n -> GraphvizOutput -> (Handle -> IO a) -> IO a
graphvizWithHandle GraphvizCommand
cmd dg n
gr GraphvizOutput
t Handle -> IO String
toFile
  where
    addFl :: ShowS
addFl = forall a. [a] -> [a] -> [a]
(++) (String
"Unable to create " forall a. [a] -> [a] -> [a]
++ String
fp forall a. [a] -> [a] -> [a]
++ String
"\n")
    toFile :: Handle -> IO String
toFile Handle
h = Handle -> IO ByteString
SB.hGetContents Handle
h forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= String -> ByteString -> IO ()
SB.writeFile String
fp forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> forall (m :: * -> *) a. Monad m => a -> m a
return String
fp

    addExc :: GraphvizException -> GraphvizException
addExc (GVProgramExc String
e) = String -> GraphvizException
GVProgramExc forall a b. (a -> b) -> a -> b
$ ShowS
addFl String
e
    addExc GraphvizException
e                = GraphvizException
e

-- | Append the default extension for the provided 'GraphvizOutput' to
--   the provided 'FilePath' for the output file.
addExtension          :: (GraphvizOutput -> FilePath -> a)
                         -> GraphvizOutput -> FilePath -> a
addExtension :: forall a.
(GraphvizOutput -> String -> a) -> GraphvizOutput -> String -> a
addExtension GraphvizOutput -> String -> a
cmd GraphvizOutput
t String
fp = GraphvizOutput -> String -> a
cmd GraphvizOutput
t String
fp'
  where
    fp' :: String
fp' = String
fp String -> ShowS
<.> GraphvizOutput -> String
defaultExtension GraphvizOutput
t

-- | Run the chosen Graphviz command on this graph, but send the
--   result to the given handle rather than to a file.
--
--   Note that the @'Handle' -> 'IO' a@ function /must/ fully consume
--   the input from the 'Handle'; e.g. use strict @ByteStrings@ rather
--   than lazy ones.
--
--   If the command was unsuccessful, then a 'GraphvizException' is
--   thrown.
graphvizWithHandle :: (PrintDotRepr dg n)
                      => GraphvizCommand  -- ^ Which command to run
                      -> dg n             -- ^ The 'DotRepr' to use
                      -> GraphvizOutput   -- ^ The 'GraphvizOutput' type
                      -> (Handle -> IO a) -- ^ Extract the output
                      -> IO a             -- ^ The error or the result.
graphvizWithHandle :: forall (dg :: * -> *) n a.
PrintDotRepr dg n =>
GraphvizCommand
-> dg n -> GraphvizOutput -> (Handle -> IO a) -> IO a
graphvizWithHandle = forall (dg :: * -> *) n o a.
(PrintDotRepr dg n, GraphvizResult o) =>
GraphvizCommand -> dg n -> o -> (Handle -> IO a) -> IO a
graphvizWithHandle'

-- This version is not exported as we don't want to let arbitrary
-- @Handle -> IO a@ functions to be used for GraphvizCanvas outputs.
graphvizWithHandle' :: (PrintDotRepr dg n, GraphvizResult o)
                       => GraphvizCommand -> dg n -> o
                       -> (Handle -> IO a) -> IO a
graphvizWithHandle' :: forall (dg :: * -> *) n o a.
(PrintDotRepr dg n, GraphvizResult o) =>
GraphvizCommand -> dg n -> o -> (Handle -> IO a) -> IO a
graphvizWithHandle' GraphvizCommand
cmd dg n
dg o
t Handle -> IO a
f = forall (dg :: * -> *) n a.
PrintDotRepr dg n =>
String -> [String] -> (Handle -> IO a) -> dg n -> IO a
runCommand (GraphvizCommand -> String
showCmd GraphvizCommand
cmd)
                                            [String
"-T" forall a. [a] -> [a] -> [a]
++ forall o. GraphvizResult o => o -> String
outputCall o
t]
                                            Handle -> IO a
f'
                                            dg n
dg
  where
    f' :: Handle -> IO a
f' Handle
h = Handle -> Bool -> IO ()
hSetBinaryMode Handle
h Bool
True forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Handle -> IO a
f Handle
h

-- | Run the chosen Graphviz command on this graph and render it using
--   the given canvas type.
runGraphvizCanvas          :: (PrintDotRepr dg n) => GraphvizCommand -> dg n
                              -> GraphvizCanvas -> IO ()
runGraphvizCanvas :: forall (dg :: * -> *) n.
PrintDotRepr dg n =>
GraphvizCommand -> dg n -> GraphvizCanvas -> IO ()
runGraphvizCanvas GraphvizCommand
cmd dg n
gr GraphvizCanvas
c = forall (dg :: * -> *) n o a.
(PrintDotRepr dg n, GraphvizResult o) =>
GraphvizCommand -> dg n -> o -> (Handle -> IO a) -> IO a
graphvizWithHandle' GraphvizCommand
cmd dg n
gr GraphvizCanvas
c Handle -> IO ()
nullHandle
  where
    nullHandle :: Handle -> IO ()
    nullHandle :: Handle -> IO ()
nullHandle = forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM (forall a b. a -> b -> a
const ()) forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> IO ByteString
SB.hGetContents

-- | Run the recommended Graphviz command on this graph and render it
--   using the given canvas type.
runGraphvizCanvas'   :: (PrintDotRepr dg n) => dg n -> GraphvizCanvas -> IO ()
runGraphvizCanvas' :: forall (dg :: * -> *) n.
PrintDotRepr dg n =>
dg n -> GraphvizCanvas -> IO ()
runGraphvizCanvas' dg n
d = forall (dg :: * -> *) n.
PrintDotRepr dg n =>
GraphvizCommand -> dg n -> GraphvizCanvas -> IO ()
runGraphvizCanvas (forall (dg :: * -> *) n. DotRepr dg n => dg n -> GraphvizCommand
commandFor dg n
d) dg n
d

-- -----------------------------------------------------------------------------

-- | Is the Graphviz suite of tools installed?  This is determined by
--   whether @dot@ is available in the @PATH@.
isGraphvizInstalled :: IO Bool
isGraphvizInstalled :: IO Bool
isGraphvizInstalled = forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM forall a. Maybe a -> Bool
isJust forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> IO (Maybe String)
findExecutable forall a b. (a -> b) -> a -> b
$ GraphvizCommand -> String
showCmd GraphvizCommand
Dot

-- | If Graphviz does not seem to be available, print the provided
--   error message and then exit fatally.
quitWithoutGraphviz     :: String -> IO ()
quitWithoutGraphviz :: String -> IO ()
quitWithoutGraphviz String
err = do Bool
hasGraphviz <- IO Bool
isGraphvizInstalled
                             forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless Bool
hasGraphviz
                               forall a b. (a -> b) -> a -> b
$ Handle -> String -> IO ()
hPutStrLn Handle
stderr String
err forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> forall a. ExitCode -> IO a
exitWith (Int -> ExitCode
ExitFailure Int
1)