{- |
Module      : Antelude.String
Description : Contains some functions for Strings.
Maintainer  : dneavesdev@pm.me
-}
module Antelude.String
    ( String
    , String.IsString (..)
      -- | Reexport from 'Data.String'
    , String.lines
      -- | Reexport from 'Data.String'
    , String.unlines
      -- | Reexport from 'Data.String'
    , String.unwords
      -- | Reexport from 'Data.String'
    , String.words
    , bytestring
    , bytestringLazy
    , contains
    , join
    , joinWith
    , pad
    , padLeft
    , padRight
    , replace
    , split
    , text
    , textLazy
    , trim
    , trimLeft
    , trimRight
    , unBytestring
    , unBytestringLazy
    , unText
    , unTextLazy
    ) where

import safe           Antelude.Function              ( (|>) )
import safe           Antelude.Internal.TypesClasses
    ( Bool (..)
    , ByteString
    , ByteStringLazy
    , Char
    , Int
    , List
    , String
    , Text
    , TextLazy
    , (<>)
    , (==)
    )
import safe qualified Antelude.List                  as List
import safe           Antelude.Tuple.Pair            ( first )

import safe qualified Data.ByteString.Char8          as BC
import safe qualified Data.ByteString.Lazy.Char8     as BLC
import safe qualified Data.String                    as String
import safe qualified Data.Text                      as TS
import safe qualified Data.Text.Lazy                 as TL


-- | Given a substring, separate a 'String' into a 'List' containing all parts between (and not including) the substring.
split :: String -> String -> List String
split :: String -> String -> List String
split String
splitWith String
splitThis =
    let splitterLength :: Int
        splitterLength :: Int
splitterLength = String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
List.length String
splitWith

        splitFunc :: (List String, String) -> String -> (List String, String)
        splitFunc :: (List String, String) -> String -> (List String, String)
splitFunc (List String
accum, []) [] = (List String
accum, [])
        splitFunc (List String
accum, []) String
tmp = (String -> List String -> List String
forall a. a -> List a -> List a
List.append String
tmp List String
accum, [])
        splitFunc (List String
accum, String
str) String
tmp =
            if String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
List.isPrefixOf String
splitWith String
str
            then
                (List String, String) -> String -> (List String, String)
splitFunc
                ( case String
tmp of
                    String
"" -> List String
accum
                    String
_  -> String -> List String -> List String
forall a. a -> List a -> List a
List.append String
tmp List String
accum
                , Int -> String -> String
forall a. Int -> [a] -> [a]
List.drop Int
splitterLength String
str
                )
                []
            else (List String, String) -> String -> (List String, String)
splitFunc (List String
accum, Int -> String -> String
forall a. Int -> [a] -> [a]
List.drop Int
1 String
str) (String
tmp String -> String -> String
forall a. Semigroup a => a -> a -> a
<> Int -> String -> String
forall a. Int -> [a] -> [a]
List.take Int
1 String
str)
    in  (List String, String) -> String -> (List String, String)
splitFunc ([], String
splitThis) [] (List String, String)
-> ((List String, String) -> List String) -> List String
forall a b. a -> (a -> b) -> b
|> (List String, String) -> List String
forall a b. Pair a b -> a
first


-- | Given a "replaceable" substring to replace, and a "replacement" substring, replace all instances of the "replaceable" within a 'String' with the "replacement".
replace :: String -> String -> String -> String
replace :: String -> String -> String -> String
replace String
_ String
_ [] = []
replace [] String
_ String
string = String
string
replace String
replaceThis String
replaceWith String
string =
    let replacerLength :: Int
        replacerLength :: Int
replacerLength = String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
List.length String
replaceThis

        replaceFunc :: (List String, String) -> String -> (List String, String)
        replaceFunc :: (List String, String) -> String -> (List String, String)
replaceFunc (List String
accum, []) [] = (List String
accum, [])
        replaceFunc (List String
accum, []) String
tmp = (String -> List String -> List String
forall a. a -> List a -> List a
List.append String
tmp List String
accum, [])
        replaceFunc (List String
accum, String
str) String
tmp =
            if String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
List.isPrefixOf String
replaceThis String
str
            then
                (List String, String) -> String -> (List String, String)
replaceFunc
                ( String -> List String -> List String
forall a. a -> List a -> List a
List.append (String
tmp String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
replaceWith) List String
accum
                , Int -> String -> String
forall a. Int -> [a] -> [a]
List.drop Int
replacerLength String
str
                )
                []
            else (List String, String) -> String -> (List String, String)
replaceFunc (List String
accum, Int -> String -> String
forall a. Int -> [a] -> [a]
List.drop Int
1 String
str) (String
tmp String -> String -> String
forall a. Semigroup a => a -> a -> a
<> Int -> String -> String
forall a. Int -> [a] -> [a]
List.take Int
1 String
str)
    in  (List String, String) -> String -> (List String, String)
replaceFunc ([], String
string) [] (List String, String)
-> ((List String, String) -> List String) -> List String
forall a b. a -> (a -> b) -> b
|> (List String, String) -> List String
forall a b. Pair a b -> a
first List String -> (List String -> String) -> String
forall a b. a -> (a -> b) -> b
|> List String -> String
join


-- | Given a substring, see if it is within a provided 'String'.
contains :: String -> String -> Bool
contains :: String -> String -> Bool
contains String
_ [] = Bool
False
contains [] String
_ = Bool
True
contains String
substring String
string =
    String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
List.isInfixOf String
substring String
string


-- | Join a 'List' of 'String's together with no additional characters
join :: List String -> String
join :: List String -> String
join = String -> List String -> String
forall a. [a] -> [[a]] -> [a]
List.intercalate String
""


-- | Join a 'List' of 'String's together with a specified character
joinWith :: String -> List String -> String
joinWith :: String -> List String -> String
joinWith = String -> List String -> String
forall a. [a] -> [[a]] -> [a]
List.intercalate


-- | Add a specified number of 'Char's to the left side
padLeft :: Int -> Char -> String -> String
padLeft :: Int -> Char -> String -> String
padLeft Int
qnt Char
chr String
str =
    (Char -> String
forall a. a -> [a]
List.repeat Char
chr String -> (String -> String) -> String
forall a b. a -> (a -> b) -> b
|> Int -> String -> String
forall a. Int -> [a] -> [a]
List.take Int
qnt) String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
str


-- | Add a specified number of 'Char's to the right side
padRight :: Int -> Char -> String -> String
padRight :: Int -> Char -> String -> String
padRight Int
qnt Char
chr String
str =
    String
str String -> String -> String
forall a. Semigroup a => a -> a -> a
<> (Char -> String
forall a. a -> [a]
List.repeat Char
chr String -> (String -> String) -> String
forall a b. a -> (a -> b) -> b
|> Int -> String -> String
forall a. Int -> [a] -> [a]
List.take Int
qnt)


-- | Add a specified number of 'Char's to the both side
pad :: Int -> Char -> String -> String
pad :: Int -> Char -> String -> String
pad Int
qnt Char
chr String
str =
    (Char -> String
forall a. a -> [a]
List.repeat Char
chr String -> (String -> String) -> String
forall a b. a -> (a -> b) -> b
|> Int -> String -> String
forall a. Int -> [a] -> [a]
List.take Int
qnt) String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
str String -> String -> String
forall a. Semigroup a => a -> a -> a
<> (Char -> String
forall a. a -> [a]
List.repeat Char
chr String -> (String -> String) -> String
forall a b. a -> (a -> b) -> b
|> Int -> String -> String
forall a. Int -> [a] -> [a]
List.take Int
qnt)


-- | Remove 'Char's from the left
trimLeft :: Char -> String -> String
trimLeft :: Char -> String -> String
trimLeft Char
chr String
str =
    String
str
        String -> (String -> String) -> String
forall a b. a -> (a -> b) -> b
|> (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
List.dropWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
chr)


-- | Remove 'Char's from the right
trimRight :: Char -> String -> String
trimRight :: Char -> String -> String
trimRight Char
chr String
str =
    String
str
        String -> (String -> String) -> String
forall a b. a -> (a -> b) -> b
|> String -> String
forall a. [a] -> [a]
List.reverse
        String -> (String -> String) -> String
forall a b. a -> (a -> b) -> b
|> (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
List.dropWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
chr)
        String -> (String -> String) -> String
forall a b. a -> (a -> b) -> b
|> String -> String
forall a. [a] -> [a]
List.reverse


-- | Remove 'Char's from both sides
trim :: Char -> String -> String
trim :: Char -> String -> String
trim Char
chr String
str =
    String
str
        String -> (String -> String) -> String
forall a b. a -> (a -> b) -> b
|> Char -> String -> String
trimRight Char
chr
        String -> (String -> String) -> String
forall a b. a -> (a -> b) -> b
|> Char -> String -> String
trimLeft Char
chr


-- | Turn a String into a strict Text
text :: String -> Text
text :: String -> Text
text = String -> Text
TS.pack


-- | Turn a strict Text into a String
unText :: Text -> String
unText :: Text -> String
unText = Text -> String
TS.unpack


-- | Turn a String into a lazy Text
textLazy :: String -> TextLazy
textLazy :: String -> TextLazy
textLazy = String -> TextLazy
TL.pack


-- | Turn a lazy Text into a String
unTextLazy :: TextLazy -> String
unTextLazy :: TextLazy -> String
unTextLazy = TextLazy -> String
TL.unpack


-- | Turn a String into a strict ByteString
bytestring :: String -> ByteString
bytestring :: String -> ByteString
bytestring = String -> ByteString
BC.pack


-- | Turn a strict ByteString into a String
unBytestring :: ByteString -> String
unBytestring :: ByteString -> String
unBytestring = ByteString -> String
BC.unpack


-- | Turn a String into a lazy ByteString
bytestringLazy :: String -> ByteStringLazy
bytestringLazy :: String -> ByteStringLazy
bytestringLazy = String -> ByteStringLazy
BLC.pack


-- | Turn a lazy ByteString into a String
unBytestringLazy :: ByteStringLazy -> String
unBytestringLazy :: ByteStringLazy -> String
unBytestringLazy = ByteStringLazy -> String
BLC.unpack