content: {-# LANGUAGE FlexibleContexts, ScopedTypeVariables #-}
  --------------------------------------------------------------------------------
  -- | Miscellaneous string manipulation functions.
  module Hakyll.Core.Util.String
      ( trim
      , replaceAll
      , splitAll
      , needlePrefix
      , removeWinPathSeparator
      ) where
  
  
  --------------------------------------------------------------------------------
  import Data.Char (isSpace)
  import Data.List (isPrefixOf)
  import Text.Regex.TDFA ((=~~))
  
  
  --------------------------------------------------------------------------------
  -- | Trim a string (drop spaces, tabs and newlines at both sides).
  trim :: String -> String
  trim = reverse . trim' . reverse . trim'
    where
      trim' = dropWhile isSpace
  
  
  --------------------------------------------------------------------------------
  -- | A simple (but inefficient) regex replace funcion
  replaceAll :: String              -- ^ Pattern
             -> (String -> String)  -- ^ Replacement (called on match)
             -> String              -- ^ Source string
             -> String              -- ^ Result
  replaceAll pattern f source = replaceAll' source
    where
      replaceAll' ""  = ""
      replaceAll' src = case src =~~ pattern of
          Nothing                       -> src
          Just (before, capture, after) -> before ++ f capture ++ replaceAll' after
  
  
  --------------------------------------------------------------------------------
  -- | A simple regex split function. The resulting list will contain no empty
  -- strings.
  splitAll :: String    -- ^ Pattern
           -> String    -- ^ String to split
           -> [String]  -- ^ Result
  splitAll pattern = filter (not . null) . splitAll'
    where
      splitAll' ""  = []
      splitAll' src = case src =~~ pattern of
          Nothing                         -> [src]
          Just (before, _::String, after) -> before : splitAll' after
  
  
  
  --------------------------------------------------------------------------------
  -- | Find the first instance of needle (must be non-empty) in haystack. We
  -- return the prefix of haystack before needle is matched.
  --
  -- Examples:
  --
  -- > needlePrefix "cd" "abcde" = "ab"
  --
  -- > needlePrefix "ab" "abc" = ""
  --
  -- > needlePrefix "ab" "xxab" = "xx"
  --
  -- > needlePrefix "a" "xx" = "xx"
  needlePrefix :: String -> String -> Maybe String
  needlePrefix needle haystack = go [] haystack
    where
      go _   []                     = Nothing
      go acc xss@(x:xs)
          | needle `isPrefixOf` xss = Just $ reverse acc
          | otherwise               = go (x : acc) xs
  
  
  --------------------------------------------------------------------------------
  -- | Translate native Windows path separators '\\' to '/' if present.
  removeWinPathSeparator :: String -> String
  removeWinPathSeparator = concatMap (\c -> if c == '\\' then ['/'] else [c])