content: -- | This module contains data type for parsing exception and pretty
  -- formatting of such exceptions.
  
  module Importify.ParseException
         ( ModuleParseException (..)
         , eitherParseResult
         , reportErrorsIfAny
         , setMpeFile
         ) where
  
  import           Universum
  
  import           Fmt                   (Builder, blockListF, build, indentF, (+|), (|+))
  import           Language.Haskell.Exts (ParseResult (..), SrcLoc (srcFilename),
                                          prettyPrint)
  
  import           Extended.Data.Str     (charWrap, wordWrap)
  import           Extended.System.Wlog  (printWarning)
  
  data ModuleParseException = MPE !SrcLoc !String
      deriving (Show)
  
  instance Exception ModuleParseException
  instance Buildable ModuleParseException where
      build (MPE loc reason) = "Location:\n"
                            +| indentF 4 (build $ charWrap 80 $ prettyPrint loc)
                            |+ "Reason:\n"
                            +| indentF 4 (build $ wordWrap 80 reason)
                            |+ ""
  
  -- | Updates file name of error location. Sometimes error location
  -- looks like @- Location: : -1: -1@ which is not very helpful.
  setMpeFile :: FilePath -> ModuleParseException -> ModuleParseException
  setMpeFile modulePath (MPE loc msg) = MPE (loc {srcFilename = modulePath}) msg
  
  -- | Converts 'ParseResult' into 'Either' making error look pretty.
  eitherParseResult :: ParseResult res
                    -> Either ModuleParseException res
  eitherParseResult (ParseOk res)            = Right res
  eitherParseResult (ParseFailed loc reason) = Left $ MPE loc reason
  
  -- | Pretty printing 'NonEmpty' list of errors in really nice way.
  prettyParseErrors :: Text -> NonEmpty ModuleParseException -> Text
  prettyParseErrors libName exceptions =
      "Next errors occured during caching of package: "+|libName|+"\n"
   +| indentF 4 (blockListF exceptions) |+ ""
  
  -- | Prints parse errors if list of errors is not empty.
  reportErrorsIfAny :: [ModuleParseException] -> Text -> IO ()
  reportErrorsIfAny exceptions libName = whenNotNull exceptions $
      printWarning . prettyParseErrors libName
  