    {-# 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 dg n -> Bool
    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
    (GraphvizOutput -> GraphvizOutput -> Bool)
    -> (GraphvizOutput -> GraphvizOutput -> Bool) -> Eq GraphvizOutput
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: GraphvizOutput -> GraphvizOutput -> Bool
    == :: GraphvizOutput -> GraphvizOutput -> Bool
    $c/= :: GraphvizOutput -> GraphvizOutput -> Bool
    /= :: GraphvizOutput -> GraphvizOutput -> Bool
    Eq, Eq GraphvizOutput
    Eq GraphvizOutput =>
    (GraphvizOutput -> GraphvizOutput -> Ordering)
    -> (GraphvizOutput -> GraphvizOutput -> Bool)
    -> (GraphvizOutput -> GraphvizOutput -> Bool)
    -> (GraphvizOutput -> GraphvizOutput -> Bool)
    -> (GraphvizOutput -> GraphvizOutput -> Bool)
    -> (GraphvizOutput -> GraphvizOutput -> GraphvizOutput)
    -> (GraphvizOutput -> GraphvizOutput -> GraphvizOutput)
    -> Ord 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
    $ccompare :: GraphvizOutput -> GraphvizOutput -> Ordering
    compare :: GraphvizOutput -> GraphvizOutput -> Ordering
    $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
    >= :: GraphvizOutput -> GraphvizOutput -> Bool
    $cmax :: GraphvizOutput -> GraphvizOutput -> GraphvizOutput
    max :: GraphvizOutput -> GraphvizOutput -> GraphvizOutput
    $cmin :: GraphvizOutput -> GraphvizOutput -> GraphvizOutput
    min :: GraphvizOutput -> GraphvizOutput -> GraphvizOutput
    Ord, Int -> GraphvizOutput -> ShowS
    [GraphvizOutput] -> ShowS
    GraphvizOutput -> String
    (Int -> GraphvizOutput -> ShowS)
    -> (GraphvizOutput -> String)
    -> ([GraphvizOutput] -> ShowS)
    -> Show GraphvizOutput
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> GraphvizOutput -> ShowS
    showsPrec :: Int -> GraphvizOutput -> ShowS
    $cshow :: GraphvizOutput -> String
    show :: GraphvizOutput -> String
    $cshowList :: [GraphvizOutput] -> ShowS
    showList :: [GraphvizOutput] -> ShowS
    Show, ReadPrec [GraphvizOutput]
    ReadPrec GraphvizOutput
    Int -> ReadS GraphvizOutput
    ReadS [GraphvizOutput]
    (Int -> ReadS GraphvizOutput)
    -> ReadS [GraphvizOutput]
    -> ReadPrec GraphvizOutput
    -> ReadPrec [GraphvizOutput]
    -> Read GraphvizOutput
    forall a.
    (Int -> ReadS a)
    -> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
    $creadsPrec :: Int -> ReadS GraphvizOutput
    readsPrec :: Int -> ReadS GraphvizOutput
    $creadList :: ReadS [GraphvizOutput]
    readList :: ReadS [GraphvizOutput]
    $creadPrec :: ReadPrec GraphvizOutput
    readPrec :: ReadPrec GraphvizOutput
    $creadListPrec :: ReadPrec [GraphvizOutput]
    readListPrec :: ReadPrec [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" String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String -> (Version -> String) -> Maybe Version -> String
    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
    (GraphvizCanvas -> GraphvizCanvas -> Bool)
    -> (GraphvizCanvas -> GraphvizCanvas -> Bool) -> Eq GraphvizCanvas
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: GraphvizCanvas -> GraphvizCanvas -> Bool
    == :: GraphvizCanvas -> GraphvizCanvas -> Bool
    $c/= :: GraphvizCanvas -> GraphvizCanvas -> Bool
    /= :: GraphvizCanvas -> GraphvizCanvas -> Bool
    Eq, Eq GraphvizCanvas
    Eq GraphvizCanvas =>
    (GraphvizCanvas -> GraphvizCanvas -> Ordering)
    -> (GraphvizCanvas -> GraphvizCanvas -> Bool)
    -> (GraphvizCanvas -> GraphvizCanvas -> Bool)
    -> (GraphvizCanvas -> GraphvizCanvas -> Bool)
    -> (GraphvizCanvas -> GraphvizCanvas -> Bool)
    -> (GraphvizCanvas -> GraphvizCanvas -> GraphvizCanvas)
    -> (GraphvizCanvas -> GraphvizCanvas -> GraphvizCanvas)
    -> Ord 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
    $ccompare :: GraphvizCanvas -> GraphvizCanvas -> Ordering
    compare :: GraphvizCanvas -> GraphvizCanvas -> Ordering
    $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
    >= :: GraphvizCanvas -> GraphvizCanvas -> Bool
    $cmax :: GraphvizCanvas -> GraphvizCanvas -> GraphvizCanvas
    max :: GraphvizCanvas -> GraphvizCanvas -> GraphvizCanvas
    $cmin :: GraphvizCanvas -> GraphvizCanvas -> GraphvizCanvas
    min :: GraphvizCanvas -> GraphvizCanvas -> GraphvizCanvas
    Ord, GraphvizCanvas
    GraphvizCanvas -> GraphvizCanvas -> Bounded GraphvizCanvas
    forall a. a -> a -> Bounded a
    $cminBound :: GraphvizCanvas
    minBound :: GraphvizCanvas
    $cmaxBound :: GraphvizCanvas
    maxBound :: GraphvizCanvas
    Bounded, Int -> GraphvizCanvas
    GraphvizCanvas -> Int
    GraphvizCanvas -> [GraphvizCanvas]
    GraphvizCanvas -> GraphvizCanvas
    GraphvizCanvas -> GraphvizCanvas -> [GraphvizCanvas]
    GraphvizCanvas
    -> GraphvizCanvas -> GraphvizCanvas -> [GraphvizCanvas]
    (GraphvizCanvas -> GraphvizCanvas)
    -> (GraphvizCanvas -> GraphvizCanvas)
    -> (Int -> GraphvizCanvas)
    -> (GraphvizCanvas -> Int)
    -> (GraphvizCanvas -> [GraphvizCanvas])
    -> (GraphvizCanvas -> GraphvizCanvas -> [GraphvizCanvas])
    -> (GraphvizCanvas -> GraphvizCanvas -> [GraphvizCanvas])
    -> (GraphvizCanvas
        -> GraphvizCanvas -> GraphvizCanvas -> [GraphvizCanvas])
    -> Enum 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
    $csucc :: GraphvizCanvas -> GraphvizCanvas
    succ :: GraphvizCanvas -> GraphvizCanvas
    $cpred :: GraphvizCanvas -> GraphvizCanvas
    pred :: GraphvizCanvas -> GraphvizCanvas
    $ctoEnum :: Int -> GraphvizCanvas
    toEnum :: Int -> GraphvizCanvas
    $cfromEnum :: GraphvizCanvas -> Int
    fromEnum :: GraphvizCanvas -> Int
    $cenumFrom :: GraphvizCanvas -> [GraphvizCanvas]
    enumFrom :: GraphvizCanvas -> [GraphvizCanvas]
    $cenumFromThen :: GraphvizCanvas -> GraphvizCanvas -> [GraphvizCanvas]
    enumFromThen :: GraphvizCanvas -> GraphvizCanvas -> [GraphvizCanvas]
    $cenumFromTo :: GraphvizCanvas -> GraphvizCanvas -> [GraphvizCanvas]
    enumFromTo :: GraphvizCanvas -> GraphvizCanvas -> [GraphvizCanvas]
    $cenumFromThenTo :: GraphvizCanvas
    -> GraphvizCanvas -> GraphvizCanvas -> [GraphvizCanvas]
    enumFromThenTo :: GraphvizCanvas
    -> GraphvizCanvas -> GraphvizCanvas -> [GraphvizCanvas]
    Enum, ReadPrec [GraphvizCanvas]
    ReadPrec GraphvizCanvas
    Int -> ReadS GraphvizCanvas
    ReadS [GraphvizCanvas]
    (Int -> ReadS GraphvizCanvas)
    -> ReadS [GraphvizCanvas]
    -> ReadPrec GraphvizCanvas
    -> ReadPrec [GraphvizCanvas]
    -> Read GraphvizCanvas
    forall a.
    (Int -> ReadS a)
    -> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
    $creadsPrec :: Int -> ReadS GraphvizCanvas
    readsPrec :: Int -> ReadS GraphvizCanvas
    $creadList :: ReadS [GraphvizCanvas]
    readList :: ReadS [GraphvizCanvas]
    $creadPrec :: ReadPrec GraphvizCanvas
    readPrec :: ReadPrec GraphvizCanvas
    $creadListPrec :: ReadPrec [GraphvizCanvas]
    readListPrec :: ReadPrec [GraphvizCanvas]
    Read, Int -> GraphvizCanvas -> ShowS
    [GraphvizCanvas] -> ShowS
    GraphvizCanvas -> String
    (Int -> GraphvizCanvas -> ShowS)
    -> (GraphvizCanvas -> String)
    -> ([GraphvizCanvas] -> ShowS)
    -> Show GraphvizCanvas
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> GraphvizCanvas -> ShowS
    showsPrec :: Int -> GraphvizCanvas -> ShowS
    $cshow :: GraphvizCanvas -> String
    show :: GraphvizCanvas -> String
    $cshowList :: [GraphvizCanvas] -> ShowS
    showList :: [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 = GraphvizCommand -> dg n -> GraphvizOutput -> String -> IO String
    forall (dg :: * -> *) n.
    PrintDotRepr dg n =>
    GraphvizCommand -> dg n -> GraphvizOutput -> String -> IO String
    runGraphvizCommand (dg n -> GraphvizCommand
    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
      = (GraphvizException -> IO String) -> IO String -> IO String
    forall e a. Exception e => (e -> IO a) -> IO a -> IO a
    handle (GraphvizException -> IO String
    forall e a. (HasCallStack, Exception e) => e -> IO a
    throwIO (GraphvizException -> IO String)
    -> (GraphvizException -> GraphvizException)
    -> GraphvizException
    -> IO String
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . GraphvizException -> GraphvizException
    addExc) (IO String -> IO String) -> IO String -> IO String
    forall a b. (a -> b) -> a -> b
    $ GraphvizCommand
    -> dg n -> GraphvizOutput -> (Handle -> IO String) -> IO String
    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 = String -> ShowS
    forall a. [a] -> [a] -> [a]
    (++) (String
    "Unable to create " String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String
    fp String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String
    "\n")
        toFile :: Handle -> IO String
    toFile Handle
    h = Handle -> IO ByteString
    SB.hGetContents Handle
    h IO ByteString -> (ByteString -> 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 -> ByteString -> IO ()
    SB.writeFile String
    fp IO () -> IO String -> IO String
    forall a b. IO a -> IO b -> IO b
    forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
    >> String -> IO String
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return String
    fp

        addExc :: GraphvizException -> GraphvizException
    addExc (GVProgramExc String
    e) = String -> GraphvizException
    GVProgramExc (String -> GraphvizException) -> String -> GraphvizException
    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 = GraphvizCommand
    -> dg n -> GraphvizOutput -> (Handle -> IO a) -> IO a
    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 = String -> [String] -> (Handle -> IO a) -> dg n -> IO a
    forall (dg :: * -> *) n a.
    PrintDotRepr dg n =>
    String -> [String] -> (Handle -> IO a) -> dg n -> IO a
    runCommand (GraphvizCommand -> String
    showCmd GraphvizCommand
    cmd)
                                                [String
    "-T" String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ o -> String
    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 IO () -> IO a -> IO a
    forall a b. IO a -> IO b -> IO b
    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 = GraphvizCommand
    -> dg n -> GraphvizCanvas -> (Handle -> IO ()) -> IO ()
    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 = (ByteString -> ()) -> IO ByteString -> IO ()
    forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
    liftM (() -> ByteString -> ()
    forall a b. a -> b -> a
    const ()) (IO ByteString -> IO ())
    -> (Handle -> IO ByteString) -> Handle -> IO ()
    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 = GraphvizCommand -> dg n -> GraphvizCanvas -> IO ()
    forall (dg :: * -> *) n.
    PrintDotRepr dg n =>
    GraphvizCommand -> dg n -> GraphvizCanvas -> IO ()
    runGraphvizCanvas (dg n -> GraphvizCommand
    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 = (Maybe String -> Bool) -> IO (Maybe String) -> IO Bool
    forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
    liftM Maybe String -> Bool
    forall a. Maybe a -> Bool
    isJust (IO (Maybe String) -> IO Bool)
    -> (String -> IO (Maybe String)) -> String -> IO Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> IO (Maybe String)
    findExecutable (String -> IO Bool) -> String -> IO Bool
    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 hasGraphviz <- IO Bool
    isGraphvizInstalled
                                 unless hasGraphviz
                                   $ hPutStrLn stderr err >> exitWith (ExitFailure 1)