-- |module for reading many template definitions from files module Text.StringTemplates.Files (getTemplates) where import Data.Char (isAlphaNum) import Data.List (intercalate, isPrefixOf) import Data.Maybe (maybeToList) import System.IO -- |parses template definitions read from the file path (using utf8) -- definitions are separated by >=1 lines starting with '#' -- if first line of definition looks like foo=bar, then it returns -- (foo, bar ++ rest of the lines (from definition) concatenated) -- broken definitons are skipped -- -- Example template file: -- -- @ -- foo= -- \ -- \ -- \

hello \

-- \ -- \ -- ### -- bar=\BAR\ -- @ getTemplates :: FilePath -- ^ file path of a file with template definitions -> IO [(String, String)] getTemplates fp = withFile fp ReadMode $ \handle -> do hSetEncoding handle utf8 parseTemplates handle -- parses template definitions from the handle -- definitions are separated by >=1 lines starting with '#' -- if first line of definition looks like foo=bar, then it returns -- (foo, bar ++ rest of the lines (from definition) concatenated) -- broken definitons are skipped parseTemplates :: Handle -> IO [(String,String)] parseTemplates handle = do e <- hIsEOF handle if (e) then return [] else do t <- parseTemplate handle ts <- parseTemplates handle return $ (maybeToList t) ++ ts -- reads many lines from the handle, stopping at -- first line starting with '#', (read from the handle, not used) -- if line should looks like "foo=bar", then it returns -- Just (foo, bar ++ rest of the lines concatenated) -- otherwise Nothing parseTemplate :: Handle -> IO (Maybe (String, String)) parseTemplate handle = do ls <- parseLines handle let (name,t) = break (== '=') $ head ls if (null ls || null (name) || null t) then return Nothing else do let template = intercalate "\r\n" ((tail t): (tail ls)) return $ Just (filter isAlphaNum name,template) -- returns list of lines read from the handle -- stops at first line starting with '#' -- (it's read from the handle, but not returned) parseLines :: Handle -> IO [String] parseLines handle = do l <- hGetLine handle e <- hIsEOF handle if (isPrefixOf ("#") l) then return [] else if e then return [l] else fmap ((:) l) (parseLines handle)