hinit-0.2.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.Types
import Hinit.Utils
import Path
import System.Exit
import System.IO
import System.Process
import Text.Megaparsec.Error
import Text.Mustache.Render
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 Text
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 $ pretty 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|]
newtype VcsCmdNotFound = VcsCmdNotFound VCS
deriving (Eq, Generic)
deriving (Show) via PrettyShow VcsCmdNotFound
deriving anyclass (Exception)
instance Pretty VcsCmdNotFound where
pretty (VcsCmdNotFound vcs) =
[i|vcs tool #{vcs} was not installed even though it was specified in your config|]
data ProcessExitFailure
= ProcessExitFailure CmdSpec Int String String
deriving (Eq, Generic)
deriving (Show) via PrettyShow ProcessExitFailure
deriving anyclass (Exception)
instance Pretty ProcessExitFailure where
pretty (ProcessExitFailure cmd e out err) =
vsep
[ [i|process "#{prettyCmd cmd}" failed with exit code #{e}|],
"stdout:",
indent 2 $ pretty out,
"stderr:",
indent 2 $ pretty err
]
where
prettyCmd (ShellCommand c) = c
prettyCmd (RawCommand c args) = unwords (c : args)
prettyPrintError :: Has Terminal sig m => Doc AnsiStyle -> m ()
prettyPrintError err = prettyPrint stderr doc
where
doc = (annotate (color Red) "Error" <> ":") <+> err
prettyPrintWarning :: Has Terminal sig m => Doc AnsiStyle -> m ()
prettyPrintWarning warning = prettyPrint stderr doc
where
doc = (annotate (color Yellow) "Warning" <> ":") <+> warning
simpleHandler :: (Has Terminal sig m, Has (Lift IO) sig m, Pretty a) => a -> m ()
simpleHandler a = do
prettyPrintError $ pretty a
sendIO exitFailure