module NeatInterpolation.String where

import NeatInterpolation.Prelude


normalizeQQInput :: [Char] -> [Char]
normalizeQQInput :: [Char] -> [Char]
normalizeQQInput = [Char] -> [Char]
trim ([Char] -> [Char]) -> ([Char] -> [Char]) -> [Char] -> [Char]
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. [Char] -> [Char]
unindent' ([Char] -> [Char]) -> ([Char] -> [Char]) -> [Char] -> [Char]
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. [Char] -> [Char]
tabsToSpaces
  where
    unindent' :: [Char] -> [Char]
    unindent' :: [Char] -> [Char]
unindent' s :: [Char]
s =
      case [Char] -> [[Char]]
lines [Char]
s of
        head :: [Char]
head:tail :: [[Char]]
tail -> 
          let 
            unindentedHead :: [Char]
unindentedHead = (Char -> Bool) -> [Char] -> [Char]
forall a. (a -> Bool) -> [a] -> [a]
dropWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== ' ') [Char]
head 
            minimumTailIndent :: Maybe Int
minimumTailIndent = [Char] -> Maybe Int
minimumIndent ([Char] -> Maybe Int)
-> ([[Char]] -> [Char]) -> [[Char]] -> Maybe Int
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. [[Char]] -> [Char]
unlines ([[Char]] -> Maybe Int) -> [[Char]] -> Maybe Int
forall a b. (a -> b) -> a -> b
$ [[Char]]
tail
            unindentedTail :: [[Char]]
unindentedTail = case Maybe Int
minimumTailIndent of
              Just indent :: Int
indent -> ([Char] -> [Char]) -> [[Char]] -> [[Char]]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> [Char] -> [Char]
forall a. Int -> [a] -> [a]
drop Int
indent) [[Char]]
tail
              Nothing -> [[Char]]
tail
          in [[Char]] -> [Char]
unlines ([[Char]] -> [Char]) -> [[Char]] -> [Char]
forall a b. (a -> b) -> a -> b
$ [Char]
unindentedHead [Char] -> [[Char]] -> [[Char]]
forall a. a -> [a] -> [a]
: [[Char]]
unindentedTail
        [] -> []

trim :: [Char] -> [Char]
trim :: [Char] -> [Char]
trim = (Char -> Bool) -> [Char] -> [Char]
forall a. (a -> Bool) -> [a] -> [a]
dropWhileRev Char -> Bool
isSpace ([Char] -> [Char]) -> ([Char] -> [Char]) -> [Char] -> [Char]
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. (Char -> Bool) -> [Char] -> [Char]
forall a. (a -> Bool) -> [a] -> [a]
dropWhile Char -> Bool
isSpace

dropWhileRev :: (a -> Bool) -> [a] -> [a]
dropWhileRev :: (a -> Bool) -> [a] -> [a]
dropWhileRev p :: a -> Bool
p = (a -> [a] -> [a]) -> [a] -> [a] -> [a]
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr (\x :: a
x xs :: [a]
xs -> if a -> Bool
p a
x Bool -> Bool -> Bool
&& [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [a]
xs then [] else a
xa -> [a] -> [a]
forall a. a -> [a] -> [a]
:[a]
xs) []

unindent :: [Char] -> [Char]
unindent :: [Char] -> [Char]
unindent s :: [Char]
s =
  case [Char] -> Maybe Int
minimumIndent [Char]
s of
    Just indent :: Int
indent -> [[Char]] -> [Char]
unlines ([[Char]] -> [Char]) -> ([Char] -> [[Char]]) -> [Char] -> [Char]
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. ([Char] -> [Char]) -> [[Char]] -> [[Char]]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> [Char] -> [Char]
forall a. Int -> [a] -> [a]
drop Int
indent) ([[Char]] -> [[Char]])
-> ([Char] -> [[Char]]) -> [Char] -> [[Char]]
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. [Char] -> [[Char]]
lines ([Char] -> [Char]) -> [Char] -> [Char]
forall a b. (a -> b) -> a -> b
$ [Char]
s
    Nothing -> [Char]
s

tabsToSpaces :: [Char] -> [Char]
tabsToSpaces :: [Char] -> [Char]
tabsToSpaces ('\t':tail :: [Char]
tail) = "    " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char] -> [Char]
tabsToSpaces [Char]
tail
tabsToSpaces (head :: Char
head:tail :: [Char]
tail) = Char
head Char -> [Char] -> [Char]
forall a. a -> [a] -> [a]
: [Char] -> [Char]
tabsToSpaces [Char]
tail
tabsToSpaces [] = []

minimumIndent :: [Char] -> Maybe Int
minimumIndent :: [Char] -> Maybe Int
minimumIndent = 
  [Int] -> Maybe Int
forall a. [a] -> Maybe a
listToMaybe ([Int] -> Maybe Int) -> ([Char] -> [Int]) -> [Char] -> Maybe Int
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. [Int] -> [Int]
forall a. Ord a => [a] -> [a]
sort ([Int] -> [Int]) -> ([Char] -> [Int]) -> [Char] -> [Int]
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. ([Char] -> Int) -> [[Char]] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map [Char] -> Int
lineIndent 
    ([[Char]] -> [Int]) -> ([Char] -> [[Char]]) -> [Char] -> [Int]
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. ([Char] -> Bool) -> [[Char]] -> [[Char]]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool) -> ([Char] -> Bool) -> [Char] -> Bool
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. [Char] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Char] -> Bool) -> ([Char] -> [Char]) -> [Char] -> Bool
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. (Char -> Bool) -> [Char] -> [Char]
forall a. (a -> Bool) -> [a] -> [a]
dropWhile Char -> Bool
isSpace) ([[Char]] -> [[Char]])
-> ([Char] -> [[Char]]) -> [Char] -> [[Char]]
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. [Char] -> [[Char]]
lines

-- | Amount of preceding spaces on first line
lineIndent :: [Char] -> Int
lineIndent :: [Char] -> Int
lineIndent = [Char] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([Char] -> Int) -> ([Char] -> [Char]) -> [Char] -> Int
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. (Char -> Bool) -> [Char] -> [Char]
forall a. (a -> Bool) -> [a] -> [a]
takeWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== ' ')