{-# LANGUAGE OverloadedStrings #-}
module Data.Text.Extended
    ( module Data.Text
    , tabFilter
    , joinLines
    , lines'
    ) where

import           Data.Text
import qualified Data.Text as T

-- Convert tabs to spaces using specified tab stop.
tabFilter :: Int -> Text -> Text
tabFilter tabstop = T.concat . pad . T.split (== '\t')
  where pad []  = []
        pad [t] = [t]
        pad (t:ts) = T.justifyLeft n ' ' t : pad ts
            where tl = T.length t
                  n  = tl + tabstop - (tl `mod` tabstop)

-- | Like unlines but does not add a final newline.
-- | Concatenates lines with newlines between.
joinLines :: [Text] -> Text
joinLines = T.intercalate "\n"

-- | Been commented out from Data.Text
-- /O(n)/ Portably breaks a 'Text' up into a list of 'Text's at line
-- boundaries.
--
-- A line boundary is considered to be either a line feed, a carriage
-- return immediately followed by a line feed, or a carriage return.
-- This accounts for both Unix and Windows line ending conventions,
-- and for the old convention used on Mac OS 9 and earlier.

lines' :: Text -> [Text]
lines' ps | T.null ps = []
          | otherwise = h : case T.uncons t of
                              Nothing -> []
                              Just (c,t')
                                  | c == '\n' -> lines' t'
                                  | c == '\r' -> case T.uncons t' of
                                                   Just ('\n',t'') -> lines' t''
                                                   _               -> lines' t'
                              _ -> error "lines': IMPOSSIBLE HAPPENED"
    where (h,t)    = T.span notEOL ps
          notEOL c = c /= '\n' && c /= '\r'