{-# LANGUAGE CPP #-}

-- | 'LaTeX' values pretty printer.
--
--   Still experimental. Give it a try and send us your feedback! :)
module Text.LaTeX.Base.Pretty (
    -- * @LaTeX@ pretty printer
    prettyLaTeX
    -- * Configurable printer
  , docLaTeX
  ) where

import Text.LaTeX.Base.Syntax
import Text.LaTeX.Base.Render
import Data.Text.Prettyprint.Doc
  ( Doc, pretty
  , backslash, line, softline, hardline
  , braces, brackets
  , indent, align, vsep
  , list, encloseSep
  , LayoutOptions (..)
  , PageWidth (..)
  , layoutSmart
    )
import Data.Text.Prettyprint.Doc.Render.String (renderString)
import Data.Text (unpack,lines)
#if !MIN_VERSION_base(4,8,0)
import Data.Monoid (mconcat,mempty)
#endif

text :: Text -> Doc ann
text :: forall ann. Text -> Doc ann
text = forall a ann. Pretty a => a -> Doc ann
pretty

-- | This function transforms a value of type 'LaTeX' to a 'Doc'.
--   You can then choose how to print this 'Doc' value using
--   the function from the "Text.PrettyPrint.Free" module.
docLaTeX :: LaTeX -> Doc ()
docLaTeX :: LaTeX -> Doc ()
docLaTeX (TeXRaw Text
t) = forall a ann. Pretty a => a -> Doc ann
pretty forall a b. (a -> b) -> a -> b
$ Text -> String
unpack Text
t
docLaTeX (TeXComm String
n [TeXArg]
as) = forall ann. Doc ann
backslash forall a. Semigroup a => a -> a -> a
<> forall a ann. Pretty a => a -> Doc ann
pretty String
n forall a. Semigroup a => a -> a -> a
<> forall ann. Doc ann -> Doc ann
align (forall a. Monoid a => [a] -> a
mconcat (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap TeXArg -> Doc ()
docTeXArg [TeXArg]
as)) forall a. Semigroup a => a -> a -> a
<> forall ann. Doc ann
softline
docLaTeX (TeXCommS String
n) = forall ann. Doc ann
backslash forall a. Semigroup a => a -> a -> a
<> forall a ann. Pretty a => a -> Doc ann
pretty String
n forall a. Semigroup a => a -> a -> a
<> forall ann. Doc ann
softline
docLaTeX (TeXEnv String
n [TeXArg]
as LaTeX
b) =
  let a :: TeXArg
a = LaTeX -> TeXArg
FixArg forall a b. (a -> b) -> a -> b
$ forall a. IsString a => String -> a
fromString String
n
  in  forall a. Monoid a => [a] -> a
mconcat
       [ forall ann. Doc ann
line
       , LaTeX -> Doc ()
docLaTeX forall a b. (a -> b) -> a -> b
$ String -> [TeXArg] -> LaTeX
TeXComm String
"begin" forall a b. (a -> b) -> a -> b
$ TeXArg
a forall a. a -> [a] -> [a]
: [TeXArg]
as
       , forall ann. Int -> Doc ann -> Doc ann
indent Int
4 forall a b. (a -> b) -> a -> b
$ LaTeX -> Doc ()
docLaTeX LaTeX
b
       , forall ann. Doc ann
line
       , LaTeX -> Doc ()
docLaTeX forall a b. (a -> b) -> a -> b
$ String -> [TeXArg] -> LaTeX
TeXComm String
"end" [TeXArg
a]
         ]
docLaTeX (TeXMath MathType
t LaTeX
b) =
  let (Text
l,Text
r) =
        case MathType
t of
          MathType
Parentheses -> (Text
"\\(",Text
"\\)")
          MathType
Square -> (Text
"\\[",Text
"\\]")
          MathType
Dollar -> (Text
"$",Text
"$")
          MathType
DoubleDollar -> (Text
"$$",Text
"$$")
  in  forall ann. Text -> Doc ann
text Text
l forall a. Semigroup a => a -> a -> a
<> LaTeX -> Doc ()
docLaTeX LaTeX
b forall a. Semigroup a => a -> a -> a
<> forall ann. Text -> Doc ann
text Text
r
docLaTeX (TeXLineBreak Maybe Measure
m Bool
b) =
  forall ann. Text -> Doc ann
text Text
"\\\\" forall a. Semigroup a => a -> a -> a
<> forall b a. b -> (a -> b) -> Maybe a -> b
maybe forall a. Monoid a => a
mempty (forall ann. Doc ann -> Doc ann
brackets forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a ann. Pretty a => a -> Doc ann
pretty forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
unpack forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Render a => a -> Text
render) Maybe Measure
m forall a. Semigroup a => a -> a -> a
<> ( if Bool
b then forall ann. Text -> Doc ann
text Text
"*" else forall a. Monoid a => a
mempty )
docLaTeX (TeXBraces LaTeX
b) = forall ann. Doc ann -> Doc ann
braces forall a b. (a -> b) -> a -> b
$ LaTeX -> Doc ()
docLaTeX LaTeX
b
docLaTeX (TeXComment Text
t) =
  let ls :: [Text]
ls = Text -> [Text]
Data.Text.lines Text
t
  in  if forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Text]
ls
         then forall a ann. Pretty a => a -> Doc ann
pretty Char
'%' forall a. Semigroup a => a -> a -> a
<> forall ann. Doc ann
hardline
         else forall ann. Doc ann -> Doc ann
align (forall ann. [Doc ann] -> Doc ann
vsep forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall a ann. Pretty a => a -> Doc ann
pretty forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String
"% "forall a. [a] -> [a] -> [a]
++) forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
unpack) [Text]
ls) forall a. Semigroup a => a -> a -> a
<> forall ann. Doc ann
hardline
docLaTeX (TeXSeq LaTeX
l1 LaTeX
l2) = LaTeX -> Doc ()
docLaTeX LaTeX
l1 forall a. Semigroup a => a -> a -> a
<> LaTeX -> Doc ()
docLaTeX LaTeX
l2
docLaTeX LaTeX
TeXEmpty = forall a. Monoid a => a
mempty

docTeXArg :: TeXArg -> Doc ()
docTeXArg :: TeXArg -> Doc ()
docTeXArg (FixArg LaTeX
l) = forall ann. Doc ann -> Doc ann
braces forall a b. (a -> b) -> a -> b
$ LaTeX -> Doc ()
docLaTeX LaTeX
l
docTeXArg (OptArg LaTeX
l) = forall ann. Doc ann -> Doc ann
brackets forall a b. (a -> b) -> a -> b
$ LaTeX -> Doc ()
docLaTeX LaTeX
l
docTeXArg (MOptArg [LaTeX]
ls) =
  if forall (t :: * -> *) a. Foldable t => t a -> Bool
null [LaTeX]
ls then forall a. Monoid a => a
mempty
             else forall ann. [Doc ann] -> Doc ann
list forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap LaTeX -> Doc ()
docLaTeX [LaTeX]
ls
docTeXArg (SymArg LaTeX
l) = TeXArg -> Doc ()
docTeXArg forall a b. (a -> b) -> a -> b
$ [LaTeX] -> TeXArg
MSymArg [LaTeX
l]
docTeXArg (MSymArg [LaTeX]
ls) = forall ann. Doc ann -> Doc ann -> Doc ann -> [Doc ann] -> Doc ann
encloseSep (forall a ann. Pretty a => a -> Doc ann
pretty Char
'<') (forall a ann. Pretty a => a -> Doc ann
pretty Char
'>') (forall a ann. Pretty a => a -> Doc ann
pretty Char
',') forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap LaTeX -> Doc ()
docLaTeX [LaTeX]
ls
docTeXArg (ParArg LaTeX
l) = TeXArg -> Doc ()
docTeXArg forall a b. (a -> b) -> a -> b
$ [LaTeX] -> TeXArg
MParArg [LaTeX
l]
docTeXArg (MParArg [LaTeX]
ls) = forall ann. Doc ann -> Doc ann -> Doc ann -> [Doc ann] -> Doc ann
encloseSep (forall a ann. Pretty a => a -> Doc ann
pretty Char
'(') (forall a ann. Pretty a => a -> Doc ann
pretty Char
')') (forall a ann. Pretty a => a -> Doc ann
pretty Char
',') forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap LaTeX -> Doc ()
docLaTeX [LaTeX]
ls

-- | Pretty print a 'LaTeX' value. It produces a more human-friendly output than 'render'.
--
--   This function should be used only for debugging purposes since it may change
--   the semantics of the input in order to create a prettier output.
--   In other words, running a LaTeX compiler in the output file of @renderFile fp l@ may
--   produce a different document than running it in the output of @writeFile fp (prettyLaTeX l)@.
--   You should use 'renderFile' unless you really need to read the LaTeX file.
--
prettyLaTeX :: LaTeX -> String
prettyLaTeX :: LaTeX -> String
prettyLaTeX = forall ann. SimpleDocStream ann -> String
renderString forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall ann. LayoutOptions -> Doc ann -> SimpleDocStream ann
layoutSmart LayoutOptions
layout forall b c a. (b -> c) -> (a -> b) -> a -> c
. LaTeX -> Doc ()
docLaTeX

layout :: LayoutOptions
layout :: LayoutOptions
layout = PageWidth -> LayoutOptions
LayoutOptions forall a b. (a -> b) -> a -> b
$ Int -> Double -> PageWidth
AvailablePerLine Int
60 Double
1