module Data.GraphViz.Attributes.Internal
( PortName(..)
, PortPos(..)
, CompassPoint(..)
, compassLookup
, parseEdgeBasedPP
) where
import Data.GraphViz.Parsing
import Data.GraphViz.Printing
import Data.Map (Map)
import qualified Data.Map as Map
import Data.Maybe (isNothing)
import Data.Text.Lazy (Text)
newtype PortName = PN { portName :: Text }
deriving (Eq, Ord, Show, Read)
instance PrintDot PortName where
unqtDot = unqtDot . portName
toDot = toDot . portName
instance ParseDot PortName where
parseUnqt = PN <$> parseEscaped False [] ['"', ':']
parse = quotedParse parseUnqt
`onFail`
unqtPortName
unqtPortName :: Parse PortName
unqtPortName = PN <$> quotelessString
data PortPos = LabelledPort PortName (Maybe CompassPoint)
| CompassPoint CompassPoint
deriving (Eq, Ord, Show, Read)
instance PrintDot PortPos where
unqtDot (LabelledPort n mc) = unqtDot n
<> maybe empty (colon <>) (fmap unqtDot mc)
unqtDot (CompassPoint cp) = unqtDot cp
toDot (LabelledPort n Nothing) = toDot n
toDot lp@LabelledPort{} = dquotes $ unqtDot lp
toDot cp = unqtDot cp
instance ParseDot PortPos where
parseUnqt = do n <- parseUnqt
mc <- optional $ character ':' >> parseUnqt
return $ if isNothing mc
then checkPortName n
else LabelledPort n mc
parse = quotedParse parseUnqt
`onFail`
fmap checkPortName unqtPortName
checkPortName :: PortName -> PortPos
checkPortName pn = maybe (LabelledPort pn Nothing) CompassPoint
. (`Map.lookup` compassLookup)
$ portName pn
parseEdgeBasedPP :: Parse PortPos
parseEdgeBasedPP = liftA2 LabelledPort parse (fmap Just $ character ':' *> parse)
`onFail`
parse
data CompassPoint = North
| NorthEast
| East
| SouthEast
| South
| SouthWest
| West
| NorthWest
| CenterPoint
| NoCP
deriving (Eq, Ord, Bounded, Enum, Show, Read)
instance PrintDot CompassPoint where
unqtDot NorthEast = text "ne"
unqtDot NorthWest = text "nw"
unqtDot North = text "n"
unqtDot East = text "e"
unqtDot SouthEast = text "se"
unqtDot SouthWest = text "sw"
unqtDot South = text "s"
unqtDot West = text "w"
unqtDot CenterPoint = text "c"
unqtDot NoCP = text "_"
instance ParseDot CompassPoint where
parseUnqt = oneOf [ stringRep NorthEast "ne"
, stringRep NorthWest "nw"
, stringRep North "n"
, stringRep SouthEast "se"
, stringRep SouthWest "sw"
, stringRep South "s"
, stringRep East "e"
, stringRep West "w"
, stringRep CenterPoint "c"
, stringRep NoCP "_"
]
compassLookup :: Map Text CompassPoint
compassLookup = Map.fromList [ ("ne", NorthEast)
, ("nw", NorthWest)
, ("n", North)
, ("e", East)
, ("se", SouthEast)
, ("sw", SouthWest)
, ("s", South)
, ("w", West)
, ("c", CenterPoint)
, ("_", NoCP)
]