minirotate-0.1.2.0: src/Pattern.hs
{-# LANGUAGE TemplateHaskell #-}
module Pattern where
import System.Time
import System.FilePath
import System.Locale ( defaultTimeLocale )
import Data.Accessor
import Data.Accessor.Basic ( get )
import Data.Accessor.Template
import Data.List.Split ( split, dropBlanks, whenElt )
import Text.Printf
import Control.Monad.Error () -- brings instance for Monad (Either String b)
import Debug.Trace
import System.IO.Unsafe ( unsafePerformIO )
type ErrString = String
data PatternEnv = PatternEnv { file_ :: FilePath
, basename_ :: FilePath
, ext_ :: FilePath
, modtime_ :: ClockTime
}
$( deriveAccessors ''PatternEnv )
makeEnv mt fp =
PatternEnv { file_ = takeFileName fp
, basename_ = takeBaseName fp
, ext_ = takeExtension fp
, modtime_ = mt
}
-- | compile file pattern and produce function that maps clock time and file name into resulting file name
compilePattern :: String -> Either ErrString (ClockTime -> String -> String)
compilePattern pat = case compilePatternLow pat of
Left err -> Left err
Right fun -> Right (\mt fp -> fun (makeEnv mt fp))
-- | compile pattern into environment-taking function that returns final string
compilePatternLow pat = let f <> g = \e -> (f e) ++ (g e)
aux acc [] = return acc
aux acc ("{":funargs:"}":rest) = do
let (fun,spaceargs) = break (==' ') funargs
args = dropWhile (== ' ') spaceargs
newFun <- getFunction fun args
aux (acc <> newFun) rest
aux acc ("{":_) = fail "Bad format: unterminated '{'"
aux acc (sth:rest) = aux (acc <> const sth) rest
in
aux (const "") (split (whenElt (`elem` "{}")) pat)
-- | return function that applied to environment will return string
getFunction "file" "" = Right (get file)
getFunction "ext" "" = Right (get ext)
getFunction "basename" "" = Right (get basename)
getFunction "file" _ = Left "Function 'file' takes no arguments."
getFunction "ext" _ = Left "Function 'ext' takes no arguments."
getFunction "basename" _ = Left "Function 'basename' takes no arguments."
getFunction "modtime" [] = Left "Function 'modtime' requires format string as an argument."
getFunction "modtime" format = Right (\ env -> let mt = (get modtime) $ env
ct = unsafePerformIO (toCalendarTime mt)
in
formatCalendarTime defaultTimeLocale format ct)
getFunction xx yy = Left (printf "Unknown function: '%s', args: %s" xx (show yy))