hinit-0.1.0: src/Hinit/Errors.hs
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE QuasiQuotes #-}
module Hinit.Errors where
import Control.Algebra
import Control.Effect.Lift
import Control.Effect.Terminal
import Control.Exception
import Data.String.Interpolate
import Data.Text (Text)
import Data.Text.Prettyprint.Doc
import Data.Text.Prettyprint.Doc.Render.Terminal
import Data.Void
import GHC.Generics
import Hinit.Utils
import Path
import System.Exit
import System.IO
import Text.Megaparsec.Error
import Text.Mustache.Render
import qualified Text.Parsec.Error as T
import Toml.Codec.Error
import Prelude hiding (print)
data ExprParseError = ExprParseError
{ expression :: Text,
errors :: [ParseError Text Void]
}
deriving (Eq, Generic)
deriving (Show) via PrettyShow ExprParseError
deriving anyclass (Exception)
instance Pretty ExprParseError where
pretty ExprParseError {..} =
vsep
[ [i|failed to parse boolean expressionession "#{expression}":|],
indent 2 $ mkBulletList $ map (pretty . parseErrorPretty) errors
]
data TomlFile
= Global
| Template Text
deriving (Eq)
instance Show TomlFile where
show Global = "global config file (~/.config/hi/config.toml)"
show (Template t) = [i|template config file from #{t}|]
data ConfigParseError = ConfigParseError
{ file :: TomlFile,
errors :: [TomlDecodeError]
}
deriving (Eq, Generic)
deriving (Show) via PrettyShow ConfigParseError
deriving anyclass (Exception)
instance Pretty ConfigParseError where
pretty ConfigParseError {..} =
vsep
[ [i|failed to parse #{file}:|],
indent 2 $ mkBulletList $ map (pretty . prettyTomlDecodeError) errors
]
data MustacheError
= forall a. RenderingError (Path Rel a) Bool [SubstitutionError]
| forall a. TemplateParseError (Path Rel a) Bool T.ParseError
deriving (Show) via PrettyShow MustacheError
deriving anyclass (Exception)
instance Pretty MustacheError where
pretty e
| (RenderingError p isFilename errors) <- e =
vsep
[ [i|failed to substitute the #{s isFilename} of file #{toFilePath p}:|],
indent 2 $ mkBulletList $ map viaShow errors
]
| (TemplateParseError p isFilename err) <- e =
vsep
[ [i|failed to parse the #{s isFilename} of file #{toFilePath p}:|],
indent 2 $ viaShow err
]
where
s :: Bool -> String
s True = "filename"
s False = "contents"
data IllformedPath
= TemplateName Text
| ProjectName Text
| forall a. TemplateFile (Path Rel a) Text
deriving (Show) via PrettyShow IllformedPath
deriving anyclass (Exception)
instance Pretty IllformedPath where
pretty (TemplateName s) =
[i|illformed template name "#{s}" (there should be no slashes in template names)|]
pretty (ProjectName s) =
[i|illformed project name "#{s}" (there should be no slashes in project names)|]
pretty (TemplateFile p f) =
[i|file "#{toFilePath p}"" has illformed name "#{f}" after substitution|]
newtype TemplateNotFound
= TemplateNotFound Text
deriving (Eq, Generic)
deriving (Show) via PrettyShow TemplateNotFound
deriving anyclass (Exception)
instance Pretty TemplateNotFound where
pretty (TemplateNotFound t) =
[i|template #{t} not found in both bundled templates and local templates|]
newtype ProjectAlreadExist
= ProjectAlreadExist Text
deriving (Eq, Generic)
deriving (Show) via PrettyShow ProjectAlreadExist
deriving anyclass (Exception)
instance Pretty ProjectAlreadExist where
pretty (ProjectAlreadExist a) =
[i|project #{a} already exists, to overwrite it use -f/--force|]
prettyPrintError :: Has Terminal sig m => Doc AnsiStyle -> m ()
prettyPrintError err = prettyPrint stderr doc
where
doc = (annotate (color Red) "Error" <> ":") <+> err
simpleHandler :: (Has Terminal sig m, Has (Lift IO) sig m, Pretty a) => a -> m ()
simpleHandler a = do
prettyPrintError $ pretty a
sendIO exitFailure