{-# LANGUAGE OverloadedStrings #-}
module HIndent.ByteString
( findPrefix
, stripPrefix
, addPrefix
, unlines'
, hasTrailingLine
) where
import Data.ByteString (ByteString)
import qualified Data.ByteString as S
import qualified Data.ByteString.Char8 as S8
import Data.List hiding (stripPrefix)
import Data.Maybe
findPrefix :: [ByteString] -> ByteString
findPrefix :: [ByteString] -> ByteString
findPrefix = ByteString -> ByteString
takePrefix (ByteString -> ByteString)
-> ([ByteString] -> ByteString) -> [ByteString] -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ByteString] -> ByteString
findCommonPrefix ([ByteString] -> ByteString)
-> ([ByteString] -> [ByteString]) -> [ByteString] -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ByteString] -> [ByteString]
dropNewlines
stripPrefix :: ByteString -> ByteString -> ByteString
stripPrefix :: ByteString -> ByteString -> ByteString
stripPrefix ByteString
prefix =
ByteString -> Maybe ByteString -> ByteString
forall a. a -> Maybe a -> a
fromMaybe ([Char] -> ByteString
forall a. HasCallStack => [Char] -> a
error [Char]
"Missing expected prefix") (Maybe ByteString -> ByteString)
-> (ByteString -> Maybe ByteString) -> ByteString -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString -> Maybe ByteString
S.stripPrefix ByteString
prefix
addPrefix :: ByteString -> ByteString -> ByteString
addPrefix :: ByteString -> ByteString -> ByteString
addPrefix ByteString
prefix = [ByteString] -> ByteString
unlines' ([ByteString] -> ByteString)
-> (ByteString -> [ByteString]) -> ByteString -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ByteString -> ByteString) -> [ByteString] -> [ByteString]
forall a b. (a -> b) -> [a] -> [b]
map (ByteString
prefix ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<>) ([ByteString] -> [ByteString])
-> (ByteString -> [ByteString]) -> ByteString -> [ByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [ByteString]
S8.lines
findCommonPrefix :: [ByteString] -> ByteString
findCommonPrefix :: [ByteString] -> ByteString
findCommonPrefix [] = ByteString
""
findCommonPrefix (ByteString
"":[ByteString]
_) = ByteString
""
findCommonPrefix (ByteString
p:[ByteString]
ps) =
if (ByteString -> Bool) -> [ByteString] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Char -> ByteString -> Bool
startsWithChar Char
first) [ByteString]
ps
then Char -> ByteString -> ByteString
S8.cons Char
first ([ByteString] -> ByteString
findCommonPrefix (HasCallStack => ByteString -> ByteString
ByteString -> ByteString
S.tail ByteString
p ByteString -> [ByteString] -> [ByteString]
forall a. a -> [a] -> [a]
: (ByteString -> ByteString) -> [ByteString] -> [ByteString]
forall a b. (a -> b) -> [a] -> [b]
map HasCallStack => ByteString -> ByteString
ByteString -> ByteString
S.tail [ByteString]
ps))
else ByteString
""
where
first :: Char
first = ByteString -> Char
S8.head ByteString
p
unlines' :: [ByteString] -> ByteString
unlines' :: [ByteString] -> ByteString
unlines' = [ByteString] -> ByteString
S.concat ([ByteString] -> ByteString)
-> ([ByteString] -> [ByteString]) -> [ByteString] -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [ByteString] -> [ByteString]
forall a. a -> [a] -> [a]
intersperse ByteString
"\n"
takePrefix :: ByteString -> ByteString
takePrefix :: ByteString -> ByteString
takePrefix ByteString
txt
| ByteString -> Bool
S8.null ByteString
txt = ByteString
""
| ByteString -> Char
S8.head ByteString
txt Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'>' = Char -> ByteString -> ByteString
S8.cons Char
'>' (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString
takeSpaceOrTab (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ HasCallStack => ByteString -> ByteString
ByteString -> ByteString
S8.tail ByteString
txt
| Bool
otherwise = ByteString -> ByteString
takeSpaceOrTab ByteString
txt
dropNewlines :: [ByteString] -> [ByteString]
dropNewlines :: [ByteString] -> [ByteString]
dropNewlines = (ByteString -> Bool) -> [ByteString] -> [ByteString]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool) -> (ByteString -> Bool) -> ByteString -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Bool
S.null (ByteString -> Bool)
-> (ByteString -> ByteString) -> ByteString -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> ByteString -> ByteString
S8.dropWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'\n'))
takeSpaceOrTab :: ByteString -> ByteString
takeSpaceOrTab :: ByteString -> ByteString
takeSpaceOrTab = (Char -> Bool) -> ByteString -> ByteString
S8.takeWhile Char -> Bool
isSpaceOrTab
hasTrailingLine :: ByteString -> Bool
hasTrailingLine :: ByteString -> Bool
hasTrailingLine ByteString
xs = Bool -> Bool
not (ByteString -> Bool
S8.null ByteString
xs) Bool -> Bool -> Bool
&& ByteString -> Char
S8.last ByteString
xs Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'\n'
startsWithChar :: Char -> ByteString -> Bool
startsWithChar :: Char -> ByteString -> Bool
startsWithChar Char
c ByteString
x = ByteString -> Int
S8.length ByteString
x Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0 Bool -> Bool -> Bool
&& ByteString -> Char
S8.head ByteString
x Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
c
isSpaceOrTab :: Char -> Bool
isSpaceOrTab :: Char -> Bool
isSpaceOrTab = (Char -> [Char] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Char
' ', Char
'\t'])