content: {-# LANGUAGE CPP                  #-}
  {-# LANGUAGE ConstraintKinds      #-}
  {-# LANGUAGE FlexibleContexts     #-}
  {-# LANGUAGE FlexibleInstances    #-}
  {-# LANGUAGE OverloadedStrings    #-}
  {-# LANGUAGE TypeFamilies         #-}
  {-# LANGUAGE TypeSynonymInstances #-}
  {-# LANGUAGE UndecidableInstances #-}
  {-# OPTIONS_GHC -fno-warn-orphans #-}
  -----------------------------------------------------------------------------
  -- |
  -- Module      :  Diagrams.Backend.SVG.CmdLine
  -- Copyright   :  (c) 2013 Diagrams team (see LICENSE)
  -- License     :  BSD-style (see LICENSE)
  -- Maintainer  :  diagrams-discuss@googlegroups.com
  --
  -- Convenient creation of command-line-driven executables for
  -- rendering diagrams using the SVG backend.
  --
  -- * 'defaultMain' creates an executable which can render a single
  --   diagram at various options.
  --
  -- * 'multiMain' is like 'defaultMain' but allows for a list of
  --   diagrams from which the user can choose one to render.
  --
  -- * 'mainWith' is a generic form that does all of the above but with
  --   a slightly scarier type.  See "Diagrams.Backend.CmdLine".  This
  --   form can also take a function type that has a subtable final result
  --   (any of arguments to the above types) and 'Parseable' arguments.
  --
  -- If you want to generate diagrams programmatically---/i.e./ if you
  -- want to do anything more complex than what the below functions
  -- provide---you have several options.
  --
  -- * Use a function with 'mainWith'.  This may require making
  --   'Parseable' instances for custom argument types.
  --
  -- * Make a new 'Mainable' instance.  This may require a newtype
  --   wrapper on your diagram type to avoid the existing instances.
  --   This gives you more control over argument parsing, intervening
  --   steps, and diagram creation.
  --
  -- * Build option records and pass them along with a diagram to 'mainRender'
  --   from "Diagrams.Backend.CmdLine".
  --
  -- * You can use 'Diagrams.Backend.SVG.renderSVG' to render a diagram
  --   to a file directly; see "Diagrams.Backend.SVG".
  --
  -- * A more flexible approach is to directly call 'renderDia'; see
  --   "Diagrams.Backend.SVG" for more information.
  --
  -- For a tutorial on command-line diagram creation see
  -- <https://diagrams.github.io/doc/cmdline.html>.
  --
  -----------------------------------------------------------------------------
  
  module Diagrams.Backend.SVG.CmdLine
         (
           -- * General form of @main@
           -- $mainwith
  
           mainWith
  
           -- * Supported forms of @main@
  
         , defaultMain
         , multiMain
  
           -- * Backend tokens
  
         , SVG
         , B
         ) where
  
  import           Diagrams.Backend.CmdLine
  import           Diagrams.Backend.SVG
  import           Diagrams.Prelude         hiding (height, interval, output,
                                             width)
  
  import           Options.Applicative
  
  import           Data.List.Split
  
  -- $mainwith
  -- The 'mainWith' method unifies all of the other forms of @main@ and is
  -- now the recommended way to build a command-line diagrams program.  It
  -- works as a direct replacement for 'defaultMain' or 'multiMain' as well
  -- as allowing more general arguments.  For example, given a function that
  -- produces a diagram when given an @Int@ and a @'Colour' Double@, 'mainWith'
  -- will produce a program that looks for additional number and color arguments.
  --
  -- > ... definitions ...
  -- > f :: Int -> Colour Double -> Diagram SVG V2 Double
  -- > f i c = ...
  -- >
  -- > main = mainWith f
  --
  -- We can run this program as follows:
  --
  -- > $ ghc --make MyDiagram
  -- >
  -- > # output image.svg built by `f 20 red`
  -- > $ ./MyDiagram -o image.svg -w 200 20 red
  
  
  -- | This is the simplest way to render diagrams, and is intended to
  --   be used like so:
  --
  -- > ... definitions ...
  -- >
  -- > main = defaultMain myDiagram
  --
  --   Compiling this file will result in an executable which takes
  --   various command-line options for setting the size, output file,
  --   and so on, and renders @myDiagram@ with the specified options.
  --
  --   Pass @--help@ to the generated executable to see all available
  --   options.  Currently it looks something like
  --
  -- @
  -- ./Program
  --
  -- Usage: ./Program [-w|--width WIDTH] [-h|--height HEIGHT] [-o|--output OUTPUT] [--loop] [-s|--src ARG] [-i|--interval INTERVAL] [-p|--pretty]
  --   Command-line diagram generation.
  --
  -- Available options:
  --   -?,--help                Show this help text
  --   -w,--width WIDTH         Desired WIDTH of the output image
  --   -h,--height HEIGHT       Desired HEIGHT of the output image
  --   -o,--output OUTPUT       OUTPUT file
  --   -l,--loop                Run in a self-recompiling loop
  --   -s,--src ARG             Source file to watch
  --   -i,--interval INTERVAL   When running in a loop, check for changes every INTERVAL seconds.
  --   -p,--pretty              Pretty print the SVG output
  -- @
  --
  --   For example, a common scenario is
  --
  -- @
  -- $ ghc --make MyDiagram
  --
  --   # output image.svg with a width of 400pt (and auto-determined height)
  -- $ ./MyDiagram -o image.svg -w 400
  -- @
  
  defaultMain :: SVGFloat n => QDiagram SVG V2 n Any -> IO ()
  defaultMain = mainWith
  
  newtype PrettyOpt = PrettyOpt {isPretty :: Bool}
  
  prettyOpt :: Parser PrettyOpt
  prettyOpt = PrettyOpt <$> switch (long "pretty"
                       <> short 'p'
                       <> help "Pretty print the SVG output")
  
  instance Parseable PrettyOpt where
    parser = prettyOpt
  
  instance SVGFloat n => Mainable (QDiagram SVG V2 n Any) where
      type MainOpts (QDiagram SVG V2 n Any) = (DiagramOpts, PrettyOpt)
      mainRender (opts, pretty) d = chooseRender opts pretty d
  
  chooseRender :: SVGFloat n => DiagramOpts -> PrettyOpt -> QDiagram SVG V2 n Any -> IO ()
  chooseRender opts pretty d =
    case splitOn "." (opts^.output) of
      [""] -> putStrLn "No output file given."
      ps | last ps `elem` ["svg"] -> do
             let szSpec = fromIntegral <$> mkSizeSpec2D (opts^.width) (opts^.height)
             if isPretty pretty
               then renderPretty (opts^.output) szSpec d
               else renderSVG (opts^.output) szSpec d
         | otherwise -> putStrLn $ "Unknown file type: " ++ last ps
  
  -- | @multiMain@ is like 'defaultMain', except 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@.
  --
  --   Example usage:
  --
  -- @
  -- $ ghc --make MultiTest
  -- [1 of 1] Compiling Main             ( MultiTest.hs, MultiTest.o )
  -- Linking MultiTest ...
  -- $ ./MultiTest --list
  -- Available diagrams:
  --   foo bar
  -- $ ./MultiTest --selection bar -o Bar.eps -w 200
  -- @
  
  multiMain :: SVGFloat n => [(String, QDiagram SVG V2 n Any)] -> IO ()
  multiMain = mainWith
  
  instance SVGFloat n => Mainable [(String,QDiagram SVG V2 n Any)] where
      type MainOpts [(String,QDiagram SVG V2 n Any)]
          = (MainOpts (QDiagram SVG V2 n Any), DiagramMultiOpts)
  
      mainRender = defaultMultiMainRender
  