module Data.String.Interpolate.Util (unindent) where
import Control.Arrow ((>>>))
import Data.Char
unindent :: String -> String
unindent :: String -> String
unindent =
String -> [String]
lines_
(String -> [String]) -> ([String] -> String) -> String -> String
forall k (cat :: k -> k -> *) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
>>> [String] -> [String]
removeLeadingEmptyLine
([String] -> [String])
-> ([String] -> String) -> [String] -> String
forall k (cat :: k -> k -> *) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
>>> [String] -> [String]
trimLastLine
([String] -> [String])
-> ([String] -> String) -> [String] -> String
forall k (cat :: k -> k -> *) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
>>> [String] -> [String]
removeIndentation
([String] -> [String])
-> ([String] -> String) -> [String] -> String
forall k (cat :: k -> k -> *) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
>>> [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
where
isEmptyLine :: String -> Bool
isEmptyLine :: String -> Bool
isEmptyLine = (Char -> Bool) -> String -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Char -> Bool
isSpace
lines_ :: String -> [String]
lines_ :: String -> [String]
lines_ [] = []
lines_ s :: String
s = case (Char -> Bool) -> String -> (String, String)
forall a. (a -> Bool) -> [a] -> ([a], [a])
span (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= '\n') String
s of
(first :: String
first, '\n' : rest :: String
rest) -> (String
first String -> String -> String
forall a. [a] -> [a] -> [a]
++ "\n") String -> [String] -> [String]
forall a. a -> [a] -> [a]
: String -> [String]
lines_ String
rest
(first :: String
first, rest :: String
rest) -> String
first String -> [String] -> [String]
forall a. a -> [a] -> [a]
: String -> [String]
lines_ String
rest
removeLeadingEmptyLine :: [String] -> [String]
removeLeadingEmptyLine :: [String] -> [String]
removeLeadingEmptyLine xs :: [String]
xs = case [String]
xs of
y :: String
y:ys :: [String]
ys | String -> Bool
isEmptyLine String
y -> [String]
ys
_ -> [String]
xs
trimLastLine :: [String] -> [String]
trimLastLine :: [String] -> [String]
trimLastLine (a :: String
a : b :: String
b : r :: [String]
r) = String
a String -> [String] -> [String]
forall a. a -> [a] -> [a]
: [String] -> [String]
trimLastLine (String
b String -> [String] -> [String]
forall a. a -> [a] -> [a]
: [String]
r)
trimLastLine [a :: String
a] = if (Char -> Bool) -> String -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== ' ') String
a
then []
else [String
a]
trimLastLine [] = []
removeIndentation :: [String] -> [String]
removeIndentation :: [String] -> [String]
removeIndentation ys :: [String]
ys = (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> String -> String
forall t. (Eq t, Num t) => t -> String -> String
dropSpaces Int
indentation) [String]
ys
where
dropSpaces :: t -> String -> String
dropSpaces 0 s :: String
s = String
s
dropSpaces n :: t
n (' ' : r :: String
r) = t -> String -> String
dropSpaces (t
n t -> t -> t
forall a. Num a => a -> a -> a
- 1) String
r
dropSpaces _ s :: String
s = String
s
indentation :: Int
indentation = [String] -> Int
minimalIndentation [String]
ys
minimalIndentation :: [String] -> Int
minimalIndentation =
Int -> [Int] -> Int
forall a. Ord a => a -> [a] -> a
safeMinimum 0
([Int] -> Int) -> ([String] -> [Int]) -> [String] -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> Int) -> [String] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map (String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (String -> Int) -> (String -> String) -> String -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
takeWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== ' '))
([String] -> [Int]) -> ([String] -> [String]) -> [String] -> [Int]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [String] -> [String]
removeEmptyLines
removeEmptyLines :: [String] -> [String]
removeEmptyLines = (String -> Bool) -> [String] -> [String]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool) -> (String -> Bool) -> String -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Bool
isEmptyLine)
safeMinimum :: Ord a => a -> [a] -> a
safeMinimum :: a -> [a] -> a
safeMinimum x :: a
x xs :: [a]
xs = case [a]
xs of
[] -> a
x
_ -> [a] -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum [a]
xs