{-# LANGUAGE OverloadedStrings #-}

-- | This module contains the implementation of the @dhall format@ subcommand

module Dhall.Format
    ( -- * Format
      format
    ) where

import Dhall.Parser (exprAndHeaderFromText)
import Dhall.Pretty (CharacterSet(..), annToAnsiStyle, layoutOpts)

import Data.Monoid ((<>))

import qualified Data.Text.Prettyprint.Doc                 as Pretty
import qualified Data.Text.Prettyprint.Doc.Render.Terminal as Pretty
import qualified Control.Exception
import qualified Data.Text.IO
import qualified Dhall.Pretty
import qualified System.Console.ANSI
import qualified System.IO

-- | Implementation of the @dhall format@ subcommand
format
    :: CharacterSet
    -> Maybe FilePath
    -- ^ Modify file in-place if present, otherwise read from @stdin@ and write
    --   to @stdout@
    -> IO ()
format characterSet inplace = do
        case inplace of
            Just file -> do
                text <- Data.Text.IO.readFile file
                (header, expr) <- case exprAndHeaderFromText "(stdin)" text of
                    Left  err -> Control.Exception.throwIO err
                    Right x   -> return x

                let doc =   Pretty.pretty header
                        <>  Pretty.unAnnotate (Dhall.Pretty.prettyCharacterSet characterSet expr)
                System.IO.withFile file System.IO.WriteMode (\handle -> do
                    Pretty.renderIO handle (Pretty.layoutSmart layoutOpts doc)
                    Data.Text.IO.hPutStrLn handle "" )
            Nothing -> do
                inText <- Data.Text.IO.getContents

                (header, expr) <- case exprAndHeaderFromText "(stdin)" inText of
                    Left  err -> Control.Exception.throwIO err
                    Right x   -> return x

                let doc =   Pretty.pretty header
                        <>  Dhall.Pretty.prettyCharacterSet characterSet expr

                supportsANSI <- System.Console.ANSI.hSupportsANSI System.IO.stdout

                if supportsANSI
                  then
                    Pretty.renderIO
                      System.IO.stdout
                      (fmap annToAnsiStyle (Pretty.layoutSmart layoutOpts doc))
                  else
                    Pretty.renderIO
                      System.IO.stdout
                      (Pretty.layoutSmart layoutOpts (Pretty.unAnnotate doc))