{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE FlexibleInstances #-} module Twitch.Internal where import System.FilePath ( FilePath ) import Control.Monad.Trans.State as State ( State, put, modify, execState, get ) import qualified Twitch.Rule as Rule ( addF, modifyF, deleteF, nameF ) import Twitch.Rule ( Rule ) import Data.String ( IsString(..) ) import Control.Applicative -- satisfy GHC < 7.10 import Data.Monoid -- satisfy GHC < 7.10 import Prelude hiding (FilePath) -- | A polymorphic 'Dep'. Exported for completeness, ignore. newtype DepM a = DepM { unDepM :: State [Rule] a} deriving ( Functor , Applicative , Monad ) instance Monoid a => Monoid (DepM a) where mempty = return mempty mappend x y = x >> y -- | This is the key type of the package, it is where rules are accumulated. type Dep = DepM () instance IsString Dep where fromString = addRule . fromString runDep :: Dep -> [Rule] runDep = runDepWithState mempty runDepWithState :: [Rule] -> Dep -> [Rule] runDepWithState xs = flip execState xs . unDepM addRule :: Rule -> Dep addRule r = DepM $ State.modify (r :) modHeadRule :: Dep -> (Rule -> Rule) -> Dep modHeadRule (DepM dep) f = DepM $ do dep get >>= \res -> case res of x:xs -> put $ f x : xs r -> put r -- Infix API ----------------------------------------------------------------- infixl 8 |+, |%, |-, |>, |# (|+), (|%), (|-), (|>) :: Dep -> (FilePath -> IO a) -> Dep -- | Add a \'add\' callback -- ex. -- -- > "*.png" |+ addToManifest x |+ f = modHeadRule x $ Rule.addF f -- | Add a \'modify\' callback -- ex. -- -- > "*.c" |% [s|gcc -o$directory$basename.o $path|] x |% f = modHeadRule x $ Rule.modifyF f -- | Add a \'delete' callback -- ex. -- -- > "*.c" |- [s|gcc -o$directory$basename.o $path|] x |- f = modHeadRule x $ Rule.deleteF f -- | Add the same callback for the \'add\' and the \'modify\' events. -- ex. -- -- > "*.md" |> [s|pandoc -t html $path|] -- -- Defined as: x '|>' f = x '|+' f '|%' f x |> f = x |+ f |% f -- | Set the name of a rule. Useful for debugging when logging is enabled. -- Rules names default to the glob pattern. -- ex. -- -- > "*.md" |> [s|pandoc -t html $path|] |# "markdown to html" (|#) :: Dep -> String -> Dep r |# p = modHeadRule r $ Rule.nameF p -- Prefix API ----------------------------------------------------------------- add, modify, delete, addModify :: (FilePath -> IO a) -> Dep -> Dep -- | Add a \'add\' callback -- ex. -- -- > add addToManifest "*.png" add = flip (|+) -- | Add a \'modify\' callback -- ex. -- -- > mod [s|gcc -o$directory$basename.o $path|] "*.c" modify = flip (|%) -- | Add a \'delete' callback -- ex. -- -- > delete [s|gcc -o$directory$basename.o $path|] "*.c" delete = flip (|-) -- | Add the same callback for the \'add\' and the \'modify\' events. -- ex. -- -- > addModify [s|pandoc -t html $path|] "*.md" addModify = flip (|>) -- | Set the name of a rule. Useful for debugging when logging is enabled. -- Rules names default to the glob pattern. -- ex. -- -- > name "markdown to html" $ addModify [s|pandoc -t html $path|] "*.md" name :: String -> Dep -> Dep name = flip (|#)