module System.Directory.Layout.QQ (dedent) where
import Data.Char (isSpace)
import Data.List (intercalate)
import Language.Haskell.TH.Quote (QuasiQuoter(..))
import Language.Haskell.TH.Syntax (liftString)
import Language.Haskell.TH (Q, Exp)
dedent :: QuasiQuoter
dedent = quoter $
liftString . intercalate "\n" . stripCommonLeadingWhitespace . dropFirst (all isSpace) . lines
dropFirst :: (a -> Bool) -> [a] -> [a]
dropFirst _ [] = []
dropFirst p (x : xs)
| p x = xs
| otherwise = x : xs
stripCommonLeadingWhitespace :: [String] -> [String]
stripCommonLeadingWhitespace xs = map (drop (commonLeadingWhitespace xs)) xs
commonLeadingWhitespace :: [String] -> Int
commonLeadingWhitespace = minimumOr 0 . map (length . takeWhile isSpace)
minimumOr :: Ord a => a -> [a] -> a
minimumOr n [] = n
minimumOr _ xs = minimum xs
quoter :: (String -> Q Exp) -> QuasiQuoter
quoter quote = QuasiQuoter
{ quoteExp = quote
, quotePat = failure "patterns"
, quoteType = failure "types"
, quoteDec = failure "declarations"
}
where
failure kind =
fail $ "this quasiquoter does not support splicing " ++ kind