packages feed

graphviz 2999.10.0.1 → 2999.11.0.0

raw patch · 10 files changed

+451/−226 lines, 10 filesdep ~QuickCheckdep ~bytestringPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: QuickCheck, bytestring

API changes (from Hackage documentation)

- Data.GraphViz: instance (Eq el) => Eq (EdgeID el)
- Data.GraphViz: instance (Ord el) => Ord (EdgeID el)
- Data.GraphViz: instance (Show el) => Show (EdgeID el)
- Data.GraphViz.Attributes: data LayerList
- Data.GraphViz.Parsing: instance (ParseDot a) => ParseDot [a]
- Data.GraphViz.Printing: instance (PrintDot a) => PrintDot [a]
- Data.GraphViz.Types: instance (Eq a) => Eq (DotGraph a)
- Data.GraphViz.Types: instance (Eq a) => Eq (DotStatements a)
- Data.GraphViz.Types: instance (Eq a) => Eq (DotSubGraph a)
- Data.GraphViz.Types: instance (Ord a) => Ord (DotGraph a)
- Data.GraphViz.Types: instance (Ord a) => Ord (DotStatements a)
- Data.GraphViz.Types: instance (Ord a) => Ord (DotSubGraph a)
- Data.GraphViz.Types: instance (ParseDot a) => ParseDot (DotGraph a)
- Data.GraphViz.Types: instance (ParseDot a) => ParseDot (DotStatements a)
- Data.GraphViz.Types: instance (ParseDot a) => ParseDot (DotSubGraph a)
- Data.GraphViz.Types: instance (PrintDot a) => PrintDot (DotGraph a)
- Data.GraphViz.Types: instance (PrintDot a) => PrintDot (DotStatements a)
- Data.GraphViz.Types: instance (PrintDot a) => PrintDot (DotSubGraph a)
- Data.GraphViz.Types: instance (Read a) => Read (DotGraph a)
- Data.GraphViz.Types: instance (Read a) => Read (DotStatements a)
- Data.GraphViz.Types: instance (Read a) => Read (DotSubGraph a)
- Data.GraphViz.Types: instance (Show a) => Show (DotGraph a)
- Data.GraphViz.Types: instance (Show a) => Show (DotStatements a)
- Data.GraphViz.Types: instance (Show a) => Show (DotSubGraph a)
- Data.GraphViz.Types.Generalised: instance (Eq a) => Eq (GDotGraph a)
- Data.GraphViz.Types.Generalised: instance (Eq a) => Eq (GDotStatement a)
- Data.GraphViz.Types.Generalised: instance (Eq a) => Eq (GDotSubGraph a)
- Data.GraphViz.Types.Generalised: instance (Ord a) => Ord (GDotGraph a)
- Data.GraphViz.Types.Generalised: instance (Ord a) => Ord (GDotStatement a)
- Data.GraphViz.Types.Generalised: instance (Ord a) => Ord (GDotSubGraph a)
- Data.GraphViz.Types.Generalised: instance (ParseDot a) => ParseDot (GDotGraph a)
- Data.GraphViz.Types.Generalised: instance (ParseDot a) => ParseDot (GDotStatement a)
- Data.GraphViz.Types.Generalised: instance (ParseDot a) => ParseDot (GDotSubGraph a)
- Data.GraphViz.Types.Generalised: instance (PrintDot a) => PrintDot (GDotGraph a)
- Data.GraphViz.Types.Generalised: instance (PrintDot a) => PrintDot (GDotStatement a)
- Data.GraphViz.Types.Generalised: instance (PrintDot a) => PrintDot (GDotSubGraph a)
- Data.GraphViz.Types.Generalised: instance (Read a) => Read (GDotGraph a)
- Data.GraphViz.Types.Generalised: instance (Read a) => Read (GDotStatement a)
- Data.GraphViz.Types.Generalised: instance (Read a) => Read (GDotSubGraph a)
- Data.GraphViz.Types.Generalised: instance (Show a) => Show (GDotGraph a)
- Data.GraphViz.Types.Generalised: instance (Show a) => Show (GDotStatement a)
- Data.GraphViz.Types.Generalised: instance (Show a) => Show (GDotSubGraph a)
+ Data.GraphViz: instance Eq el => Eq (EdgeID el)
+ Data.GraphViz: instance Ord el => Ord (EdgeID el)
+ Data.GraphViz: instance Show el => Show (EdgeID el)
+ Data.GraphViz.Attributes: class Labellable a
+ Data.GraphViz.Attributes: createPoint :: Double -> Double -> Point
+ Data.GraphViz.Attributes: forcePos :: Point -> Bool
+ Data.GraphViz.Attributes: instance Labellable (PortName, EscString)
+ Data.GraphViz.Attributes: instance Labellable Bool
+ Data.GraphViz.Attributes: instance Labellable Char
+ Data.GraphViz.Attributes: instance Labellable Double
+ Data.GraphViz.Attributes: instance Labellable EscString
+ Data.GraphViz.Attributes: instance Labellable HtmlLabel
+ Data.GraphViz.Attributes: instance Labellable HtmlTable
+ Data.GraphViz.Attributes: instance Labellable HtmlText
+ Data.GraphViz.Attributes: instance Labellable Int
+ Data.GraphViz.Attributes: instance Labellable PortName
+ Data.GraphViz.Attributes: instance Labellable RecordField
+ Data.GraphViz.Attributes: instance Labellable RecordFields
+ Data.GraphViz.Attributes: newtype LayerList
+ Data.GraphViz.Attributes: toLabel :: Labellable a => a -> Attribute
+ Data.GraphViz.Attributes: xCoord :: Point -> Double
+ Data.GraphViz.Attributes: yCoord :: Point -> Double
+ Data.GraphViz.Attributes: zCoord :: Point -> Maybe Double
+ Data.GraphViz.Parsing: instance ParseDot a => ParseDot [a]
+ Data.GraphViz.Printing: instance PrintDot a => PrintDot [a]
+ Data.GraphViz.Types: instance Eq a => Eq (DotGraph a)
+ Data.GraphViz.Types: instance Eq a => Eq (DotStatements a)
+ Data.GraphViz.Types: instance Eq a => Eq (DotSubGraph a)
+ Data.GraphViz.Types: instance Ord a => Ord (DotGraph a)
+ Data.GraphViz.Types: instance Ord a => Ord (DotStatements a)
+ Data.GraphViz.Types: instance Ord a => Ord (DotSubGraph a)
+ Data.GraphViz.Types: instance ParseDot a => ParseDot (DotGraph a)
+ Data.GraphViz.Types: instance ParseDot a => ParseDot (DotStatements a)
+ Data.GraphViz.Types: instance ParseDot a => ParseDot (DotSubGraph a)
+ Data.GraphViz.Types: instance PrintDot a => PrintDot (DotGraph a)
+ Data.GraphViz.Types: instance PrintDot a => PrintDot (DotStatements a)
+ Data.GraphViz.Types: instance PrintDot a => PrintDot (DotSubGraph a)
+ Data.GraphViz.Types: instance Read a => Read (DotGraph a)
+ Data.GraphViz.Types: instance Read a => Read (DotStatements a)
+ Data.GraphViz.Types: instance Read a => Read (DotSubGraph a)
+ Data.GraphViz.Types: instance Show a => Show (DotGraph a)
+ Data.GraphViz.Types: instance Show a => Show (DotStatements a)
+ Data.GraphViz.Types: instance Show a => Show (DotSubGraph a)
+ Data.GraphViz.Types.Generalised: instance Eq a => Eq (GDotGraph a)
+ Data.GraphViz.Types.Generalised: instance Eq a => Eq (GDotStatement a)
+ Data.GraphViz.Types.Generalised: instance Eq a => Eq (GDotSubGraph a)
+ Data.GraphViz.Types.Generalised: instance Ord a => Ord (GDotGraph a)
+ Data.GraphViz.Types.Generalised: instance Ord a => Ord (GDotStatement a)
+ Data.GraphViz.Types.Generalised: instance Ord a => Ord (GDotSubGraph a)
+ Data.GraphViz.Types.Generalised: instance ParseDot a => ParseDot (GDotGraph a)
+ Data.GraphViz.Types.Generalised: instance ParseDot a => ParseDot (GDotStatement a)
+ Data.GraphViz.Types.Generalised: instance ParseDot a => ParseDot (GDotSubGraph a)
+ Data.GraphViz.Types.Generalised: instance PrintDot a => PrintDot (GDotGraph a)
+ Data.GraphViz.Types.Generalised: instance PrintDot a => PrintDot (GDotStatement a)
+ Data.GraphViz.Types.Generalised: instance PrintDot a => PrintDot (GDotSubGraph a)
+ Data.GraphViz.Types.Generalised: instance Read a => Read (GDotGraph a)
+ Data.GraphViz.Types.Generalised: instance Read a => Read (GDotStatement a)
+ Data.GraphViz.Types.Generalised: instance Read a => Read (GDotSubGraph a)
+ Data.GraphViz.Types.Generalised: instance Show a => Show (GDotGraph a)
+ Data.GraphViz.Types.Generalised: instance Show a => Show (GDotStatement a)
+ Data.GraphViz.Types.Generalised: instance Show a => Show (GDotSubGraph a)
- Data.GraphViz: addEdgeIDs :: (Graph gr) => gr nl el -> gr nl (EdgeID el)
+ Data.GraphViz: addEdgeIDs :: Graph gr => gr nl el -> gr nl (EdgeID el)
- Data.GraphViz: prettyPrint :: (DotRepr dg n) => dg n -> IO String
+ Data.GraphViz: prettyPrint :: DotRepr dg n => dg n -> IO String
- Data.GraphViz: prettyPrint' :: (DotRepr dg n) => dg n -> String
+ Data.GraphViz: prettyPrint' :: DotRepr dg n => dg n -> String
- Data.GraphViz: preview :: (Ord el, Graph gr) => gr nl el -> IO ()
+ Data.GraphViz: preview :: (Ord el, Graph gr, Labellable nl, Labellable el) => gr nl el -> IO ()
- Data.GraphViz.Attributes: LL :: String -> [(String, String)] -> LayerList
+ Data.GraphViz.Attributes: LL :: [LayerID] -> LayerList
- Data.GraphViz.Attributes: LRS :: LayerID -> String -> LayerID -> LayerRange
+ Data.GraphViz.Attributes: LRS :: LayerID -> LayerID -> LayerRange
- Data.GraphViz.Attributes: Point :: Double -> Double -> Point
+ Data.GraphViz.Attributes: Point :: Double -> Double -> Maybe Double -> Bool -> Point
- Data.GraphViz.Commands: commandFor :: (DotRepr dg n) => dg n -> GraphvizCommand
+ Data.GraphViz.Commands: commandFor :: DotRepr dg n => dg n -> GraphvizCommand
- Data.GraphViz.Commands: graphvizWithHandle :: (DotRepr dg n) => GraphvizCommand -> dg n -> GraphvizOutput -> (Handle -> IO a) -> IO (Either String a)
+ Data.GraphViz.Commands: graphvizWithHandle :: DotRepr dg n => GraphvizCommand -> dg n -> GraphvizOutput -> (Handle -> IO a) -> IO (Either String a)
- Data.GraphViz.Commands: runGraphviz :: (DotRepr dg n) => dg n -> GraphvizOutput -> FilePath -> IO (Either String FilePath)
+ Data.GraphViz.Commands: runGraphviz :: DotRepr dg n => dg n -> GraphvizOutput -> FilePath -> IO (Either String FilePath)
- Data.GraphViz.Commands: runGraphvizCanvas :: (DotRepr dg n) => GraphvizCommand -> dg n -> GraphvizCanvas -> IO RunResult
+ Data.GraphViz.Commands: runGraphvizCanvas :: DotRepr dg n => GraphvizCommand -> dg n -> GraphvizCanvas -> IO RunResult
- Data.GraphViz.Commands: runGraphvizCanvas' :: (DotRepr dg n) => dg n -> GraphvizCanvas -> IO RunResult
+ Data.GraphViz.Commands: runGraphvizCanvas' :: DotRepr dg n => dg n -> GraphvizCanvas -> IO RunResult
- Data.GraphViz.Commands: runGraphvizCommand :: (DotRepr dg n) => GraphvizCommand -> dg n -> GraphvizOutput -> FilePath -> IO (Either String FilePath)
+ Data.GraphViz.Commands: runGraphvizCommand :: DotRepr dg n => GraphvizCommand -> dg n -> GraphvizOutput -> FilePath -> IO (Either String FilePath)
- Data.GraphViz.Parsing: noneOf :: (Eq a) => [a] -> Parser a a
+ Data.GraphViz.Parsing: noneOf :: Eq a => [a] -> Parser a a
- Data.GraphViz.Parsing: parse :: (ParseDot a) => Parse a
+ Data.GraphViz.Parsing: parse :: ParseDot a => Parse a
- Data.GraphViz.Parsing: parseEscaped :: Bool -> [Char] -> Parse String
+ Data.GraphViz.Parsing: parseEscaped :: Bool -> [Char] -> [Char] -> Parse String
- Data.GraphViz.Parsing: parseField :: (ParseDot a) => (a -> b) -> String -> Parse b
+ Data.GraphViz.Parsing: parseField :: ParseDot a => (a -> b) -> String -> Parse b
- Data.GraphViz.Parsing: parseFieldDef :: (ParseDot a) => (a -> b) -> a -> String -> Parse b
+ Data.GraphViz.Parsing: parseFieldDef :: ParseDot a => (a -> b) -> a -> String -> Parse b
- Data.GraphViz.Parsing: parseFields :: (ParseDot a) => (a -> b) -> [String] -> Parse b
+ Data.GraphViz.Parsing: parseFields :: ParseDot a => (a -> b) -> [String] -> Parse b
- Data.GraphViz.Parsing: parseFieldsDef :: (ParseDot a) => (a -> b) -> a -> [String] -> Parse b
+ Data.GraphViz.Parsing: parseFieldsDef :: ParseDot a => (a -> b) -> a -> [String] -> Parse b
- Data.GraphViz.Parsing: parseIt :: (ParseDot a) => String -> (a, String)
+ Data.GraphViz.Parsing: parseIt :: ParseDot a => String -> (a, String)
- Data.GraphViz.Parsing: parseIt' :: (ParseDot a) => String -> a
+ Data.GraphViz.Parsing: parseIt' :: ParseDot a => String -> a
- Data.GraphViz.Parsing: parseList :: (ParseDot a) => Parse [a]
+ Data.GraphViz.Parsing: parseList :: ParseDot a => Parse [a]
- Data.GraphViz.Parsing: parseUnqt :: (ParseDot a) => Parse a
+ Data.GraphViz.Parsing: parseUnqt :: ParseDot a => Parse a
- Data.GraphViz.Parsing: parseUnqtList :: (ParseDot a) => Parse [a]
+ Data.GraphViz.Parsing: parseUnqtList :: ParseDot a => Parse [a]
- Data.GraphViz.Parsing: tryParseList :: (ParseDot a) => Parse [a]
+ Data.GraphViz.Parsing: tryParseList :: ParseDot a => Parse [a]
- Data.GraphViz.Printing: listToDot :: (PrintDot a) => [a] -> DotCode
+ Data.GraphViz.Printing: listToDot :: PrintDot a => [a] -> DotCode
- Data.GraphViz.Printing: printField :: (PrintDot a) => String -> a -> DotCode
+ Data.GraphViz.Printing: printField :: PrintDot a => String -> a -> DotCode
- Data.GraphViz.Printing: printIt :: (PrintDot a) => a -> String
+ Data.GraphViz.Printing: printIt :: PrintDot a => a -> String
- Data.GraphViz.Printing: toDot :: (PrintDot a) => a -> DotCode
+ Data.GraphViz.Printing: toDot :: PrintDot a => a -> DotCode
- Data.GraphViz.Printing: unqtDot :: (PrintDot a) => a -> DotCode
+ Data.GraphViz.Printing: unqtDot :: PrintDot a => a -> DotCode
- Data.GraphViz.Printing: unqtListToDot :: (PrintDot a) => [a] -> DotCode
+ Data.GraphViz.Printing: unqtListToDot :: PrintDot a => [a] -> DotCode
- Data.GraphViz.Types: edgeInformation :: (DotRepr dg n) => Bool -> dg n -> [DotEdge n]
+ Data.GraphViz.Types: edgeInformation :: DotRepr dg n => Bool -> dg n -> [DotEdge n]
- Data.GraphViz.Types: getID :: (DotRepr dg n) => dg n -> Maybe GraphID
+ Data.GraphViz.Types: getID :: DotRepr dg n => dg n -> Maybe GraphID
- Data.GraphViz.Types: graphEdges :: (DotRepr dg n) => dg n -> [DotEdge n]
+ Data.GraphViz.Types: graphEdges :: DotRepr dg n => dg n -> [DotEdge n]
- Data.GraphViz.Types: graphIsDirected :: (DotRepr dg n) => dg n -> Bool
+ Data.GraphViz.Types: graphIsDirected :: DotRepr dg n => dg n -> Bool
- Data.GraphViz.Types: graphIsStrict :: (DotRepr dg n) => dg n -> Bool
+ Data.GraphViz.Types: graphIsStrict :: DotRepr dg n => dg n -> Bool
- Data.GraphViz.Types: graphStructureInformation :: (DotRepr dg n) => dg n -> (GlobalAttributes, ClusterLookup)
+ Data.GraphViz.Types: graphStructureInformation :: DotRepr dg n => dg n -> (GlobalAttributes, ClusterLookup)
- Data.GraphViz.Types: makeStrict :: (DotRepr dg n) => dg n -> dg n
+ Data.GraphViz.Types: makeStrict :: DotRepr dg n => dg n -> dg n
- Data.GraphViz.Types: nodeInformation :: (DotRepr dg n) => Bool -> dg n -> NodeLookup n
+ Data.GraphViz.Types: nodeInformation :: DotRepr dg n => Bool -> dg n -> NodeLookup n
- Data.GraphViz.Types: parseDotGraph :: (DotRepr dg n) => String -> dg n
+ Data.GraphViz.Types: parseDotGraph :: DotRepr dg n => String -> dg n
- Data.GraphViz.Types: printDotGraph :: (DotRepr dg n) => dg n -> String
+ Data.GraphViz.Types: printDotGraph :: DotRepr dg n => dg n -> String
- Data.GraphViz.Types: setID :: (DotRepr dg n) => GraphID -> dg n -> dg n
+ Data.GraphViz.Types: setID :: DotRepr dg n => GraphID -> dg n -> dg n

Files

Changelog view
@@ -7,6 +7,31 @@ The following is information about what major changes have gone into each release. +Changes in 2999.11.0.0+----------------------++* Addition of the `Labellable` class (and its method `toLabel`) to+  make it easier to construct labels.++* Backslashes (i.e. the `\` character) are now escaped/unescaped+  properly (bug spotted by **Han Joosten**).  As part of this:++    - Dot-specific escapes such as `\N` are now also handled+      correctly, so the slash does not need to be escaped.++    - Newline (`'\n'`) characters in labels, etc. are escaped to+      centred-newlines in Dot code, but not unescaped.++* `Point` values can now have the optional third dimension and end in+  a `!` to indicate that that position should be used (as input to+  Graphviz).++* `LayerList` uses `LayerID` values, and now has a proper `shrink`+  implementation in the test suite.++* The optional `z` coordinate and `!` argument for `Point` values are+  now supported.+ Changes in 2999.10.0.1 ---------------------- 
Data/GraphViz.hs view
@@ -1,6 +1,4 @@-{-# LANGUAGE   MultiParamTypeClasses-             , FlexibleContexts-  #-}+{-# LANGUAGE   MultiParamTypeClasses, FlexibleContexts #-}  {- |    Module      : Data.GraphViz@@ -21,16 +19,17 @@ module Data.GraphViz     ( -- * Conversion from graphs to /Dot/ format.       -- ** Specifying parameters.+      -- $params       GraphvizParams(..)     , defaultParams     , nonClusteredParams     , blankParams     , setDirectedness-      -- ** Converting graphs.-    , graphToDot-      -- ** Conversion with support for clusters.+      -- *** Specifying clusters.     , LNodeCluster     , NodeCluster(..)+      -- ** Converting graphs.+    , graphToDot       -- ** Pseudo-inverse conversion.     , dotToGraph       -- * Graph augmentation.@@ -88,6 +87,62 @@  -- ----------------------------------------------------------------------------- +{- $params++   A 'GraphvizParams' value contains all the information necessary to+   manipulate 'Graph's with this library.  As such, its components deal+   with:++   * Whether to treat graphs as being directed or not;++   * Which top-level 'GlobalAttributes' values should be applied;++   * How to define (and name) clusters;++   * How to format clusters, nodes and edges.++   Apart from not having to pass multiple values around, another+   advantage of using 'GraphvizParams' over the previous approach is that+   there is no distinction between clustering and non-clustering variants+   of the same functions.++   Example usages of 'GraphvizParams' follow:++   * Quickly visualise a graph using the default parameters.  Note the+     usage of @'nonClusteredParams'@ over @'defaultParams'@ to avoid+     type-checking problems with the cluster type.++     > defaultVis :: (Graph gr) => gr nl el -> DotGraph Node+     > defaultVis = graphToDot nonClusteredParams++   * As with @defaultVis@, but determine whether or not the graph is+     directed or undirected.++     > checkDirectednessVis :: (Graph gr, Ord el) => gr nl el -> DotGraph Node+     > checkDirectednessVis = setDirectedness graphToDot nonClusteredParams++   * Clustering nodes based upon whether they are even or odd.  We have+     the option of either constructing a @GraphvizParams@ directly, or+     using @'blankParams'@.  Going with the latter to avoid setting+     @'isDirected'@.++     > evenOdd :: (Graph gr, Ord el) => gr Int el -> DotGraph Node+     > evenOdd = setDirectedness graphToDot params+     >   where+     >     params = blankParams { globalAttributes = []+     >                          , clusterBy        = clustBy+     >                          , clusterID        = Just . Int+     >                          , fmtCluster       = clFmt+     >                          , fmtNode          = const []+     >                          , fmtEdge          = const []+     >                          }+     >     clustBy (n,l) = C (n `mod` 2) $ N (n,l)+     >     clFmt m = [GraphAttrs [toLabel $ "n == " ++ show m ++ " (mod 2)"]]++   For more examples, see the source of 'dotizeGraph' and 'preview'.++-}+ -- | Defines the parameters used to convert a 'Graph' into a 'DotRepr'. -- --   A value of type @'GraphvizParams' nl el cl l@ indicates that the@@ -98,32 +153,33 @@ -- --   The clustering in 'clusterBy' can be to arbitrary depth. data GraphvizParams nl el cl l-     = Params { -- | 'True' if the 'Graph' is directed; 'False'+     = Params { -- | @True@ if the graph is directed; @False@                 --   otherwise.                 isDirected       :: Bool                 -- | The top-level global 'Attributes' for the entire-                --   'Graph'.+                --   graph.               , globalAttributes :: [GlobalAttributes]                 -- | A function to specify which cluster a particular                 --   'LNode' is in.               , clusterBy        :: (LNode nl -> LNodeCluster cl l)-                -- | The 'GraphID' for a cluster.+                -- | The name/identifier for a cluster.               , clusterID        :: (cl -> Maybe GraphID)                 -- | Specify which global attributes are applied in                 --   the given cluster.               , fmtCluster       :: (cl -> [GlobalAttributes])-                -- | The specific 'Attributes' for that 'LNode'.+                -- | The specific @Attributes@ for a node.               , fmtNode          :: (LNode l -> Attributes)-                -- | The specific 'Attributes' for that 'LEdge'.+                -- | The specific @Attributes@ for an edge.               , fmtEdge          :: (LEdge el -> Attributes)               }  -- | A default 'GraphvizParams' value which assumes the graph is --   directed, contains no clusters and has no 'Attribute's set. -----   If you wish to have the labels of the nodes after applying---   'clusterBy' to have a different from before clustering, then you---   will have to specify your own 'GraphvizParams' value from scratch.+--   If you wish to have the labels of the nodes to have a different+--   type after applying 'clusterBy' from before clustering, then you+--   will have to specify your own 'GraphvizParams' value from+--   scratch (or use 'blankParams'). defaultParams :: GraphvizParams nl el cl nl defaultParams = Params { isDirected       = True                        , globalAttributes = []@@ -135,9 +191,9 @@                        }  -- | A variant of 'defaultParams' that enforces that the clustering---   type is @'()'@; this avoids problems when using 'defaultParams'---   internally within a function without any constraint on what the---   clustering type is.+--   type is @'()'@ (i.e.: no clustering); this avoids problems when+--   using 'defaultParams' internally within a function without any+--   constraint on what the clustering type is. nonClusteredParams :: GraphvizParams nl el () nl nonClusteredParams = defaultParams @@ -145,7 +201,9 @@ --   @'undefined'@.  This is useful when you have a function that will --   set some of the values for you (e.g. 'setDirectedness') but you --   don't want to bother thinking of default values to set in the---   meantime.+--   meantime.  This is especially useful when you are+--   programmatically setting the clustering function (and as such do+--   not know what the types might be). blankParams :: GraphvizParams nl el cl l blankParams = Params { isDirected       = undefined                      , globalAttributes = undefined@@ -415,11 +473,17 @@ canonicalise :: (DotRepr dg n, DotRepr DotGraph n) => dg n -> IO (DotGraph n) canonicalise = liftM parseDotGraph . prettyPrint --- | Quickly visualise a graph using the 'Xlib' 'GraphvizCanvas'.-preview   :: (Ord el, Graph gr) => gr nl el -> IO ()+-- | Quickly visualise a graph using the 'Xlib' 'GraphvizCanvas'.  If+--   your label types are not (and cannot) be instances of 'Labellable',+--   you may wish to use 'gmap', 'nmap' or 'emap' to set them to a value+--   such as @\"\"@.+preview   :: (Ord el, Graph gr, Labellable nl, Labellable el) => gr nl el -> IO () preview g = ign $ forkIO (ign $ runGraphvizCanvas' dg Xlib)   where-    dg = setDirectedness graphToDot nonClusteredParams g+    dg = setDirectedness graphToDot params g+    params = nonClusteredParams { fmtNode = \ (_,l) -> [toLabel l]+                                , fmtEdge = \ (_, _, l) -> [toLabel l]+                                }     ign = (>> return ())  -- | Used for obtaining results from 'graphvizWithHandle', etc. when
Data/GraphViz/Attributes.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-}+ {- |    Module      : Data.GraphViz.Attributes    Description : Definition of the Graphviz attributes.@@ -27,11 +29,12 @@      (since /A/ is at the tail end of the arrow).     * @ColorList@, @DoubleList@ and @PointfList@ are defined as actual-     lists (but 'LayerList' is not).  All of these are assumed to be-     non-empty lists.  Note that for the @Color@ 'Attribute' for node-     values, only a single Color is valid; edges are allowed multiple-     colors with one spline/arrow per color in the list (but you must have-     at least one 'Color' in the list).  This might be changed in future.+     lists (@'LayerList'@ needs a newtype for other reasons).  All of these+     are assumed to be non-empty lists.  Note that for the @Color@+     'Attribute' for node values, only a single Color is valid; edges are+     allowed multiple colors with one spline/arrow per color in the list+     (but you must have at least one 'Color' in the list).  This might be+     changed in future.     * Style is implemented as a list of 'StyleItem' values; note that      empty lists are not allowed.@@ -41,10 +44,8 @@      expanded upon to give an idea of what they represent rather than      using generic terms. -   * @PointF@ and 'Point' have been combined, and feature support for pure-     'Int'-based co-ordinates as well as 'Double' ones (i.e. no floating-     point-only points for Point).  The optional '!' and third value-     for Point are not available.+   * @PointF@ and 'Point' have been combined.  The optional '!' and+     third value for Point are also available.     * 'Rect' uses two 'Point' values to denote the lower-left and      top-right corners.@@ -79,63 +80,41 @@     , usedByClusters     , usedByNodes     , usedByEdges+       -- * Value types for @Attribute@s.+    , module Data.GraphViz.Attributes.Colors++      -- ** Labels     , EscString-    , ArrowType(..)-    , AspectType(..)-    , Rect(..)-    , ClusterMode(..)-    , DirType(..)-    , DEConstraints(..)-    , DPoint(..)-    , ModeType(..)-    , Model(..)     , Label(..)-    , Point(..)-    , Overlap(..)-    , LayerRange(..)-    , LayerID(..)-    , LayerList(..)-    , OutputMode(..)-    , Pack(..)-    , PackMode(..)-    , Pos(..)-    , EdgeType(..)-    , PageDir(..)-    , Spline(..)-    , QuadType(..)-    , Root(..)-    , RankType(..)-    , RankDir(..)-    , Shape(..)-    , SmoothType(..)-    , StartType(..)-    , STStyle(..)-    , StyleItem(..)-    , StyleName(..)-    , ViewPort(..)-    , FocusType(..)+    , Labellable(..)     , VerticalPlacement(..)-    , ScaleType(..)+    , module Data.GraphViz.Attributes.HTML+      -- *** Types representing the Dot grammar for records.+    , RecordFields+    , RecordField(..)+    , Rect(..)     , Justification(..)-    , Ratios(..)-      -- Re-exported from Data.GraphViz.Attributes.Internal++      -- ** Nodes+    , Shape(..)+    , ScaleType(..)++      -- ** Edges+    , DirType(..)+    , EdgeType(..)+      -- *** Modifying where edges point     , PortName(..)     , PortPos(..)     , CompassPoint(..)-      -- Re-exporting modules-    , module Data.GraphViz.Attributes.Colors-    , module Data.GraphViz.Attributes.HTML-      -- * Types representing the Dot grammar for records.-    , RecordFields-    , RecordField(..)-      -- * Types representing the Dot grammar for @ArrowType@.+      -- *** Arrows+    , ArrowType(..)     , ArrowShape(..)     , ArrowModifier(..)     , ArrowFill(..)     , ArrowSide(..)-      -- ** Default @ArrowType@ aliases.-      -- *** The 9 primitive @ArrowShape@s.+      -- **** Default @ArrowType@ aliases.+      -- ***** The 9 primitive @ArrowShape@s.     , box     , crow     , diamond@@ -145,24 +124,63 @@     , normal     , tee     , vee-      -- *** 5 derived Arrows.+      -- ***** 5 derived Arrows.     , oDot     , invDot     , invODot     , oBox     , oDiamond-      -- *** 5 supported cases for backwards compatibility+      -- ***** 5 supported cases for backwards compatibility     , eDiamond     , openArr     , halfOpen     , emptyArr     , invEmpty-      -- ** @ArrowModifier@ instances+      -- **** @ArrowModifier@ instances     , noMods     , openMod-      -- * Other exported functions\/values++      -- ** Positioning+    , Point(..)+    , createPoint+    , Pos(..)+    , Spline(..)+    , DPoint(..)++      -- ** Layout+    , AspectType(..)+    , ClusterMode(..)+    , Model(..)+    , Overlap(..)+    , Root(..)+    , OutputMode(..)+    , Pack(..)+    , PackMode(..)+    , PageDir(..)+    , QuadType(..)+    , RankType(..)+    , RankDir(..)+    , StartType(..)+    , ViewPort(..)+    , FocusType(..)+    , Ratios(..)++      -- ** Modes+    , ModeType(..)+    , DEConstraints(..)++      -- ** Layers+    , LayerRange(..)+    , LayerID(..)+    , LayerList(..)     , defLayerSep     , notLayerSep++      -- ** Stylistic+    , SmoothType(..)+    , STStyle(..)+    , StyleItem(..)+    , StyleName(..)     ) where  import Data.GraphViz.Attributes.Colors@@ -1257,6 +1275,7 @@  -- ----------------------------------------------------------------------------- +-- | Should only have 2D points (i.e. created with 'createPoint'). data Rect = Rect Point Point             deriving (Eq, Ord, Show, Read) @@ -1266,7 +1285,7 @@     toDot = doubleQuotes . unqtDot  instance ParseDot Rect where-    parseUnqt = liftM (uncurry Rect) commaSepUnqt+    parseUnqt = liftM (uncurry Rect) $ commaSep' parsePoint2D parsePoint2D      parse = quotedParse parseUnqt @@ -1328,7 +1347,8 @@  -- ----------------------------------------------------------------------------- --- | Either a 'Double' or a 'Point'.+-- | Either a 'Double' or a (2D) 'Point' (i.e. created with+--   'createPoint'). data DPoint = DVal Double             | PVal Point              deriving (Eq, Ord, Show, Read)@@ -1341,13 +1361,13 @@     toDot (PVal p) = toDot p  instance ParseDot DPoint where-    parseUnqt = liftM PVal parseUnqt+    parseUnqt = liftM PVal parsePoint2D                 `onFail`                 liftM DVal parseUnqt -    parse = liftM PVal parse+    parse = quotedParse parseUnqt             `onFail`-            liftM DVal parse+            liftM DVal parseUnqt  -- ----------------------------------------------------------------------------- @@ -1426,6 +1446,51 @@                   , liftM StrLabel parse                   ] +-- | A convenience class to make it easier to create labels.  It is+--   highly recommended that you make any other types that you wish to+--   create labels from an instance of this class, preferably via the+--   @String@ instance.+class Labellable a where+  toLabel :: a -> Attribute++instance Labellable EscString where+  toLabel = Label . StrLabel++instance Labellable Char where+  toLabel = toLabel . (:[])++instance Labellable Int where+  toLabel = toLabel . show++instance Labellable Double where+  toLabel = toLabel . show++instance Labellable Bool where+  toLabel = toLabel . show++instance Labellable HtmlLabel where+  toLabel = Label . HtmlLabel++instance Labellable HtmlText where+  toLabel = toLabel . HtmlText++instance Labellable HtmlTable where+  toLabel = toLabel . HtmlTable++instance Labellable RecordFields where+  toLabel = Label . RecordLabel++instance Labellable RecordField where+  toLabel = toLabel . (:[])++-- | A shorter variant than using @PortName@ from 'RecordField'.+instance Labellable PortName where+  toLabel = toLabel . PortName++-- | A shorter variant than using 'LabelledTarget'.+instance Labellable (PortName, EscString) where+  toLabel = toLabel . uncurry LabelledTarget+ -- -----------------------------------------------------------------------------  -- | A RecordFields value should never be empty.@@ -1489,7 +1554,7 @@ printPortName = angled . unqtRecordString . portName  parseRecord :: Parse String-parseRecord = parseEscaped False recordEscChars+parseRecord = parseEscaped False recordEscChars []  unqtRecordString :: String -> DotCode unqtRecordString = unqtEscaped recordEscChars@@ -1499,11 +1564,27 @@  -- ----------------------------------------------------------------------------- -data Point = Point Double Double-             deriving (Eq, Ord, Show, Read)+data Point = Point { xCoord   :: Double+                   , yCoord   :: Double+                      -- | Can only be 'Just' for @'Dim' 3@ or greater.+                   , zCoord   :: Maybe Double+                     -- | Input to Graphviz only: specify that the+                     --   node position should not change.+                   , forcePos :: Bool+                   }+           deriving (Eq, Ord, Show, Read) +-- | Create a point with only @x@ and @y@ values.+createPoint     :: Double -> Double -> Point+createPoint x y = Point x y Nothing False++parsePoint2D :: Parse Point+parsePoint2D = liftM (uncurry createPoint) commaSepUnqt+ instance PrintDot Point where-    unqtDot (Point  x y) = commaDel x y+    unqtDot (Point x y mz frs) = bool id (<> char '!') frs+                                 . maybe id (\ z -> (<> unqtDot z) . (<> comma)) mz+                                 $ commaDel x y      toDot = doubleQuotes . unqtDot @@ -1512,11 +1593,10 @@     listToDot = doubleQuotes . unqtListToDot  instance ParseDot Point where-    -- Need to take into account the situation where first value is an-    -- integer, second a double: if Point parsing first, then it won't-    -- parse the second number properly; but if PointD first then it-    -- will treat Int/Int as Double/Double.-    parseUnqt = liftM (uncurry Point) commaSepUnqt+    parseUnqt = do (x,y) <- commaSepUnqt+                   mz <- optional $ parseComma >> parseUnqt+                   bng <- liftM isJust . optional $ character '!'+                   return $ Point x y mz bng      parse = quotedParse parseUnqt @@ -1561,29 +1641,31 @@ -- -----------------------------------------------------------------------------  data LayerRange = LRID LayerID-                | LRS LayerID String LayerID+                | LRS LayerID LayerID                   deriving (Eq, Ord, Show, Read)  instance PrintDot LayerRange where-    unqtDot (LRID lid)      = unqtDot lid-    unqtDot (LRS id1 s id2) = unqtDot id1 <> unqtDot s <> unqtDot id2+    unqtDot (LRID lid)    = unqtDot lid+    unqtDot (LRS id1 id2) = unqtDot id1 <> s <> unqtDot id2+      where+        s = unqtDot $ head defLayerSep      toDot (LRID lid) = toDot lid     toDot lrs        = doubleQuotes $ unqtDot lrs  instance ParseDot LayerRange where     parseUnqt = do id1 <- parseUnqt-                   s   <- parseLayerSep+                   _   <- parseLayerSep                    id2 <- parseUnqt-                   return $ LRS id1 s id2+                   return $ LRS id1 id2                 `onFail`                 liftM LRID parseUnqt       parse = quotedParse ( do id1 <- parseUnqt-                             s   <- parseLayerSep+                             _   <- parseLayerSep                              id2 <- parseUnqt-                             return $ LRS id1 s id2+                             return $ LRS id1 id2                         )             `onFail`             liftM LRID parse@@ -1592,12 +1674,12 @@ parseLayerSep = many1 . oneOf                 $ map character defLayerSep +-- | The default separators for 'LayerSep'. defLayerSep :: [Char] defLayerSep = [' ', ':', '\t']  parseLayerName :: Parse String-parseLayerName = many1 . orQuote-                 $ satisfy (liftM2 (&&) notLayerSep (quoteChar /=))+parseLayerName = parseEscaped False [] defLayerSep  parseLayerName' :: Parse String parseLayerName' = stringBlock@@ -1607,11 +1689,11 @@ notLayerSep :: Char -> Bool notLayerSep = flip notElem defLayerSep --- | You should not have any quote characters for the 'LRName' option,---   as it won't be parseable.+-- | You should not have any layer separator characters for the+--   'LRName' option, as they won't be parseable. data LayerID = AllLayers              | LRInt Int-             | LRName String+             | LRName String -- ^ Should not be a number of @"all"@.                deriving (Eq, Ord, Show, Read)  instance PrintDot LayerID where@@ -1623,6 +1705,15 @@     -- Other two don't need quotes     toDot li          = unqtDot li +    unqtListToDot = hcat . punctuate s . map unqtDot+      where+        s = unqtDot $ head defLayerSep++    listToDot [l] = toDot l+    -- Might not need quotes, but probably will.  Can't tell either+    -- way since we don't know what the separator character will be.+    listToDot ll  = doubleQuotes $ unqtDot ll+ instance ParseDot LayerID where     parseUnqt = liftM checkLayerName parseLayerName -- tests for Int and All @@ -1637,31 +1728,23 @@                then AllLayers                else LRName str --- | The list represent (Separator, Name).  You should not have any---   quote characters for any of the 'String's, since there are---   parsing problems with them.-data LayerList = LL String [(String, String)]-                 deriving (Eq, Ord, Show, Read)+-- | A non-empty list of layer names.  The names should all be+--   'LRName' values, and when printed will use an arbitrary character+--   from 'defLayerSep'.+newtype LayerList = LL [LayerID]+                  deriving (Eq, Ord, Show, Read)  instance PrintDot LayerList where-    unqtDot (LL l1 ols) = unqtDot l1 <> hcat (map subLL ols)-        where-          subLL (s, l) = unqtDot s <> unqtDot l+  unqtDot (LL ll) = unqtDot ll -    toDot (LL l1 []) = toDot l1-    -- Might not need quotes, but probably will.-    toDot ll         = doubleQuotes $ unqtDot ll+  toDot (LL ll) = toDot ll  instance ParseDot LayerList where-    parseUnqt = do l1 <- parseLayerName-                   ols <- many $ do s   <- parseLayerSep-                                    lnm <- parseLayerName-                                    return (s, lnm)-                   return $ LL l1 ols+  parseUnqt = liftM LL $ sepBy1 parseUnqt parseLayerSep -    parse = quotedParse parseUnqt-            `onFail`-            liftM (flip LL []) (parseLayerName' `onFail` numString)+  parse = quotedParse parseUnqt+          `onFail`+          liftM (LL . (:[]) . LRName) stringBlock  -- ----------------------------------------------------------------------------- @@ -2219,11 +2302,14 @@                 _           -> DD str  parseStyleName :: Parse String-parseStyleName = do f <- orQuote . noneOf $ ' ' : disallowedChars-                    r <- many (orQuote $ noneOf disallowedChars)+parseStyleName = do f <- orEscaped . noneOf $ ' ' : disallowedChars+                    r <- parseEscaped True [] disallowedChars                     return $ f:r   where     disallowedChars = [quoteChar, '(', ')', ',']+    -- Used because the first character has slightly stricter requirements than the rest.+    orSlash p = stringRep '\\' "\\\\" `onFail` p+    orEscaped = orQuote . orSlash  -- ----------------------------------------------------------------------------- @@ -2254,6 +2340,7 @@      parse = quotedParse parseUnqt +-- | For use with 'ViewPort'. data FocusType = XY Point                | NodeFocus String                  deriving (Eq, Ord, Show, Read)
Data/GraphViz/Attributes/Internal.hs view
@@ -50,8 +50,8 @@   toDot = toDot . portName  instance ParseDot PortName where-  parseUnqt = liftM PN . many1-              . orQuote $ satisfy (`notElem` ['"', ':'])+  parseUnqt = liftM PN+              $ parseEscaped False [] ['"', ':']    parse= quotedParse parseUnqt          `onFail`
Data/GraphViz/Commands.hs view
@@ -59,7 +59,7 @@ import System.Exit(ExitCode(ExitSuccess)) import System.Process(runInteractiveProcess, waitForProcess) import Control.Concurrent(MVar, forkIO, newEmptyMVar, putMVar, takeMVar)-import Control.Exception.Extensible( SomeException(..), catch+import Control.Exception.Extensible( IOException, catch                                    , bracket, evaluate, handle) import Control.Monad(liftM) import System.FilePath((<.>))@@ -355,22 +355,25 @@             ExitSuccess -> return output             _           -> return $ Left $ othErr ++ err     where-      notRunnable e@SomeException{} = return . Left $ unwords-                                      [ "Unable to call the Graphviz command "-                                      , cmd'-                                      , " with the arguments: "-                                      , unwords args-                                      , " because of: "-                                      , show e-                                      ]+      notRunnable :: IOException -> IO (Either String a)+      notRunnable e = return . Left $ unwords+                      [ "Unable to call the Graphviz command "+                      , cmd'+                      , " with the arguments: "+                      , unwords args+                      , " because of: "+                      , show e+                      ]       cmd' = showCmd cmd       args = ["-T" ++ outputCall t]        -- Augmenting the f function to let it work within the forkIO:       f' h = liftM Right (f h)              `catch`-             (\e@SomeException{} -> return . Left $ fErr ++ show e)-      fErr = "Error re-directing the output from " ++ cmd' ++ ": "+             fErr+      fErr :: IOException -> IO (Either String a)+      fErr e = return . Left $ "Error re-directing the output from "+               ++ cmd' ++ ": " ++ show e        othErr = "Error messages from " ++ cmd' ++ ":\n" 
Data/GraphViz/Parsing.hs view
@@ -82,7 +82,9 @@ import Data.Char( digitToInt                 , isDigit                 , isSpace+                , isLower                 , toLower+                , toUpper                 ) import Data.Maybe(fromMaybe, isNothing) import Data.Ratio((%))@@ -204,7 +206,7 @@  -- | Used when quotes are explicitly required; quotedString :: Parse String-quotedString = parseEscaped True []+quotedString = parseEscaped True [] []  parseSigned :: Real a => Parse a -> Parse a parseSigned p = (character '-' >> liftM negate p)@@ -303,7 +305,10 @@               `adjustErr`               (++ "\nnot the expected char: " ++ [c])   where-    parseC c' = c' == c || toLower c == c'+    parseC c' = c' == c || c == flipCase c'+    flipCase c' = if isLower c'+                  then toUpper c'+                  else toLower c'  noneOf :: (Eq a) => [a] -> Parser a a noneOf t = satisfy (\x -> all (/= x) t)@@ -346,22 +351,24 @@ quoteChar :: Char quoteChar = '"' --- | Parse a 'String' where the provided 'Char's (as well as @\"@) are---   escaped.  Note: does not parse surrounding quotes, and assumes---   that @\\@ is not an escaped character.  The 'Bool' value---   indicates whether empty 'String's are allowed or not.-parseEscaped         :: Bool -> [Char] -> Parse String-parseEscaped empt cs = lots $ qPrs `onFail` oth+-- | Parse a 'String' where the provided 'Char's (as well as @\"@ and+--   @\\@) are escaped and the second list of 'Char's are those that+--   are not permitted.  Note: does not parse surrounding quotes.  The+--   'Bool' value indicates whether empty 'String's are allowed or+--   not.+parseEscaped             :: Bool -> [Char] -> [Char] -> Parse String+parseEscaped empt cs bnd = lots $ qPrs `onFail` oth   where     lots = if empt then many else many1-    cs' = quoteChar : cs+    cs' = quoteChar : slash : cs     csSet = Set.fromList cs'+    bndSet = Set.fromList bnd `Set.union` csSet     slash = '\\'     -- Have to allow standard slashes     qPrs = do character slash               mE <- optional $ oneOf (map character cs')               return $ fromMaybe slash mE-    oth = satisfy (`Set.notMember` csSet)+    oth = satisfy (`Set.notMember` bndSet)  newline :: Parse String newline = oneOf $ map string ["\r\n", "\n", "\r"]
Data/GraphViz/Printing.hs view
@@ -74,6 +74,7 @@ import Data.Char(toLower) import qualified Data.Set as Set import Data.Word(Word8, Word16)+import Control.Monad(ap)  -- ----------------------------------------------------------------------------- @@ -216,13 +217,23 @@ --   needs to pass the result from this to 'addQuotes' to determine if --   it needs to be quoted or not. addEscapes   :: [Char] -> String ->  String-addEscapes cs = foldr escape ""+addEscapes cs = foldr escape "" . withNext   where-    cs' = Set.fromList $ quote : cs+    cs' = Set.fromList $ quote : slash : cs     slash = '\\'     quote = '"'-    escape c str | c `Set.member` cs' = slash : c : str-                 | otherwise          = c : str+    escape (c,c') str+      | c == slash && c' `Set.member` escLetters = c : str+      | c `Set.member` cs'                       = slash : c : str+      | c == '\n'                                = slash : 'n' : str+      | otherwise                                = c : str++    -- When a slash precedes one of these characters, don't escape the slash.+    escLetters = Set.fromList ['N', 'G', 'E', 'T', 'H', 'L', 'n', 'l', 'r']++    -- Need to check subsequent characters when escaping slashes, but+    -- don't want to lose the last character when zipping, so append a space.+    withNext = zip `ap` ((++" ") . tail)  angled :: DotCode -> DotCode angled = wrap lang rang
Data/GraphViz/Testing/Instances.hs view
@@ -31,7 +31,6 @@ import qualified Data.Sequence as Seq import qualified Data.Map as Map import Control.Monad(liftM, liftM2, liftM3, liftM4)-import Data.Word(Word8, Word16)  -- ----------------------------------------------------------------------------- -- Defining Arbitrary instances for the overall types@@ -599,14 +598,6 @@ validUnknown _                    = True {- delete to here -} -instance Arbitrary Word8 where-  arbitrary = arbitraryBoundedIntegral-  shrink = shrinkIntegral--instance Arbitrary Word16 where-  arbitrary = arbitraryBoundedIntegral-  shrink = shrinkIntegral- instance Arbitrary ArrowType where   arbitrary = liftM AType               -- Arrow specifications have between 1 and 4 elements.@@ -637,7 +628,7 @@                                    return $ RatioPassCount ds is  instance Arbitrary Rect where-  arbitrary = liftM2 Rect arbitrary arbitrary+  arbitrary = liftM2 Rect point2D point2D    shrink (Rect p1 p2) = do p1s <- shrink p1                            p2s <- shrink p2@@ -645,12 +636,18 @@  instance Arbitrary Point where   -- Pretty sure points have to be positive...-  arbitrary = liftM2 Point posArbitrary posArbitrary+  arbitrary = liftM4 Point posArbitrary posArbitrary posZ arbitrary+    where+      posZ = frequency [(1, return Nothing), (3, liftM Just posArbitrary)] -  shrink (Point v1 v2) = do v1s <- shrink v1-                            v2s <- shrink v2-                            return $ Point v1s v2s+  shrink p = do x' <- shrink $ xCoord p+                y' <- shrink $ yCoord p+                z' <- shrinkM $ zCoord p+                return $ Point x' y' z' False +point2D :: Gen Point+point2D = liftM2 createPoint posArbitrary posArbitrary+ instance Arbitrary ClusterMode where   arbitrary = arbBounded @@ -662,7 +659,7 @@  instance Arbitrary DPoint where   arbitrary = oneof [ liftM DVal arbitrary-                    , liftM PVal arbitrary+                    , liftM PVal point2D                     ]    shrink (DVal d) = map DVal $ shrink d@@ -729,21 +726,22 @@   shrink _                 = []  instance Arbitrary LayerList where-  arbitrary = do fs <- arbLayerName-                 oths <- listOf $ liftM2 (,) arbLayerSep arbLayerName-                 return $ LL fs oths+  arbitrary = liftM LL $ listOf1 arbName+    where+      arbName = suchThat arbitrary isLayerName -  -- This should be improved to try actually shrinking the seps and names.-  -- shrink (LL _ [(_,fs')]) = [LL fs' []]-  -- shrink (LL fs oths)     = map (LL fs) $ shrink oths+      isLayerName LRName{} = True+      isLayerName _        = False +  shrink (LL ll) = map LL $ nonEmptyShrinks ll+ instance Arbitrary LayerRange where-  arbitrary = oneof [ liftM  LRID arbitrary-                    , liftM3 LRS arbitrary arbLayerSep arbitrary+  arbitrary = oneof [ liftM LRID arbitrary+                    , liftM2 LRS arbitrary arbitrary                     ] -  shrink (LRID nm)     = map LRID $ shrink nm-  shrink (LRS l1 _ l2) = [LRID l1, LRID l2]+  shrink (LRID nm)   = map LRID $ shrink nm+  shrink (LRS l1 l2) = [LRID l1, LRID l2]  instance Arbitrary LayerID where   arbitrary = oneof [ return AllLayers@@ -1132,8 +1130,8 @@   arbitrary = arbBounded  instance Arbitrary PortName where-  arbitrary = liftM PN . flip suchThat (liftM2 (&&) (not . null) notCP)-              $ liftM (filter (/= ':')) arbString+  arbitrary = liftM PN+              $ suchThat arbString (liftM2 (&&) (notElem ':') notCP)    shrink = map PN . filter notCP . shrinkString . portName @@ -1150,26 +1148,31 @@ posArbitrary = liftM fromPositive arbitrary  arbString :: Gen String-arbString = suchThat genStr validString+arbString = suchThat genStr notBool   where-    genStr = listOf1 $ elements strChr-    strChr = ['a'..'z'] ++ ['0'..'9'] ++ ['\'', '"', ' ', '(', ')'-                                         , ',', ':', '.']+    genStr = liftM2 (:) (elements notDigits) (listOf $ elements strChr)+    notDigits = ['a'..'z'] ++ ['\'', '"', ' ', '(', ')', ',', ':', '\\']+    strChr = notDigits ++ '.' : ['0'..'9'] +{-# INLINE arbString #-}+ arbIDString :: Gen String-arbIDString = suchThat genStr validString+arbIDString = suchThat genStr notBool   where     genStr = liftM2 (:) (elements frst) $ listOf (elements rest)     frst = ['a'..'z'] ++ ['_']     rest = frst ++ ['0'.. '9'] -validString         :: String -> Bool-validString "true"  = False-validString "false" = False-validString str     = notNumStr str+validString :: String -> Bool+validString = liftM2 (&&) notBool notNumStr +notBool         :: String -> Bool+notBool "true"  = False+notBool "false" = False+notBool _       = True+ shrinkString :: String -> [String]-shrinkString = filter validString . nonEmptyShrinks+shrinkString = filter validString . nonEmptyShrinks'  notNumStr :: String -> Bool notNumStr = not . isNumString@@ -1177,9 +1180,6 @@ arbBounded :: (Bounded a, Enum a) => Gen a arbBounded = elements [minBound .. maxBound] -arbLayerSep :: Gen [Char]-arbLayerSep = listOf1 (elements defLayerSep)- arbLayerName :: Gen String arbLayerName = suchThat arbString (all notLayerSep) @@ -1194,11 +1194,18 @@ nonEmptyShrinks :: (Arbitrary a) => [a] -> [[a]] nonEmptyShrinks = filter (not . null) . shrinkList +nonEmptyShrinks' :: [a] -> [[a]]+nonEmptyShrinks' = filter (not . null) . shrinkList'+ -- Shrink lists with more than one value only by removing values, not -- by shrinking individual items. shrinkList     :: (Arbitrary a) => [a] -> [[a]] shrinkList [a] = map return $ shrink a-shrinkList as  = rm (length as) as+shrinkList as  = shrinkList' as++-- Just shrink the size.+shrinkList'     :: [a] -> [[a]]+shrinkList' as  = rm (length as) as   where     rm 0 _  = []     rm 1 _  = [[]]
FAQ view
@@ -55,13 +55,18 @@   [output formats]: http://www.graphviz.org/doc/info/output.html  * Functions to convert [FGL] graphs to and from the internal Dot-  representations.+  representations.  In future, this will be expanded to a much larger+  range of graph-like values once a suitable abstraction is available.    [FGL]: http://web.engr.oregonstate.edu/~erwig/fgl/haskell/  * The ability to augment Dot and FGL graphs with positioning   information by round-trip passing through Graphviz. +* _graphviz_ is continually being worked upon and expanded to better+  suit/match the requirements of Graphviz, to improve performance and+  to make it easier for the programmer to use.+ ### Is the API of _graphviz_ stable? ###  For the most part, yes: the only items that are likely to change in@@ -110,9 +115,9 @@  * The deprecated `overlap` algorithms have not been defined. -* `pointf` and `point` values have been combined into one datatype;-  however the optional `!` and third value for `point` values is not-  accepted.+* `pointf` and `point` values have been combined into one datatype; as+  such, when constructing values such as `Rect` care should be taken+  about which parts of a `Point` are allowed.  * Only polygon-based `shape`s are available. @@ -151,6 +156,11 @@ * HTML-like and record labels are available, and feature proper   escaping/unescaping when printing/parsing. +* Other syntactic issues are taken care of for you automatically (such+  as escaping/unescaping quotation marks).  Even newlines are+  automatically escaped (but not unescaped) for you, defaulting to+  centered lines.+ Getting _graphviz_ and more documentation ----------------------------------------- @@ -201,7 +211,10 @@  ### Are there any tutorials on how to use _graphviz_? ### -There will be soon.+There will be soon.  The current stumbling block is that each time I+sit down to write a tutorial, I find that it would be even better if+_graphviz_ had some extra features in it first, so the tutorial has to+wait until I have finished that feature...  ### What other packages use _graphviz_? ### @@ -232,11 +245,11 @@  ### Can I start using _graphviz_ without knowing anything about Graphviz? ### -Unfortunately, no: the layout and design of _graphviz_ is heavily-based upon the Dot language and the various [attributes] that Graphviz-supports.  As such, you can't just suffice on the documentation-available in _graphviz_ (unless you're doing something _very_-simplistic).+You can, but if you want to start doing anything more advanced then+you should be reading Graphviz's documentation as well as+_graphviz_'s.  This is because the layout and design of _graphviz_ is+heavily based upon the Dot language and the various [attributes] that+Graphviz supports.  ### Can I just use _graphviz_ without reading its documentation? ### @@ -314,27 +327,31 @@      - `Color` to set the colour of an edge; if you supply more than       one value then the edge is drawn using parallel splines/lines-      (one per colour in the list).+      (one per colour in the list).  This can also be used to set the+      border colour for a node, but if a filled style is used and+      `FillColor` isn't set then this will also set the background+      colour.      - `PenColor` to set the colour of the bounding box for a cluster. -  When choosing a `Color` value for one of the above, it is better to-  use one of the `X11Color` values (note: these are **not** the same-  as the standard X11 colours) or - if you have to - one of the manual-  colours over a `BrewerColor`, as they come under a different license-  and have no real standard on what the values are.+        When choosing a `Color` value for one of the above, it is+        better to use one of the `X11Color` values (note: these+        colours slightly differ from the standard X11 colours) or - if+        you have to - one of the manual colours over a `BrewerColor`,+        as they come under a different license and have no real+        standard on what the values are. -* `Label`: `StrLabel` can be used for both nodes and edges; the other-  two only for nodes.  `RecordLabel` and `HtmlLabel` provide ways of-  having more fine-grained control over a node's layout with different-  sub-components, etc.; in most cases these won't be needed.+* For labels, use the `Labellable` class to more easily construct+  labels.  In most cases, a `String`-based label will suffice; for+  more fine-grained control over layout, colours, etc. use either a+  `RecordFields` or an `HtmlLabel`.  * `Rank`: this lets you control relative placement of sub-graphs and   clusters. -* `Shape`: Use `Record` and `MRecord` for `RecordLabel` labels; feel-  free to use any other ones at any time (though you probably want to-  use `PlainText` for `HtmlLabel` labels).+* `Shape`: Use `Record` and `MRecord` for `RecordFields`-based labels;+  feel free to use any other ones at any time (though you probably+  want to use `PlainText` for `HtmlLabel` labels).  * `Style`: use this to set line types, etc. for nodes and edges.  You   should **not** use a `DD` (device-dependent) value.@@ -345,7 +362,8 @@   but in future _graphviz_ will not contain this attribute and will   only allow UTF-8 usage. -* `Color` for anything except edge colours.+* `Color` for anything except edge colours (and if you must, the+  border colour for a node).  * `ColorScheme`: just stick with X11 colours. @@ -357,7 +375,7 @@  No: attributes are all defined in one big datatype for the sake of simplicity, but not all attributes are valid in all places.  Read the-documentation (either in Graphviz or _graphviz_) to determine which is+documentation (either for Graphviz or _graphviz_) to determine which is suitable where.  ### How can I use _graphviz_ to visualise non-FGL graphs? ###@@ -383,7 +401,7 @@ way of doing this is to have functions that convert between your type and `String` and let graphviz determine how to print and parse those. Here is an example of a more difficult type that should be printed-like "1: Foo":+like `"1: Foo"`:  ~~~~~~~~~~~~~~~~~~~~ {.haskell} data MyType = MyType String Int@@ -418,7 +436,7 @@   conversion functions (`int`, `text`, etc.) to ensure that   quotations, etc. are dealt with correctly. -* Be as liberal as you can when printing, especially with whitespace:+* Be as liberal as you can when parsing, especially with whitespace:   when printing only one space is used, yet when parsing we use the   `whitespace` parsing combinator that will parse all whitespace   characters (but it must consume _at least_ one; there is a variant@@ -449,6 +467,9 @@                          ] ~~~~~~~~~~~~~~~~~~~~ +I realise that doing this manually isn't as convenient, but I am open+to suggestions on how this can be improved.+ Note where `TailPort` and `HeadPort` are used; the next question explains this. @@ -609,7 +630,7 @@ copy of the darcs repository:  ~~~~~~~~~~~~~~~~~~~~ {.bash}-darcs get --lazy http://code.haskell.org/+darcs get --lazy http://code.haskell.org/graphviz ~~~~~~~~~~~~~~~~~~~~  Once you've made your changes, make sure you build and run the
graphviz.cabal view
@@ -1,5 +1,5 @@ Name:               graphviz-Version:            2999.10.0.1+Version:            2999.11.0.0 Stability:          Beta Synopsis:           Graphviz bindings for Haskell. Description: {@@ -63,8 +63,8 @@                            filepath,                            polyparse == 1.4.*,                            pretty,-                           bytestring < 0.10,-                           colour >= 2.3 && < 2.4,+                           bytestring == 0.9.*,+                           colour == 2.3.*,                            transformers == 0.2.*          Exposed-Modules:   Data.GraphViz@@ -84,7 +84,7 @@                            Data.GraphViz.Types.State                            Data.GraphViz.Util         if flag(test)-           Build-Depends:       QuickCheck >= 2.1 && < 2.2+           Build-Depends:       QuickCheck >= 2.3 && < 2.5             Exposed-Modules:     Data.GraphViz.Testing                                 Data.GraphViz.Testing.Properties