filepather-0.8.0.0: src/System/FilePather/Trail.hs
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# OPTIONS_GHC -Wall #-}
{- | The steps that built a file.
A 'Trail' is a product with one field, named 'steps'.
-}
module System.FilePather.Trail (
-- * Type
Trail (..),
-- * Traversals
trailFiles,
lastStep,
-- * Optics
TrailLike (..),
lawNamesTrail,
InheritTrail,
inheritTrail,
) where
import Control.DeepSeq (NFData)
import Control.Lens (AsEmpty (..), Cons (..), Each (..), Index, IxValue, Ixed (..), Optic, Reversing (..), Snoc (..), Traversal', cloneLens, nearly, prism, unsnoc, view, _head)
import Data.Data (Data)
import Data.Functor.Const (Const)
import GHC.Generics (Generic)
import System.FilePather.Name.StepInput (StepInputLike (..))
import System.FilePather.Name.Steps (StepsLike (..))
import System.FilePather.Step (Step)
{- $setup
>>> import Control.Lens ((^..), (^?))
>>> import System.FilePather.Step (Step (..))
>>> import System.FilePather.Name.StepName (stepName)
-}
{- | The steps that built a file ('steps'), nearest first: the step that made
the file, then the step that made its input, and so on, back to the step
whose input is a source file. A source file has the empty trail.
@since 0.7.0.0
-}
newtype Trail
= Trail [Step]
deriving stock (Eq, Ord, Show, Generic, Data)
deriving newtype (NFData, Semigroup, Monoid)
-- | @since 0.7.0.0
instance Cons Trail Trail Step Step where
_Cons =
prism
(\(s, Trail ss) -> Trail (s : ss))
( \(Trail x) ->
case x of
[] -> Left (Trail [])
s : ss -> Right (s, Trail ss)
)
{-# INLINE _Cons #-}
-- | @since 0.7.0.0
instance Snoc Trail Trail Step Step where
_Snoc =
prism
(\(Trail ss, s) -> Trail (ss <> [s]))
(\t@(Trail x) -> maybe (Left t) (\(ss, s) -> Right (Trail ss, s)) (unsnoc x))
{-# INLINE _Snoc #-}
-- | @since 0.7.0.0
instance AsEmpty Trail where
_Empty =
nearly (Trail []) (\(Trail x) -> null x)
{-# INLINE _Empty #-}
-- | @since 0.7.0.0
instance Each Trail Trail Step Step where
each =
steps . traverse
{-# INLINE each #-}
-- | @since 0.7.0.0
type instance Index Trail = Int
-- | @since 0.7.0.0
type instance IxValue Trail = Step
-- | @since 0.7.0.0
instance Ixed Trail where
ix i =
steps . ix i
{-# INLINE ix #-}
-- | @since 0.7.0.0
instance Reversing Trail where
reversing (Trail x) =
Trail (reverse x)
{-# INLINE reversing #-}
{- | The input files of the steps of a trail, nearest first.
>>> Trail [Step "pdf page 1" "public/a.pdf", Step "markdown to pdf" "src/a.md"] ^.. trailFiles
["public/a.pdf","src/a.md"]
@since 0.7.0.0
-}
trailFiles :: Traversal' Trail FilePath
trailFiles =
each . stepInput
{-# INLINE trailFiles #-}
{- | The last step of a trail: the step that made the file. A source file has
no last step.
>>> Trail [Step "pdf page 1" "public/a.pdf", Step "markdown to pdf" "src/a.md"] ^? lastStep . stepName
Just "pdf page 1"
>>> Trail [] ^? lastStep
Nothing
@since 0.7.0.0
-}
lastStep :: Traversal' Trail Step
lastStep =
steps . _head
{-# INLINE lastStep #-}
{- | The class of 'Trail'.
@since 0.8.0.0
-}
class TrailLike p f x x' where
trail ::
Optic p f x x' Trail Trail
{- | Identity
@since 0.8.0.0
-}
instance (x' ~ Trail) => TrailLike p f Trail x' where
trail =
id
{-# INLINE trail #-}
{- | Lens
@since 0.8.0.0
-}
instance (p ~ (->), Functor f, x' ~ Trail) => StepsLike p f Trail x' where
steps f (Trail x) =
fmap Trail (f x)
{-# INLINE steps #-}
{- | Rebuild a value using only the name of each field.
Laws:
> lawNamesTrail == id
@since 0.8.0.0
-}
lawNamesTrail :: Trail -> Trail
lawNamesTrail s =
Trail (view (cloneLens steps) s)
{- | The classes that a data type holding 'Trail' inherits.
@since 0.8.0.0
-}
type InheritTrail s =
( TrailLike (->) (Const ()) s s
, StepsLike (->) (Const ()) s s
)
{- | Check, where it is applied, that @s@ inherits every name of 'Trail'.
@since 0.8.0.0
-}
inheritTrail :: (InheritTrail s) => proxy s -> ()
inheritTrail _ =
()