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_ 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
/= Char
'\n') String
s of
(String
first, Char
'\n' : String
rest) -> (String
first String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"\n") String -> [String] -> [String]
forall a. a -> [a] -> [a]
: String -> [String]
lines_ String
rest
(String
first, String
rest) -> String
first String -> [String] -> [String]
forall a. a -> [a] -> [a]
: String -> [String]
lines_ String
rest
removeLeadingEmptyLine :: [String] -> [String]
removeLeadingEmptyLine :: [String] -> [String]
removeLeadingEmptyLine [String]
xs = case [String]
xs of
String
y:[String]
ys | String -> Bool
isEmptyLine String
y -> [String]
ys
[String]
_ -> [String]
xs
trimLastLine :: [String] -> [String]
trimLastLine :: [String] -> [String]
trimLastLine (String
a : String
b : [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 [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
== Char
' ') String
a
then []
else [String
a]
trimLastLine [] = []
removeIndentation :: [String] -> [String]
removeIndentation :: [String] -> [String]
removeIndentation [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 t
0 String
s = String
s
dropSpaces t
n (Char
' ' : String
r) = t -> String -> String
dropSpaces (t
n t -> t -> t
forall a. Num a => a -> a -> a
- t
1) String
r
dropSpaces t
_ 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 Int
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 a. [a] -> 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
== Char
' '))
([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 :: forall a. Ord a => a -> [a] -> a
safeMinimum a
x [a]
xs = case [a]
xs of
[] -> a
x
[a]
_ -> [a] -> a
forall a. Ord a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum [a]
xs