-- | Utilities for working with (multi-line) literals.
module Yasi.Util
  ( unindent,
  )
where

import qualified Data.Char as C
import Data.List (dropWhileEnd)
import qualified Data.Text as T

-- $setup
-- >>> import Yasi
-- >>> import qualified Data.Text.IO as T

-- | "Unindent" a string.
--
-- Also removes leading and trailing blank lines.
--
-- >>> :{
-- txt = unindent [iT|
--     foo
--       bar
--     baz
-- |]
-- :}
--
-- >>> T.putStr txt
-- foo
--   bar
-- baz
unindent :: T.Text -> T.Text
unindent :: Text -> Text
unindent Text
txt = [Text] -> Text
T.unlines ([Text] -> Text) -> ([Text] -> [Text]) -> [Text] -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text -> Text) -> [Text] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> Text -> Text
T.drop Int
ind) ([Text] -> Text) -> [Text] -> Text
forall a b. (a -> b) -> a -> b
$ [Text]
ls
  where
    isWS :: Text -> Bool
isWS = (Char -> Bool) -> Text -> Bool
T.all Char -> Bool
C.isSpace
    ls :: [Text]
ls = (Text -> Bool) -> [Text] -> [Text]
forall a. (a -> Bool) -> [a] -> [a]
dropWhile Text -> Bool
isWS ([Text] -> [Text]) -> (Text -> [Text]) -> Text -> [Text]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text -> Bool) -> [Text] -> [Text]
forall a. (a -> Bool) -> [a] -> [a]
dropWhileEnd Text -> Bool
isWS ([Text] -> [Text]) -> (Text -> [Text]) -> Text -> [Text]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> [Text]
T.lines (Text -> [Text]) -> Text -> [Text]
forall a b. (a -> b) -> a -> b
$ Text
txt
    ind :: Int
ind = case Text -> Int
T.length (Text -> Int) -> (Text -> Text) -> Text -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> Text -> Text
T.takeWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
' ') (Text -> Int) -> [Text] -> [Int]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Text -> Bool) -> [Text] -> [Text]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool) -> (Text -> Bool) -> Text -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Bool
isWS) [Text]
ls of
      [] -> Int
0
      [Int]
inds -> [Int] -> Int
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum [Int]
inds