module HsDev.Tools.Ghc.Prelude (
	reduce, trim,
	-- * Regexes
	rx, srx, splitRx,
	-- * Case
	lowerCase, upperCase, titleCase, camelCase, underscoreCase,

	module Control.Lens,
	module Data.Char,
	module Data.List,
	module Data.Maybe
	) where

import Control.Lens
import Data.Array (assocs)
import Data.Char
import Data.List hiding (uncons)
import Data.Maybe
import Text.Regex.PCRE

-- | Reduce list to one element
reduce :: ([a] -> a) -> [a] -> [a]
reduce :: ([a] -> a) -> [a] -> [a]
reduce = (a -> [a]
forall (m :: * -> *) a. Monad m => a -> m a
return (a -> [a]) -> ([a] -> a) -> [a] -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.)

-- | Trim string
trim :: String -> String
trim :: String -> String
trim = String -> String
p (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
p where
	p :: String -> String
p = String -> String
forall a. [a] -> [a]
reverse (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
dropWhile Char -> Bool
isSpace

-- | Match regex
rx :: String -> String -> Maybe String
rx :: String -> String -> Maybe String
rx String
r String
s = case String
s String -> String -> String
forall source source1 target.
(RegexMaker Regex CompOption ExecOption source,
 RegexContext Regex source1 target) =>
source1 -> source -> target
=~ String
r of
	String
"" -> Maybe String
forall a. Maybe a
Nothing
	String
res -> String -> Maybe String
forall a. a -> Maybe a
Just String
res

-- | Replace regex
srx :: String -> String -> String -> String
srx :: String -> String -> String -> String
srx String
pat String
s = [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([String] -> String) -> (String -> [String]) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Maybe String -> Maybe (String, Maybe String))
-> Maybe String -> [String]
forall b a. (b -> Maybe (a, b)) -> b -> [a]
unfoldr Maybe String -> Maybe (String, Maybe String)
split' (Maybe String -> [String])
-> (String -> Maybe String) -> String -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Maybe String
forall a. a -> Maybe a
Just where
	split' :: Maybe String -> Maybe (String, Maybe String)
	split' :: Maybe String -> Maybe (String, Maybe String)
split' Maybe String
Nothing = Maybe (String, Maybe String)
forall a. Maybe a
Nothing
	split' (Just String
str) = case MatchResult String -> String
forall a. MatchResult a -> a
mrMatch MatchResult String
r of
		String
"" -> (String, Maybe String) -> Maybe (String, Maybe String)
forall a. a -> Maybe a
Just (MatchResult String -> String
forall a. MatchResult a -> a
mrBefore MatchResult String
r, Maybe String
forall a. Maybe a
Nothing)
		String
_ -> (String, Maybe String) -> Maybe (String, Maybe String)
forall a. a -> Maybe a
Just (MatchResult String -> String
forall a. MatchResult a -> a
mrBefore MatchResult String
r String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
subst, String -> Maybe String
forall a. a -> Maybe a
Just (String -> Maybe String) -> String -> Maybe String
forall a b. (a -> b) -> a -> b
$ MatchResult String -> String
forall a. MatchResult a -> a
mrAfter MatchResult String
r)
		where
			r :: MatchResult String
r = String
str String -> String -> MatchResult String
forall source source1 target.
(RegexMaker Regex CompOption ExecOption source,
 RegexContext Regex source1 target) =>
source1 -> source -> target
=~ String
pat
			groups :: [(Int, String)]
groups = ((Int, String) -> Bool) -> [(Int, String)] -> [(Int, String)]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool) -> ((Int, String) -> Bool) -> (Int, String) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (String -> Bool)
-> ((Int, String) -> String) -> (Int, String) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int, String) -> String
forall a b. (a, b) -> b
snd) ([(Int, String)] -> [(Int, String)])
-> [(Int, String)] -> [(Int, String)]
forall a b. (a -> b) -> a -> b
$ Array Int String -> [(Int, String)]
forall i e. Ix i => Array i e -> [(i, e)]
assocs (Array Int String -> [(Int, String)])
-> Array Int String -> [(Int, String)]
forall a b. (a -> b) -> a -> b
$ MatchResult String -> Array Int String
forall a. MatchResult a -> Array Int a
mrSubs MatchResult String
r
			look :: Int -> Maybe String
look Int
i = Int -> [(Int, String)] -> Maybe String
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup Int
i [(Int, String)]
groups
			subst :: String
subst = String -> String
subst' String
s where
				subst' :: String -> String
				subst' :: String -> String
subst' String
"" = String
""
				subst' String
"\\" = String
"\\"
				subst' (Char
'\\':Char
'\\':String
ss') = Char
'\\' Char -> String -> String
forall a. a -> [a] -> [a]
: String -> String
subst' String
ss'
				subst' (Char
'\\':String
ss') = case (Char -> Bool) -> String -> (String, String)
forall a. (a -> Bool) -> [a] -> ([a], [a])
span Char -> Bool
isDigit String
ss' of
					([], String
_) -> Char
'\\' Char -> String -> String
forall a. a -> [a] -> [a]
: String -> String
subst' String
ss'
					(String
num, String
tl) -> String -> Maybe String -> String
forall a. a -> Maybe a -> a
fromMaybe String
"" (Int -> Maybe String
look (Int -> Maybe String) -> Int -> Maybe String
forall a b. (a -> b) -> a -> b
$ String -> Int
forall a. Read a => String -> a
read String
num) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
subst' String
tl
				subst' (Char
s':String
ss') = Char
s' Char -> String -> String
forall a. a -> [a] -> [a]
: String -> String
subst' String
ss'

-- | Split by regex
splitRx :: String -> String -> [String]
splitRx :: String -> String -> [String]
splitRx String
pat = (Maybe String -> Maybe (String, Maybe String))
-> Maybe String -> [String]
forall b a. (b -> Maybe (a, b)) -> b -> [a]
unfoldr Maybe String -> Maybe (String, Maybe String)
split' (Maybe String -> [String])
-> (String -> Maybe String) -> String -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Maybe String
forall a. a -> Maybe a
Just where
	split' :: Maybe String -> Maybe (String, Maybe String)
	split' :: Maybe String -> Maybe (String, Maybe String)
split' Maybe String
Nothing = Maybe (String, Maybe String)
forall a. Maybe a
Nothing
	split' (Just String
str) = case MatchResult String -> String
forall a. MatchResult a -> a
mrMatch MatchResult String
r of
		String
"" -> (String, Maybe String) -> Maybe (String, Maybe String)
forall a. a -> Maybe a
Just (MatchResult String -> String
forall a. MatchResult a -> a
mrBefore MatchResult String
r, Maybe String
forall a. Maybe a
Nothing)
		String
_ -> (String, Maybe String) -> Maybe (String, Maybe String)
forall a. a -> Maybe a
Just (MatchResult String -> String
forall a. MatchResult a -> a
mrBefore MatchResult String
r, String -> Maybe String
forall a. a -> Maybe a
Just (String -> Maybe String) -> String -> Maybe String
forall a b. (a -> b) -> a -> b
$ MatchResult String -> String
forall a. MatchResult a -> a
mrAfter MatchResult String
r)
		where
			r :: MatchResult String
r = String
str String -> String -> MatchResult String
forall source source1 target.
(RegexMaker Regex CompOption ExecOption source,
 RegexContext Regex source1 target) =>
source1 -> source -> target
=~ String
pat

lowerCase :: String -> String
lowerCase :: String -> String
lowerCase = (Char -> Char) -> String -> String
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toLower

upperCase :: String -> String
upperCase :: String -> String
upperCase = (Char -> Char) -> String -> String
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toUpper

-- | Convert to title case
titleCase :: String -> String
titleCase :: String -> String
titleCase = ASetter String String Char Char
-> (Char -> Char) -> String -> String
forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
over ASetter String String Char Char
forall s a. Cons s s a a => Traversal' s a
_head Char -> Char
toUpper

-- | Convert to camel case
camelCase :: String -> String
camelCase :: String -> String
camelCase = (String -> String) -> [String] -> String
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap String -> String
titleCase ([String] -> String) -> (String -> [String]) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String -> [String]
splitRx String
"[\\s_]+"

-- | Convert to underscore case
underscoreCase :: String -> String
underscoreCase :: String -> String
underscoreCase = String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
"_" ([String] -> String) -> (String -> [String]) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map String -> String
lowerCase ([String] -> [String])
-> (String -> [String]) -> String -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> Maybe (String, String)) -> String -> [String]
forall b a. (b -> Maybe (a, b)) -> b -> [a]
unfoldr String -> Maybe (String, String)
break' where
	break' :: String -> Maybe (String, String)
	break' :: String -> Maybe (String, String)
break' String
str = do
		(Char
s, String
ss) <- String -> Maybe (Char, String)
forall s a. Cons s s a a => s -> Maybe (a, s)
uncons String
str
		let
			(String
h, String
tl) = (Char -> Bool) -> String -> (String, String)
forall a. (a -> Bool) -> [a] -> ([a], [a])
break Char -> Bool
isUpper String
ss
		(String, String) -> Maybe (String, String)
forall (m :: * -> *) a. Monad m => a -> m a
return (Char
sChar -> String -> String
forall a. a -> [a] -> [a]
:String
h, String
tl)