    module NeatInterpolation.String where

    import NeatInterpolation.Prelude

    unindent :: [Char] -> [Char]
    unindent :: [Char] -> [Char]
    unindent [Char]
    s =
      case [Char] -> [[Char]]
    lines [Char]
    s of
        [Char]
    head : [[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
    ' ') [Char]
    head
              minimumTailIndent :: Maybe Int
    minimumTailIndent = [Char] -> Maybe Int
    minimumIndent ([Char] -> Maybe Int)
    -> ([[Char]] -> [Char]) -> [[Char]] -> Maybe Int
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    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 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
                Maybe Int
    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 b c a. (b -> c) -> (a -> b) -> a -> c
    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 :: forall a. (a -> Bool) -> [a] -> [a]
    dropWhileRev a -> Bool
    p = (a -> [a] -> [a]) -> [a] -> [a] -> [a]
    forall a b. (a -> b -> b) -> b -> [a] -> b
    forall (t :: * -> *) a b.
    Foldable t =>
    (a -> b -> b) -> b -> t a -> b
    foldr (\a
    x [a]
    xs -> if a -> Bool
    p a
    x Bool -> Bool -> Bool
    && [a] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null [a]
    xs then [] else a
    x a -> [a] -> [a]
    forall a. a -> [a] -> [a]
    : [a]
    xs) []

    tabsToSpaces :: [Char] -> [Char]
    tabsToSpaces :: [Char] -> [Char]
    tabsToSpaces (Char
    '\t' : [Char]
    tail) = [Char]
    "    " [Char] -> [Char] -> [Char]
    forall a. [a] -> [a] -> [a]
    ++ [Char] -> [Char]
    tabsToSpaces [Char]
    tail
    tabsToSpaces (Char
    head : [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 b c a. (b -> c) -> (a -> b) -> a -> c
    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 b c a. (b -> c) -> (a -> b) -> a -> c
    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 b c a. (b -> c) -> (a -> b) -> a -> c
    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 b c a. (b -> c) -> (a -> b) -> a -> c
    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 a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null ([Char] -> Bool) -> ([Char] -> [Char]) -> [Char] -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    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 b c a. (b -> c) -> (a -> b) -> a -> c
    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 a. [a] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length ([Char] -> Int) -> ([Char] -> [Char]) -> [Char] -> Int
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    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
    == Char
    ' ')