-- |This module provides text-wrapping functionality.
module Text.Trans.Wrap
    ( wrap
    , wrapLine
    )
where

import Data.List ( intercalate )

-- |Given a position @p@ and string @s@, find the greatest string
-- index @i@ such that @i <= p@ and @s !! i@ is whitespace, or zero if
-- the string contains no whitespace.
findBreak :: Int -> String -> Int
findBreak 0 _ = 0
findBreak pos str = if str !! pos `elem` " \t"
                    then pos
                    else findBreak (pos - 1) str

-- |Given a column and string not containing newlines, break the
-- string into lines each having @length <= cols@.
wrapLine :: Int -> String -> [String]
wrapLine cols str
    | length str <= cols = [str]
    | otherwise = let breakpoint = findBreak cols str
                      first = take breakpoint str
                      rest = drop (breakpoint + 1) str
                  in if breakpoint /= 0
                     then first:(wrapLine cols rest)
                     else [str]

-- |Wraps the specified string (possibly containing newlines) at the
-- specified column and returns a new string with newlines inserted
-- where appropriate.
wrap :: Int -> String -> String
wrap cols s = intercalate "\n" $ concat $ map (wrapLine cols) $ lines s