module Drasil.Build.Artifacts.Render
  ( Renderable (..),
  )
where

import Prettyprinter qualified as PNew
import Prettyprinter.Render.Text (renderIO)
import System.File.OsPath (withFile)
import System.IO (Handle, IOMode (..), hPutStr)
import System.OsPath (OsPath)
import Text.PrettyPrint qualified as PLegacy
import Prelude hiding (writeFile)

-- | Render a document and write it to a file (with a trailing newline always
-- added).
class Renderable doc where
  renderToFile :: OsPath -> doc -> IO ()

instance Renderable PLegacy.Doc where
  -- Does conversion to `String` and then does plain `String -> IO ()` writing.
  renderToFile :: OsPath -> Doc -> IO ()
renderToFile OsPath
fp = OsPath -> String -> IO ()
writeFileStr OsPath
fp (String -> IO ()) -> (Doc -> String) -> Doc -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Doc -> String
PLegacy.render (Doc -> String) -> (Doc -> Doc) -> Doc -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Doc -> Doc -> Doc
PLegacy.$+$ String -> Doc
PLegacy.text String
"")

instance Renderable (PNew.Doc ann) where
  -- `renderIO` skips intermediate representations before writing to disk:
  -- <https://hackage-content.haskell.org/package/prettyprinter-1.7.2/docs/Prettyprinter-Render-Text.html#v:renderIO>
  renderToFile :: OsPath -> Doc ann -> IO ()
renderToFile OsPath
fp Doc ann
d = OsPath -> (Handle -> IO ()) -> IO ()
forall r. OsPath -> (Handle -> IO r) -> IO r
writeFile OsPath
fp ((Handle -> IO ()) -> IO ()) -> (Handle -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Handle
h ->
    Handle -> SimpleDocStream ann -> IO ()
forall ann. Handle -> SimpleDocStream ann -> IO ()
renderIO Handle
h (LayoutOptions -> Doc ann -> SimpleDocStream ann
forall ann. LayoutOptions -> Doc ann -> SimpleDocStream ann
PNew.layoutPretty LayoutOptions
PNew.defaultLayoutOptions (Doc ann -> SimpleDocStream ann) -> Doc ann -> SimpleDocStream ann
forall a b. (a -> b) -> a -> b
$ Doc ann
d Doc ann -> Doc ann -> Doc ann
forall a. Semigroup a => a -> a -> a
PNew.<> Doc ann
forall ann. Doc ann
PNew.line)

-- | Write a 'String' to the given 'OsPath'.
writeFileStr :: OsPath -> String -> IO ()
writeFileStr :: OsPath -> String -> IO ()
writeFileStr OsPath
rp String
s = OsPath -> IOMode -> (Handle -> IO ()) -> IO ()
forall r. OsPath -> IOMode -> (Handle -> IO r) -> IO r
withFile OsPath
rp IOMode
WriteMode (Handle -> String -> IO ()
`hPutStr` String
s)
{-# INLINE writeFileStr #-}

-- | Write to a given 'OsPath' with arbitrary method.
writeFile :: OsPath -> (Handle -> IO r) -> IO r
writeFile :: forall r. OsPath -> (Handle -> IO r) -> IO r
writeFile OsPath
rp = OsPath -> IOMode -> (Handle -> IO r) -> IO r
forall r. OsPath -> IOMode -> (Handle -> IO r) -> IO r
withFile OsPath
rp IOMode
WriteMode
{-# INLINE writeFile #-}