{-# LANGUAGE DeriveAnyClass #-}
{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}

{-# HLINT ignore "Use impureThrow" #-}

module Ema.Route.Lib.Extra.StaticRoute (
  StaticRoute,
  Model (..),

  -- * Helpers
  staticRouteUrl,
) where

import Control.Exception (throw)
import Control.Monad.Logger (MonadLogger, MonadLoggerIO)
import Data.List qualified as List
import Data.Map.Strict qualified as Map
import Data.Some (Some)
import Data.Time (UTCTime, defaultTimeLocale, formatTime, getCurrentTime)
import Ema
import Ema.CLI qualified
import GHC.TypeLits (KnownSymbol, Symbol, symbolVal)
import Optics.Core (Prism', prism')
import System.FilePath (takeExtension, (</>))
import System.UnionMount qualified as UnionMount
import UnliftIO (MonadUnliftIO)

-- | Route to a static file under @baseDir@.
newtype StaticRoute (baseDir :: Symbol) = StaticRoute {StaticRoute baseDir -> FilePath
unStaticRoute :: FilePath}
  deriving newtype (StaticRoute baseDir -> StaticRoute baseDir -> Bool
(StaticRoute baseDir -> StaticRoute baseDir -> Bool)
-> (StaticRoute baseDir -> StaticRoute baseDir -> Bool)
-> Eq (StaticRoute baseDir)
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
forall (baseDir :: Symbol).
StaticRoute baseDir -> StaticRoute baseDir -> Bool
/= :: StaticRoute baseDir -> StaticRoute baseDir -> Bool
$c/= :: forall (baseDir :: Symbol).
StaticRoute baseDir -> StaticRoute baseDir -> Bool
== :: StaticRoute baseDir -> StaticRoute baseDir -> Bool
$c== :: forall (baseDir :: Symbol).
StaticRoute baseDir -> StaticRoute baseDir -> Bool
Eq, Eq (StaticRoute baseDir)
Eq (StaticRoute baseDir)
-> (StaticRoute baseDir -> StaticRoute baseDir -> Ordering)
-> (StaticRoute baseDir -> StaticRoute baseDir -> Bool)
-> (StaticRoute baseDir -> StaticRoute baseDir -> Bool)
-> (StaticRoute baseDir -> StaticRoute baseDir -> Bool)
-> (StaticRoute baseDir -> StaticRoute baseDir -> Bool)
-> (StaticRoute baseDir
    -> StaticRoute baseDir -> StaticRoute baseDir)
-> (StaticRoute baseDir
    -> StaticRoute baseDir -> StaticRoute baseDir)
-> Ord (StaticRoute baseDir)
StaticRoute baseDir -> StaticRoute baseDir -> Bool
StaticRoute baseDir -> StaticRoute baseDir -> Ordering
StaticRoute baseDir -> StaticRoute baseDir -> StaticRoute baseDir
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall {baseDir :: Symbol}. Eq (StaticRoute baseDir)
forall (baseDir :: Symbol).
StaticRoute baseDir -> StaticRoute baseDir -> Bool
forall (baseDir :: Symbol).
StaticRoute baseDir -> StaticRoute baseDir -> Ordering
forall (baseDir :: Symbol).
StaticRoute baseDir -> StaticRoute baseDir -> StaticRoute baseDir
min :: StaticRoute baseDir -> StaticRoute baseDir -> StaticRoute baseDir
$cmin :: forall (baseDir :: Symbol).
StaticRoute baseDir -> StaticRoute baseDir -> StaticRoute baseDir
max :: StaticRoute baseDir -> StaticRoute baseDir -> StaticRoute baseDir
$cmax :: forall (baseDir :: Symbol).
StaticRoute baseDir -> StaticRoute baseDir -> StaticRoute baseDir
>= :: StaticRoute baseDir -> StaticRoute baseDir -> Bool
$c>= :: forall (baseDir :: Symbol).
StaticRoute baseDir -> StaticRoute baseDir -> Bool
> :: StaticRoute baseDir -> StaticRoute baseDir -> Bool
$c> :: forall (baseDir :: Symbol).
StaticRoute baseDir -> StaticRoute baseDir -> Bool
<= :: StaticRoute baseDir -> StaticRoute baseDir -> Bool
$c<= :: forall (baseDir :: Symbol).
StaticRoute baseDir -> StaticRoute baseDir -> Bool
< :: StaticRoute baseDir -> StaticRoute baseDir -> Bool
$c< :: forall (baseDir :: Symbol).
StaticRoute baseDir -> StaticRoute baseDir -> Bool
compare :: StaticRoute baseDir -> StaticRoute baseDir -> Ordering
$ccompare :: forall (baseDir :: Symbol).
StaticRoute baseDir -> StaticRoute baseDir -> Ordering
$cp1Ord :: forall {baseDir :: Symbol}. Eq (StaticRoute baseDir)
Ord, Int -> StaticRoute baseDir -> ShowS
[StaticRoute baseDir] -> ShowS
StaticRoute baseDir -> FilePath
(Int -> StaticRoute baseDir -> ShowS)
-> (StaticRoute baseDir -> FilePath)
-> ([StaticRoute baseDir] -> ShowS)
-> Show (StaticRoute baseDir)
forall a.
(Int -> a -> ShowS) -> (a -> FilePath) -> ([a] -> ShowS) -> Show a
forall (baseDir :: Symbol). Int -> StaticRoute baseDir -> ShowS
forall (baseDir :: Symbol). [StaticRoute baseDir] -> ShowS
forall (baseDir :: Symbol). StaticRoute baseDir -> FilePath
showList :: [StaticRoute baseDir] -> ShowS
$cshowList :: forall (baseDir :: Symbol). [StaticRoute baseDir] -> ShowS
show :: StaticRoute baseDir -> FilePath
$cshow :: forall (baseDir :: Symbol). StaticRoute baseDir -> FilePath
showsPrec :: Int -> StaticRoute baseDir -> ShowS
$cshowsPrec :: forall (baseDir :: Symbol). Int -> StaticRoute baseDir -> ShowS
Show)
  deriving stock ((forall x. StaticRoute baseDir -> Rep (StaticRoute baseDir) x)
-> (forall x. Rep (StaticRoute baseDir) x -> StaticRoute baseDir)
-> Generic (StaticRoute baseDir)
forall x. Rep (StaticRoute baseDir) x -> StaticRoute baseDir
forall x. StaticRoute baseDir -> Rep (StaticRoute baseDir) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall (baseDir :: Symbol) x.
Rep (StaticRoute baseDir) x -> StaticRoute baseDir
forall (baseDir :: Symbol) x.
StaticRoute baseDir -> Rep (StaticRoute baseDir) x
$cto :: forall (baseDir :: Symbol) x.
Rep (StaticRoute baseDir) x -> StaticRoute baseDir
$cfrom :: forall (baseDir :: Symbol) x.
StaticRoute baseDir -> Rep (StaticRoute baseDir) x
Generic)

data Model = Model
  { Model -> Some @Type Action
modelCliAction :: Some Ema.CLI.Action
  , Model -> Map FilePath UTCTime
modelFiles :: Map FilePath UTCTime
  }
  deriving stock (Model -> Model -> Bool
(Model -> Model -> Bool) -> (Model -> Model -> Bool) -> Eq Model
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Model -> Model -> Bool
$c/= :: Model -> Model -> Bool
== :: Model -> Model -> Bool
$c== :: Model -> Model -> Bool
Eq, Int -> Model -> ShowS
[Model] -> ShowS
Model -> FilePath
(Int -> Model -> ShowS)
-> (Model -> FilePath) -> ([Model] -> ShowS) -> Show Model
forall a.
(Int -> a -> ShowS) -> (a -> FilePath) -> ([a] -> ShowS) -> Show a
showList :: [Model] -> ShowS
$cshowList :: [Model] -> ShowS
show :: Model -> FilePath
$cshow :: Model -> FilePath
showsPrec :: Int -> Model -> ShowS
$cshowsPrec :: Int -> Model -> ShowS
Show, (forall x. Model -> Rep Model x)
-> (forall x. Rep Model x -> Model) -> Generic Model
forall x. Rep Model x -> Model
forall x. Model -> Rep Model x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Model x -> Model
$cfrom :: forall x. Model -> Rep Model x
Generic)

instance IsRoute (StaticRoute baseDir) where
  type RouteModel (StaticRoute baseDir) = Model
  routePrism :: RouteModel (StaticRoute baseDir)
-> Prism_ FilePath (StaticRoute baseDir)
routePrism (RouteModel (StaticRoute baseDir) -> Map FilePath UTCTime
Model -> Map FilePath UTCTime
modelFiles -> Map FilePath UTCTime
files) =
    let enc :: StaticRoute baseDir -> FilePath
enc =
          StaticRoute baseDir -> FilePath
forall (baseDir :: Symbol). StaticRoute baseDir -> FilePath
unStaticRoute
        dec :: FilePath -> Maybe (StaticRoute baseDir)
dec FilePath
fp =
          FilePath -> StaticRoute baseDir
forall (baseDir :: Symbol). FilePath -> StaticRoute baseDir
StaticRoute FilePath
fp StaticRoute baseDir -> Maybe () -> Maybe (StaticRoute baseDir)
forall (f :: Type -> Type) a b. Functor f => a -> f b -> f a
<$ Bool -> Maybe ()
forall (f :: Type -> Type). Alternative f => Bool -> f ()
guard (FilePath -> Map FilePath UTCTime -> Bool
forall k a. Ord k => k -> Map k a -> Bool
Map.member FilePath
fp Map FilePath UTCTime
files)
     in Prism' FilePath (StaticRoute baseDir)
-> Prism_ FilePath (StaticRoute baseDir)
forall s a. Prism' s a -> Prism_ s a
toPrism_ (Prism' FilePath (StaticRoute baseDir)
 -> Prism_ FilePath (StaticRoute baseDir))
-> Prism' FilePath (StaticRoute baseDir)
-> Prism_ FilePath (StaticRoute baseDir)
forall a b. (a -> b) -> a -> b
$ (StaticRoute baseDir -> FilePath)
-> (FilePath -> Maybe (StaticRoute baseDir))
-> Prism' FilePath (StaticRoute baseDir)
forall b s a. (b -> s) -> (s -> Maybe a) -> Prism s s a b
prism' StaticRoute baseDir -> FilePath
forall (baseDir :: Symbol). StaticRoute baseDir -> FilePath
enc FilePath -> Maybe (StaticRoute baseDir)
dec
  routeUniverse :: RouteModel (StaticRoute baseDir) -> [StaticRoute baseDir]
routeUniverse (RouteModel (StaticRoute baseDir) -> Map FilePath UTCTime
Model -> Map FilePath UTCTime
modelFiles -> Map FilePath UTCTime
files) =
    FilePath -> StaticRoute baseDir
forall (baseDir :: Symbol). FilePath -> StaticRoute baseDir
StaticRoute (FilePath -> StaticRoute baseDir)
-> [FilePath] -> [StaticRoute baseDir]
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> Map FilePath UTCTime -> [FilePath]
forall k a. Map k a -> [k]
Map.keys Map FilePath UTCTime
files

instance KnownSymbol baseDir => EmaSite (StaticRoute baseDir) where
  siteInput :: Some @Type Action
-> SiteArg (StaticRoute baseDir)
-> m (Dynamic m (RouteModel (StaticRoute baseDir)))
siteInput Some @Type Action
cliAct SiteArg (StaticRoute baseDir)
_ = do
    Dynamic m (Map FilePath UTCTime)
files <- FilePath -> m (Dynamic m (Map FilePath UTCTime))
forall (m :: Type -> Type).
(MonadIO m, MonadUnliftIO m, MonadLogger m, MonadLoggerIO m) =>
FilePath -> m (Dynamic m (Map FilePath UTCTime))
staticFilesDynamic (FilePath -> m (Dynamic m (Map FilePath UTCTime)))
-> FilePath -> m (Dynamic m (Map FilePath UTCTime))
forall a b. (a -> b) -> a -> b
$ Proxy @Symbol baseDir -> FilePath
forall (n :: Symbol) (proxy :: Symbol -> Type).
KnownSymbol n =>
proxy n -> FilePath
symbolVal (Proxy @Symbol baseDir
forall {k} (t :: k). Proxy @k t
Proxy @baseDir)
    Dynamic m Model -> m (Dynamic m Model)
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure (Dynamic m Model -> m (Dynamic m Model))
-> Dynamic m Model -> m (Dynamic m Model)
forall a b. (a -> b) -> a -> b
$ Some @Type Action -> Map FilePath UTCTime -> Model
Model Some @Type Action
cliAct (Map FilePath UTCTime -> Model)
-> Dynamic m (Map FilePath UTCTime) -> Dynamic m Model
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> Dynamic m (Map FilePath UTCTime)
files
  siteOutput :: Prism' FilePath (StaticRoute baseDir)
-> RouteModel (StaticRoute baseDir)
-> StaticRoute baseDir
-> m (SiteOutput (StaticRoute baseDir))
siteOutput Prism' FilePath (StaticRoute baseDir)
_ RouteModel (StaticRoute baseDir)
_ (StaticRoute FilePath
path) =
    Asset LByteString -> m (Asset LByteString)
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure (Asset LByteString -> m (Asset LByteString))
-> Asset LByteString -> m (Asset LByteString)
forall a b. (a -> b) -> a -> b
$ FilePath -> Asset LByteString
forall a. FilePath -> Asset a
Ema.AssetStatic (FilePath -> Asset LByteString) -> FilePath -> Asset LByteString
forall a b. (a -> b) -> a -> b
$ Proxy @Symbol baseDir -> FilePath
forall (n :: Symbol) (proxy :: Symbol -> Type).
KnownSymbol n =>
proxy n -> FilePath
symbolVal (Proxy @Symbol baseDir
forall {k} (t :: k). Proxy @k t
Proxy @baseDir) FilePath -> ShowS
</> FilePath
path

staticFilesDynamic ::
  forall m.
  (MonadIO m, MonadUnliftIO m, MonadLogger m, MonadLoggerIO m) =>
  FilePath ->
  m (Dynamic m (Map FilePath UTCTime))
staticFilesDynamic :: FilePath -> m (Dynamic m (Map FilePath UTCTime))
staticFilesDynamic FilePath
baseDir = do
  let pats :: [((), FilePath)]
pats = [((), FilePath
"**")]
      ignorePats :: [FilePath]
ignorePats = [FilePath
".*"]
      model0 :: Map FilePath UTCTime
model0 = Map FilePath UTCTime
forall a. Monoid a => a
mempty
  (Map FilePath UTCTime, (Map FilePath UTCTime -> m ()) -> m ())
-> Dynamic m (Map FilePath UTCTime)
forall (m :: Type -> Type) a.
(a, (a -> m ()) -> m ()) -> Dynamic m a
Dynamic ((Map FilePath UTCTime, (Map FilePath UTCTime -> m ()) -> m ())
 -> Dynamic m (Map FilePath UTCTime))
-> m (Map FilePath UTCTime, (Map FilePath UTCTime -> m ()) -> m ())
-> m (Dynamic m (Map FilePath UTCTime))
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> FilePath
-> [((), FilePath)]
-> [FilePath]
-> Map FilePath UTCTime
-> (()
    -> FilePath
    -> FileAction ()
    -> m (Map FilePath UTCTime -> Map FilePath UTCTime))
-> m (Map FilePath UTCTime, (Map FilePath UTCTime -> m ()) -> m ())
forall model (m :: Type -> Type) b.
(MonadIO m, MonadUnliftIO m, MonadLogger m, Show b, Ord b) =>
FilePath
-> [(b, FilePath)]
-> [FilePath]
-> model
-> (b -> FilePath -> FileAction () -> m (model -> model))
-> m (model, (model -> m ()) -> m ())
UnionMount.mount FilePath
baseDir [((), FilePath)]
pats [FilePath]
ignorePats Map FilePath UTCTime
model0 ((FilePath
 -> FileAction ()
 -> m (Map FilePath UTCTime -> Map FilePath UTCTime))
-> ()
-> FilePath
-> FileAction ()
-> m (Map FilePath UTCTime -> Map FilePath UTCTime)
forall a b. a -> b -> a
const FilePath
-> FileAction ()
-> m (Map FilePath UTCTime -> Map FilePath UTCTime)
handleUpdate)
  where
    handleUpdate ::
      FilePath ->
      UnionMount.FileAction () ->
      m (Map FilePath UTCTime -> Map FilePath UTCTime)
    handleUpdate :: FilePath
-> FileAction ()
-> m (Map FilePath UTCTime -> Map FilePath UTCTime)
handleUpdate FilePath
fp = \case
      UnionMount.Refresh RefreshAction
_ ()
_ -> do
        UTCTime
lastAccessed <- IO UTCTime -> m UTCTime
forall (m :: Type -> Type) a. MonadIO m => IO a -> m a
liftIO IO UTCTime
getCurrentTime
        (Map FilePath UTCTime -> Map FilePath UTCTime)
-> m (Map FilePath UTCTime -> Map FilePath UTCTime)
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure ((Map FilePath UTCTime -> Map FilePath UTCTime)
 -> m (Map FilePath UTCTime -> Map FilePath UTCTime))
-> (Map FilePath UTCTime -> Map FilePath UTCTime)
-> m (Map FilePath UTCTime -> Map FilePath UTCTime)
forall a b. (a -> b) -> a -> b
$ FilePath -> UTCTime -> Map FilePath UTCTime -> Map FilePath UTCTime
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert FilePath
fp UTCTime
lastAccessed
      FileAction ()
UnionMount.Delete -> do
        (Map FilePath UTCTime -> Map FilePath UTCTime)
-> m (Map FilePath UTCTime -> Map FilePath UTCTime)
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure ((Map FilePath UTCTime -> Map FilePath UTCTime)
 -> m (Map FilePath UTCTime -> Map FilePath UTCTime))
-> (Map FilePath UTCTime -> Map FilePath UTCTime)
-> m (Map FilePath UTCTime -> Map FilePath UTCTime)
forall a b. (a -> b) -> a -> b
$ FilePath -> Map FilePath UTCTime -> Map FilePath UTCTime
forall k a. Ord k => k -> Map k a -> Map k a
Map.delete FilePath
fp

-- | Like `Ema.routeUrl`, but looks up the value and appends it to URL in live-server (for force-reload in browser)
staticRouteUrl ::
  forall s baseDir.
  (IsString s, HasCallStack) =>
  Prism' FilePath (StaticRoute baseDir) ->
  RouteModel (StaticRoute baseDir) ->
  FilePath ->
  s
staticRouteUrl :: Prism' FilePath (StaticRoute baseDir)
-> RouteModel (StaticRoute baseDir) -> FilePath -> s
staticRouteUrl Prism' FilePath (StaticRoute baseDir)
rp RouteModel (StaticRoute baseDir)
model FilePath
fp =
  let lastAccessed :: UTCTime
lastAccessed = FilePath -> Model -> UTCTime
lookupMust FilePath
fp RouteModel (StaticRoute baseDir)
Model
model
      tag :: Text
tag = FilePath -> Text
forall a. ToText a => a -> Text
toText (FilePath -> Text) -> FilePath -> Text
forall a b. (a -> b) -> a -> b
$ TimeLocale -> FilePath -> UTCTime -> FilePath
forall t. FormatTime t => TimeLocale -> FilePath -> t -> FilePath
formatTime TimeLocale
defaultTimeLocale FilePath
"%s" UTCTime
lastAccessed
      url :: Text
url = Prism' FilePath (StaticRoute baseDir)
-> StaticRoute baseDir -> Text
forall r. HasCallStack => Prism' FilePath r -> r -> Text
Ema.routeUrl Prism' FilePath (StaticRoute baseDir)
rp (StaticRoute baseDir -> Text) -> StaticRoute baseDir -> Text
forall a b. (a -> b) -> a -> b
$ FilePath -> StaticRoute baseDir
forall (baseDir :: Symbol). FilePath -> StaticRoute baseDir
StaticRoute FilePath
fp
   in FilePath -> s
forall a. IsString a => FilePath -> a
fromString (FilePath -> s) -> (Text -> FilePath) -> Text -> s
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> FilePath
forall a. ToString a => a -> FilePath
toString (Text -> s) -> Text -> s
forall a b. (a -> b) -> a -> b
$ Text
url Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text
refreshAddendum Text
tag
  where
    -- Force the browser to reload the static file referenced
    refreshAddendum :: Text -> Text
refreshAddendum Text
tag =
      Text -> Maybe Text -> Text
forall a. a -> Maybe a -> a
fromMaybe Text
"" (Maybe Text -> Text) -> Maybe Text -> Text
forall a b. (a -> b) -> a -> b
$ do
        -- In live server, force reload all (re-added/modified) static files.
        -- In statically generated site, do it only for CSS and JS files.
        Bool -> Maybe ()
forall (f :: Type -> Type). Alternative f => Bool -> f ()
guard (Bool -> Maybe ()) -> Bool -> Maybe ()
forall a b. (a -> b) -> a -> b
$
          Some @Type Action -> Bool
Ema.CLI.isLiveServer (Model -> Some @Type Action
modelCliAction RouteModel (StaticRoute baseDir)
Model
model)
            Bool -> Bool -> Bool
|| ShowS
takeExtension FilePath
fp FilePath -> [FilePath] -> Bool
forall (t :: Type -> Type) a.
(Foldable t, Eq a) =>
a -> t a -> Bool
`List.elem` [FilePath
".css", FilePath
".js"]
        Text -> Maybe Text
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure (Text -> Maybe Text) -> Text -> Maybe Text
forall a b. (a -> b) -> a -> b
$ Text
"?" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
tag

lookupMust :: FilePath -> Model -> UTCTime
lookupMust :: FilePath -> Model -> UTCTime
lookupMust FilePath
fp Model
model =
  case FilePath -> Map FilePath UTCTime -> Maybe UTCTime
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup FilePath
fp (Model -> Map FilePath UTCTime
modelFiles Model
model) of
    Just UTCTime
lastAccessed -> UTCTime
lastAccessed
    Maybe UTCTime
Nothing -> MissingStaticFile -> UTCTime
forall a e. Exception e => e -> a
throw (MissingStaticFile -> UTCTime) -> MissingStaticFile -> UTCTime
forall a b. (a -> b) -> a -> b
$ FilePath -> MissingStaticFile
MissingStaticFile FilePath
fp

newtype MissingStaticFile = MissingStaticFile FilePath
  deriving stock (MissingStaticFile -> MissingStaticFile -> Bool
(MissingStaticFile -> MissingStaticFile -> Bool)
-> (MissingStaticFile -> MissingStaticFile -> Bool)
-> Eq MissingStaticFile
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: MissingStaticFile -> MissingStaticFile -> Bool
$c/= :: MissingStaticFile -> MissingStaticFile -> Bool
== :: MissingStaticFile -> MissingStaticFile -> Bool
$c== :: MissingStaticFile -> MissingStaticFile -> Bool
Eq, Int -> MissingStaticFile -> ShowS
[MissingStaticFile] -> ShowS
MissingStaticFile -> FilePath
(Int -> MissingStaticFile -> ShowS)
-> (MissingStaticFile -> FilePath)
-> ([MissingStaticFile] -> ShowS)
-> Show MissingStaticFile
forall a.
(Int -> a -> ShowS) -> (a -> FilePath) -> ([a] -> ShowS) -> Show a
showList :: [MissingStaticFile] -> ShowS
$cshowList :: [MissingStaticFile] -> ShowS
show :: MissingStaticFile -> FilePath
$cshow :: MissingStaticFile -> FilePath
showsPrec :: Int -> MissingStaticFile -> ShowS
$cshowsPrec :: Int -> MissingStaticFile -> ShowS
Show)
  deriving anyclass (Show MissingStaticFile
Typeable @Type MissingStaticFile
Typeable @Type MissingStaticFile
-> Show MissingStaticFile
-> (MissingStaticFile -> SomeException)
-> (SomeException -> Maybe MissingStaticFile)
-> (MissingStaticFile -> FilePath)
-> Exception MissingStaticFile
SomeException -> Maybe MissingStaticFile
MissingStaticFile -> FilePath
MissingStaticFile -> SomeException
forall e.
Typeable @Type e
-> Show e
-> (e -> SomeException)
-> (SomeException -> Maybe e)
-> (e -> FilePath)
-> Exception e
displayException :: MissingStaticFile -> FilePath
$cdisplayException :: MissingStaticFile -> FilePath
fromException :: SomeException -> Maybe MissingStaticFile
$cfromException :: SomeException -> Maybe MissingStaticFile
toException :: MissingStaticFile -> SomeException
$ctoException :: MissingStaticFile -> SomeException
$cp2Exception :: Show MissingStaticFile
$cp1Exception :: Typeable @Type MissingStaticFile
Exception)