darcsden-1.1: src/DarcsDen/Util.hs
module DarcsDen.Util
(module DarcsDen.Util, module DarcsDen.Debug)
where
import Control.Monad (unless, when)
import Data.Char (isAlphaNum, isSpace)
import System.Directory
import Text.Pandoc
import Data.Text.Encoding
import Text.Blaze.Html (toHtml)
import Text.Blaze.Html.Renderer.String (renderHtml)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Char8 as BS8
import qualified Data.ByteString.Lazy as LBS
import qualified Data.Text as T
import Network.HTTP.Conduit (Request, host, path, queryString)
import DarcsDen.Debug
recursively :: (FilePath -> IO ()) -> FilePath -> IO ()
recursively f p = do
dir <- doesDirectoryExist p
if dir
then do
f p
contents <- getDirectoryContents p
mapM_ (recursively f . ((p ++ "/") ++)) $
filter (\d -> d /= "." && d /= "..") contents
else f p
recursivelyOnDirs :: (FilePath -> IO ()) -> FilePath -> IO ()
recursivelyOnDirs f =
recursively $ \p -> do
dir <- doesDirectoryExist p
when dir (f p)
recursivelyOnFiles :: (FilePath -> IO ()) -> FilePath -> IO ()
recursivelyOnFiles f =
recursively $ \p -> do
dir <- doesDirectoryExist p
unless dir (f p)
toMaybe :: [a] -> Maybe [a]
toMaybe [] = Nothing
toMaybe x = Just x
paginate :: Int -> Int -> [a] -> [a]
paginate perpage page = take perpage . drop (perpage * (page - 1))
toBS :: String -> BS.ByteString
toBS = encodeUtf8 . T.pack
fromBS :: BS.ByteString -> String
fromBS = T.unpack . decodeUtf8
toBLBS :: String -> LBS.ByteString
toBLBS = LBS.pack . map (toEnum . fromEnum)
fromBLBS :: LBS.ByteString -> String
fromBLBS = map (toEnum . fromEnum) . LBS.unpack
toLBS :: String -> LBS.ByteString
toLBS = LBS.fromChunks . (:[]) . encodeUtf8 . T.pack
fromLBS :: LBS.ByteString -> String
fromLBS = fromBS . strictLBS
strictLBS :: LBS.ByteString -> BS.ByteString
strictLBS = BS.concat . LBS.toChunks
strictTake :: Integral n => n -> LBS.ByteString -> BS.ByteString
strictTake n = strictLBS . LBS.take (fromIntegral n)
strip :: String -> String
strip = strip' . strip'
where
strip' = reverse . dropWhile isSpace
doMarkdown :: String -> String
doMarkdown
= fixEscapes
. writeHtmlString def
. readMarkdown def
. renderHtml
. toHtml
. normalize
doMarkdown' :: String -> String
doMarkdown' =
fixEscapes
. writeHtmlString def
. readMarkdown def
. normalize
normalize :: String -> String
normalize "" = ""
normalize ('\r':'\n':cs) = '\n' : normalize cs
normalize ('\r':cs) = '\n' : normalize cs
normalize (c:cs) = c : normalize cs
fixEscapes :: String -> String
fixEscapes "" = ""
fixEscapes ('&':'a':'m':'p':';':ss) | and [not (null ele), not (null rest), head rest == ';', all isAlphaNum ele]
= '&' : ele ++ fixEscapes rest
where (ele, rest) = span (/= ';') ss
fixEscapes (s:ss) = s : fixEscapes ss
-- Convert a patch author string not corresponding to a local user to
-- something suitable for display, not revealing the full email address.
safeAuthorFrom :: String -> String
safeAuthorFrom s =
case parseNameAndEmail s of
("","") -> ""
("",e) -> takeWhile (/='@') e
(n,_) -> n
nameFrom :: String -> String
nameFrom = fst . parseNameAndEmail
emailFrom :: String -> String
emailFrom = snd . parseNameAndEmail
-- Parse a real-name-and-email-address string into name and email address
-- more or less following the usual <> and () conventions. May return the
-- empty string for either or both parts.
parseNameAndEmail :: String -> (String, String)
parseNameAndEmail s
| '<' `elem` s && '>' `elem` s =
let (a,bc) = span (/= '<') s
(b,c') = span (/= '>') $ dropWhile (=='<') bc
c = dropWhile (== '>') c'
in (strip $ unwords $ words $ a++c, strip b)
| '(' `elem` s && ')' `elem` s =
let (a,bc) = span (/= '(') s
(b,c') = span (/= ')') $ dropWhile (=='(') bc
c = dropWhile (== ')') c'
in (strip b, strip $ unwords $ words $a++c)
| '@' `elem` s = ("", strip s)
| otherwise = (strip s, "")
toUrl :: Request m -> BS8.ByteString
toUrl r = BS8.concat [BS8.pack "https://", host r, path r, BS8.singleton '?', queryString r]