diagrams-lib-1.4.1.2: Embedded domain-specific language for declarative graphics

Copyright(c) 2013 Diagrams team (see LICENSE)
LicenseBSD-style (see LICENSE)
Maintainerdiagrams-discuss@googlegroups.com
Safe HaskellNone
LanguageHaskell2010

Diagrams.Backend.CmdLine

Contents

Description

Convenient creation of command-line-driven executables for rendering diagrams. This module provides a general framework and default behaviors for parsing command-line arguments, records for diagram creation options in various forms, and classes and instances for a unified entry point to command-line-driven diagram creation executables.

For a tutorial on command-line diagram creation see http://projects.haskell.org/diagrams/doc/cmdline.html.

Synopsis

Options

Standard options

data DiagramOpts #

Standard options most diagrams are likely to have.

Constructors

DiagramOpts 

Fields

Instances

Data DiagramOpts # 

Methods

gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b) -> (forall g. g -> c g) -> DiagramOpts -> c DiagramOpts #

gunfold :: (forall b r. Data b => c (b -> r) -> c r) -> (forall r. r -> c r) -> Constr -> c DiagramOpts #

toConstr :: DiagramOpts -> Constr #

dataTypeOf :: DiagramOpts -> DataType #

dataCast1 :: Typeable (* -> *) t => (forall d. Data d => c (t d)) -> Maybe (c DiagramOpts) #

dataCast2 :: Typeable (* -> * -> *) t => (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c DiagramOpts) #

gmapT :: (forall b. Data b => b -> b) -> DiagramOpts -> DiagramOpts #

gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> DiagramOpts -> r #

gmapQr :: (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> DiagramOpts -> r #

gmapQ :: (forall d. Data d => d -> u) -> DiagramOpts -> [u] #

gmapQi :: Int -> (forall d. Data d => d -> u) -> DiagramOpts -> u #

gmapM :: Monad m => (forall d. Data d => d -> m d) -> DiagramOpts -> m DiagramOpts #

gmapMp :: MonadPlus m => (forall d. Data d => d -> m d) -> DiagramOpts -> m DiagramOpts #

gmapMo :: MonadPlus m => (forall d. Data d => d -> m d) -> DiagramOpts -> m DiagramOpts #

Show DiagramOpts # 
Parseable DiagramOpts #

Parse DiagramOpts using the diagramOpts parser.

diagramOpts :: Parser DiagramOpts #

Command line parser for DiagramOpts. Width is option --width or -w. Height is option --height or -h (note we change help to be -? due to this). Output is option --output or -o.

Multi-diagram options

data DiagramMultiOpts #

Extra options for a program that can offer a choice between multiple diagrams.

Constructors

DiagramMultiOpts 

Fields

  • _selection :: Maybe String

    Selected diagram to render.

  • _list :: Bool

    Flag to indicate that a list of available diagrams should be printed to standard out.

Instances

Data DiagramMultiOpts # 

Methods

gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b) -> (forall g. g -> c g) -> DiagramMultiOpts -> c DiagramMultiOpts #

gunfold :: (forall b r. Data b => c (b -> r) -> c r) -> (forall r. r -> c r) -> Constr -> c DiagramMultiOpts #

toConstr :: DiagramMultiOpts -> Constr #

dataTypeOf :: DiagramMultiOpts -> DataType #

dataCast1 :: Typeable (* -> *) t => (forall d. Data d => c (t d)) -> Maybe (c DiagramMultiOpts) #

dataCast2 :: Typeable (* -> * -> *) t => (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c DiagramMultiOpts) #

gmapT :: (forall b. Data b => b -> b) -> DiagramMultiOpts -> DiagramMultiOpts #

gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> DiagramMultiOpts -> r #

gmapQr :: (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> DiagramMultiOpts -> r #

gmapQ :: (forall d. Data d => d -> u) -> DiagramMultiOpts -> [u] #

gmapQi :: Int -> (forall d. Data d => d -> u) -> DiagramMultiOpts -> u #

gmapM :: Monad m => (forall d. Data d => d -> m d) -> DiagramMultiOpts -> m DiagramMultiOpts #

gmapMp :: MonadPlus m => (forall d. Data d => d -> m d) -> DiagramMultiOpts -> m DiagramMultiOpts #

gmapMo :: MonadPlus m => (forall d. Data d => d -> m d) -> DiagramMultiOpts -> m DiagramMultiOpts #

Show DiagramMultiOpts # 
Parseable DiagramMultiOpts #

Parse DiagramMultiOpts using the diagramMultiOpts parser.

diagramMultiOpts :: Parser DiagramMultiOpts #

Command line parser for DiagramMultiOpts. Selection is option --selection or -S. List is --list or -L.

Animation options

data DiagramAnimOpts #

Extra options for animations.

Constructors

DiagramAnimOpts 

Fields

  • _fpu :: Double

    Number of frames per unit time to generate for the animation.

Instances

Data DiagramAnimOpts # 

Methods

gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b) -> (forall g. g -> c g) -> DiagramAnimOpts -> c DiagramAnimOpts #

gunfold :: (forall b r. Data b => c (b -> r) -> c r) -> (forall r. r -> c r) -> Constr -> c DiagramAnimOpts #

toConstr :: DiagramAnimOpts -> Constr #

dataTypeOf :: DiagramAnimOpts -> DataType #

dataCast1 :: Typeable (* -> *) t => (forall d. Data d => c (t d)) -> Maybe (c DiagramAnimOpts) #

dataCast2 :: Typeable (* -> * -> *) t => (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c DiagramAnimOpts) #

gmapT :: (forall b. Data b => b -> b) -> DiagramAnimOpts -> DiagramAnimOpts #

gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> DiagramAnimOpts -> r #

gmapQr :: (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> DiagramAnimOpts -> r #

gmapQ :: (forall d. Data d => d -> u) -> DiagramAnimOpts -> [u] #

gmapQi :: Int -> (forall d. Data d => d -> u) -> DiagramAnimOpts -> u #

gmapM :: Monad m => (forall d. Data d => d -> m d) -> DiagramAnimOpts -> m DiagramAnimOpts #

gmapMp :: MonadPlus m => (forall d. Data d => d -> m d) -> DiagramAnimOpts -> m DiagramAnimOpts #

gmapMo :: MonadPlus m => (forall d. Data d => d -> m d) -> DiagramAnimOpts -> m DiagramAnimOpts #

Show DiagramAnimOpts # 
Parseable DiagramAnimOpts #

Parse DiagramAnimOpts using the diagramAnimOpts parser.

diagramAnimOpts :: Parser DiagramAnimOpts #

Command line parser for DiagramAnimOpts Frames per unit is --fpu or -f.

Loop options

data DiagramLoopOpts #

Extra options for command-line looping.

Constructors

DiagramLoopOpts 

Fields

  • _loop :: Bool

    Flag to indicate that the program should loop creation.

  • _src :: Maybe FilePath

    File path for the source file to recompile.

  • _interval :: Int

    Interval in seconds at which to check for recompilation.

diagramLoopOpts :: Parser DiagramLoopOpts #

CommandLine parser for DiagramLoopOpts Loop is --loop or -l. Source is --src or -s. Interval is -i defaulting to one second.

Parsing

class Parseable a where #

Parseable instances give a command line parser for a type. If a custom parser for a common type is wanted a newtype wrapper could be used to make a new Parseable instance. Notice that we do not want as many instances as Read because we want to limit ourselves to things that make sense to parse from the command line.

Minimal complete definition

parser

Methods

parser :: Parser a #

Instances

Parseable Double #

Parse Double according to its Read instance.

Methods

parser :: Parser Double #

Parseable Int #

Parse Int according to its Read instance.

Methods

parser :: Parser Int #

Parseable () #

This instance is needed to signal the end of a chain of nested tuples, it always just results in the unit value without consuming anything.

Methods

parser :: Parser () #

Parseable String #

Parse a string by just accepting the given string.

Methods

parser :: Parser String #

Parseable DiagramOpts #

Parse DiagramOpts using the diagramOpts parser.

Parseable DiagramMultiOpts #

Parse DiagramMultiOpts using the diagramMultiOpts parser.

Parseable DiagramAnimOpts #

Parse DiagramAnimOpts using the diagramAnimOpts parser.

Parseable DiagramLoopOpts #

Parse DiagramLoopOpts using the diagramLoopOpts parser.

Parseable (Colour Double) #

Parse Colour Double as either a named color from Data.Colour.Names or a hexadecimal color.

Parseable (AlphaColour Double) #

Parse AlphaColour Double as either a named color from Data.Colour.Names or a hexadecimal color.

(Parseable a, Parseable b) => Parseable (a, b) #

Allow Parseable things to be combined.

Methods

parser :: Parser (a, b) #

(Parseable a, Parseable b, Parseable c) => Parseable (a, b, c) #

Triples of Parsebales should also be Parseable.

Methods

parser :: Parser (a, b, c) #

(Parseable a, Parseable b, Parseable c, Parseable d) => Parseable (a, b, c, d) # 

Methods

parser :: Parser (a, b, c, d) #

readHexColor :: (Applicative m, Monad m) => String -> m (AlphaColour Double) #

Parses a hexadecimal color. The string can start with "0x" or "#" or just be a string of hexadecimal values. If four or three digits are given each digit is repeated to form a full 24 or 32 bit color. For example, "0xfc4" is the same as "0xffcc44". When eight or six digits are given each pair of digits is a color or alpha channel with the order being red, green, blue, alpha.

Command-line programs (Mainable)

Arguments, rendering, and entry point

class Mainable d where #

This class represents the various ways we want to support diagram creation from the command line. It has the right instances to select between creating single static diagrams, multiple static diagrams, static animations, and functions that produce diagrams as long as the arguments are Parseable.

Backends are expected to create Mainable instances for the types that are suitable for generating output in the backend's format. For instance, Postscript can handle single diagrams, pages of diagrams, animations as separate files, and association lists. This implies instances for Diagram Postscript R2, [Diagram Postscript R2], Animation Postscript R2, and [(String,Diagram Postscript R2)]. We can consider these as the base cases for the function instance.

The associated type MainOpts describes the options which need to be parsed from the command-line and passed to mainRender.

Minimal complete definition

mainRender

Associated Types

type MainOpts d :: * #

Associated type that describes the options which need to be parsed from the command-line and passed to mainRender.

Methods

mainArgs :: Parseable (MainOpts d) => d -> IO (MainOpts d) #

This method invokes the command-line parser resulting in an options value or ending the program with an error or help message. Typically the default instance will work. If a different help message or parsing behavior is desired a new implementation is appropriate.

Note the d argument should only be needed to fix the type d. Its value should not be relied on as a parameter.

mainRender :: MainOpts d -> d -> IO () #

Backend specific work of rendering with the given options and mainable value is done here. All backend instances should implement this method.

mainWith :: Parseable (MainOpts d) => d -> IO () #

Main entry point for command-line diagram creation. This is the method that users will call from their program main. For instance an expected user program would take the following form.

import Diagrams.Prelude
import Diagrams.Backend.TheBestBackend.CmdLine

d :: Diagram B R2
d = ...

main = mainWith d

Most backends should be able to use the default implementation. A different implementation should be used to handle more complex interactions with the user.

Instances

Mainable d => Mainable (IO d) #

With this instance we can perform IO to produce something Mainable before rendering.

Associated Types

type MainOpts (IO d) :: * #

Methods

mainArgs :: IO d -> IO (MainOpts (IO d)) #

mainRender :: MainOpts (IO d) -> IO d -> IO () #

mainWith :: IO d -> IO () #

(ToResult d, Mainable (ResultOf d)) => Mainable (a -> d) #

This instance allows functions resulting in something that is Mainable to be Mainable. It takes a parse of collected arguments and applies them to the given function producing the Mainable result.

Associated Types

type MainOpts (a -> d) :: * #

Methods

mainArgs :: (a -> d) -> IO (MainOpts (a -> d)) #

mainRender :: MainOpts (a -> d) -> (a -> d) -> IO () #

mainWith :: (a -> d) -> IO () #

General currying

class ToResult d where #

This class allows us to abstract over functions that take some arguments and produce a final value. When some d is an instance of ToResult we get a type Args d that is a type of all the arguments at once, and a type ResultOf d that is the type of the final result from some base case instance.

Minimal complete definition

toResult

Associated Types

type Args d :: * #

type ResultOf d :: * #

Methods

toResult :: d -> Args d -> ResultOf d #

Instances

ToResult [(String, QDiagram b v n Any)] #

A list of named diagrams can give the multi-diagram interface.

Associated Types

type Args [(String, QDiagram b v n Any)] :: * #

type ResultOf [(String, QDiagram b v n Any)] :: * #

Methods

toResult :: [(String, QDiagram b v n Any)] -> Args [(String, QDiagram b v n Any)] -> ResultOf [(String, QDiagram b v n Any)] #

ToResult [QDiagram b v n Any] #

A list of diagrams can produce pages.

Associated Types

type Args [QDiagram b v n Any] :: * #

type ResultOf [QDiagram b v n Any] :: * #

Methods

toResult :: [QDiagram b v n Any] -> Args [QDiagram b v n Any] -> ResultOf [QDiagram b v n Any] #

ToResult d => ToResult (IO d) #

Diagrams that require IO to build are a base case.

Associated Types

type Args (IO d) :: * #

type ResultOf (IO d) :: * #

Methods

toResult :: IO d -> Args (IO d) -> ResultOf (IO d) #

ToResult d => ToResult (a -> d) #

An instance for a function that, given some a, can produce a d that is also an instance of ToResult. For this to work we need both the argument a and all the arguments that d will need. Producing the result is simply applying the argument to the producer and passing the remaining arguments to the produced producer.

Associated Types

type Args (a -> d) :: * #

type ResultOf (a -> d) :: * #

Methods

toResult :: (a -> d) -> Args (a -> d) -> ResultOf (a -> d) #

ToResult (Animation b v n) #

An animation is another suitable base case.

Associated Types

type Args (Animation b v n) :: * #

type ResultOf (Animation b v n) :: * #

Methods

toResult :: Animation b v n -> Args (Animation b v n) -> ResultOf (Animation b v n) #

ToResult (QDiagram b v n Any) #

A diagram can always produce a diagram when given () as an argument. This is our base case.

Associated Types

type Args (QDiagram b v n Any) :: * #

type ResultOf (QDiagram b v n Any) :: * #

Methods

toResult :: QDiagram b v n Any -> Args (QDiagram b v n Any) -> ResultOf (QDiagram b v n Any) #

helper functions for implementing mainRender

defaultAnimMainRender #

Arguments

:: (opts -> QDiagram b v n Any -> IO ()) 
-> Lens' opts FilePath

A lens into the output path.

-> (opts, DiagramAnimOpts) 
-> Animation b v n 
-> IO () 

defaultAnimMainRender is an implementation of mainRender which renders an animation as numbered frames, named by extending the given output file name by consecutive integers. For example if the given output file name is foo/blah.ext, the frames will be saved in foo/blah001.ext, foo/blah002.ext, and so on (the number of padding digits used depends on the total number of frames). It is up to the user to take these images and stitch them together into an actual animation format (using, e.g. ffmpeg).

Of course, this is a rather crude method of rendering animations; more sophisticated methods will likely be added in the future.

The fpu option from DiagramAnimOpts can be used to control how many frames will be output for each second (unit time) of animation.

This function requires a lens into the structure that the particular backend uses for it's diagram base case. If MainOpts (QDiagram b v n Any) ~ DiagramOpts then this lens will simply be output. For a backend supporting looping it will most likely be _1 . output. This lens is required because the implementation works by modifying the output field and running the base mainRender. Typically a backend can write its Animation B V instance as

  instance Mainable (Animation B V) where
      type MainOpts (Animation B V) = (DiagramOpts, DiagramAnimOpts)
      mainRender = defaultAnimMainRender output
  

We do not provide this instance in general so that backends can choose to opt-in to this form or provide a different instance that makes more sense.

defaultMultiMainRender :: Mainable d => (MainOpts d, DiagramMultiOpts) -> [(String, d)] -> IO () #

defaultMultiMainRender is an implementation of mainRender where instead of a single diagram it takes a list of diagrams paired with names as input. The generated executable then takes a --selection option specifying the name of the diagram that should be rendered. The list of available diagrams may also be printed by passing the option --list.

Typically a backend can write its [(String,QDiagram b v n Any)] instance as

  instance Mainable [(String,QDiagram b v n Any)] where
      type MainOpts [(String,QDiagram b v n Any)] = (DiagramOpts, DiagramMultiOpts)
      mainRender = defaultMultiMainRender
  

We do not provide this instance in general so that backends can choose to opt-in to this form or provide a different instance that makes more sense.