content: 
  {-# LANGUAGE OverloadedStrings #-}
  
  -- | The final purpose of this module is to render a Text value
  --   from a 'LaTeX' value. The interface is abstracted via a typeclass
  --   so you can cast to 'Text' other types as well. Also, some other
  --   handy 'Text'-related functions are defined.
  module Text.LaTeX.Base.Render
   ( -- * Re-exports
     Text
   , module Data.String
     -- * Render class
   , Render (..)
   , renderAppend
   , renderChars
   , renderCommas
   , renderFile
   , rendertex
     -- * Reading files
   , readFileTex
     -- * Util
   , showFloat
     ) where
  
  import Text.LaTeX.Base.Syntax
  import Text.LaTeX.Base.Class
  import Data.String
  import Data.List (intersperse)
  import qualified Data.ByteString as B
  import Data.Word (Word8)
  import Numeric (showFFloat)
  import Data.Text (Text,lines,unlines)
  import Data.Text.Encoding
  import Data.Text.Lazy (toStrict)
  import Data.Text.Lazy.Builder (Builder)
  import qualified Data.Text.Lazy.Builder as Builder
  import qualified Data.Text.Lazy.Builder.Int as Builder
  import qualified Data.Text.Lazy.Builder.RealFloat as Builder
  
  -- | Class of values that can be transformed to 'Text'.
  -- You mainly will use this to obtain the 'Text' output
  -- of a 'LaTeX' value. If you are going to write the result
  -- in a file, consider to use 'renderFile'.
  --
  -- Consider also to use 'rendertex' to get 'Render'able values
  -- into 'LaTeX' blocks.
  --
  -- If you want to make a type instance of 'Render' and you already
  -- have a 'Show' instance, you can use the default instance.
  --
  -- > render = fromString . show
  --
  class Show a => Render a where
   render :: a -> Text
   renderBuilder :: a -> Builder
   --
   render = fromString . show
   renderBuilder = Builder.fromText . render
  
  renderDefault :: Render a => a -> Text
  renderDefault = toStrict . Builder.toLazyText . renderBuilder
  
  -- | This instance escapes LaTeX reserved characters.
  instance Render Text where
   render = protectText
  
  -- | Render every element of a list and append results.
  renderAppend :: Render a => [a] -> Text
  renderAppend = mconcat . fmap render
  
  renderAppendBuilder :: Render a => [a] -> Builder
  renderAppendBuilder = foldMap renderBuilder
  
  -- | Render every element of a list and append results,
  --   separated by the given 'Char'.
  renderChars :: Render a => Char -> [a] -> Text
  renderChars c = mconcat . intersperse (fromString [c]) . fmap render
  
  renderCharsBuilder :: Render a => Char -> [a] -> Builder
  renderCharsBuilder c = mconcat . intersperse (Builder.singleton c) . fmap renderBuilder
  
  -- | Render every element of a list and append results,
  --   separated by commas.
  renderCommas :: Render a => [a] -> Text
  renderCommas = renderChars ','
  
  renderCommasBuilder :: Render a => [a] -> Builder
  renderCommasBuilder = renderCharsBuilder ','
  
  -- | Use this function to render a 'LaTeX' (or another
  --   one in the 'Render' class) value directly
  --   in a file.
  renderFile :: Render a => FilePath -> a -> IO ()
  renderFile f = B.writeFile f . encodeUtf8 . render
  
  -- | If you are going to insert the content of a file
  -- in your 'LaTeX' data, use this function to ensure
  -- your encoding is correct.
  readFileTex :: FilePath -> IO Text
  readFileTex = fmap decodeUtf8 . B.readFile
  
  -- | If you can transform a value to 'Text', you can
  --   insert that 'Text' in your 'LaTeX' code.
  --   That is what this function does.
  --
  -- /Warning: /'rendertex'/ does not escape LaTeX reserved characters./
  -- /Use /'protectText'/ to escape them./
  rendertex :: (Render a,LaTeXC l) => a -> l
  rendertex = fromLaTeX . TeXRaw . render
  
  -- Render instances
  
  instance Render Measure where
   render (Pt x) = render x <> "pt"
   render (Mm x) = render x <> "mm"
   render (Cm x) = render x <> "cm"
   render (In x) = render x <> "in"
   render (Ex x) = render x <> "ex"
   render (Em x) = render x <> "em"
   render (CustomMeasure x) = render x
  
  -- LaTeX instances
  
  instance Render LaTeX where
    
    renderBuilder (TeXRaw t) = Builder.fromText t
    
    renderBuilder (TeXComm name []) = "\\" <> fromString name <> "{}"
    renderBuilder (TeXComm name args) =
        "\\"
     <> fromString name
     <> renderAppendBuilder args
    renderBuilder (TeXCommS name) = "\\" <> fromString name
    
    renderBuilder (TeXEnv name args c) =
        "\\begin{"
     <> fromString name
     <> "}"
     <> renderAppendBuilder args
     <> renderBuilder c
     <> "\\end{"
     <> fromString name
     <> "}"
  
    renderBuilder (TeXMath Dollar l) = "$" <> renderBuilder l <> "$"
    renderBuilder (TeXMath DoubleDollar l) = "$$" <> renderBuilder l <> "$$"
    renderBuilder (TeXMath Square l) = "\\[" <> renderBuilder l <> "\\]"
    renderBuilder (TeXMath Parentheses l) = "\\(" <> renderBuilder l <> "\\)"
  
    renderBuilder (TeXLineBreak m b) = "\\\\" <> maybe mempty (\x -> "[" <> renderBuilder x <> "]") m <> ( if b then "*" else mempty )
  
    renderBuilder (TeXBraces l) = "{" <> renderBuilder l <> "}"
  
    renderBuilder (TeXComment c) =
     let xs = Data.Text.lines c
     in if null xs then "%\n"
                   else Builder.fromText $ Data.Text.unlines $ fmap ("%" <>) xs
  
    renderBuilder (TeXSeq l1 l2) = renderBuilder l1 <> renderBuilder l2
    renderBuilder TeXEmpty = mempty
  
    render = renderDefault
  
  instance Render TeXArg where
   renderBuilder (FixArg l) = "{" <> renderBuilder l <> "}"
   renderBuilder (OptArg l) = "[" <> renderBuilder l <> "]"
   renderBuilder (MOptArg []) = mempty
   renderBuilder (MOptArg ls) = "[" <> renderCommasBuilder ls <> "]"
   renderBuilder (SymArg l) = "<" <> renderBuilder l <> ">"
   renderBuilder (MSymArg []) = mempty
   renderBuilder (MSymArg ls) = "<" <> renderCommasBuilder ls <> ">"
   renderBuilder (ParArg l) = "(" <> renderBuilder l <> ")"
   renderBuilder (MParArg []) = mempty
   renderBuilder (MParArg ls) = "(" <> renderCommasBuilder ls <> ")"
   render = renderDefault
  
  -- Other instances
  
  -- | Show a signed floating number using standard decimal notation using 5 decimals.
  showFloat :: RealFloat a => a -> String
  showFloat x = showFFloat (Just 5) x []
  
  instance Render Int where
    renderBuilder = Builder.decimal
    render = renderDefault
  
  instance Render Integer where
    renderBuilder = Builder.decimal
    render = renderDefault
  
  instance Render Float where
    renderBuilder = Builder.formatRealFloat Builder.Fixed (Just 5)
    render = renderDefault
  
  instance Render Double where
    renderBuilder = Builder.formatRealFloat Builder.Fixed (Just 5)
    render = renderDefault
  
  instance Render Word8 where
    renderBuilder = Builder.decimal
    render = renderDefault
  
  -- | 'Render' instance for 'Bool'. It satisfies @render True = "true"@ and @render False = "false"@.
  instance Render Bool where
    render True = "true"
    render _ = "false"
  
  instance Render a => Render [a] where
   renderBuilder xs = "[" <> renderCommasBuilder xs <> "]"
   render = renderDefault
  