{-|
Module      : MODULE_NAME
Description : Extras for text manipulation
Copyright   : (c) 2019-2020 Vaclav Svejcar
License     : BSD-3
Maintainer  : vaclav.svejcar@gmail.com
Stability   : experimental
Portability : POSIX

Adds some extra functionality to the "Data.Text" module.
-}
{-# LANGUAGE LambdaCase        #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
module Headroom.Text
  ( detectNewLine
  , showNewLine
  , lines'
  , unlines'
  )
where

import           Headroom.Types                 ( NewLine(..) )
import           RIO
import           RIO.Text                       ( isInfixOf )
import qualified RIO.Text                      as T
import qualified RIO.Text.Partial              as TP


-- | Detects which newline character is used in given text (if any).
--
-- >>> detectNewLine "foo\nbar"
-- Just LF
detectNewLine :: Text          -- ^ input text
              -> Maybe NewLine -- ^ detected newline character
detectNewLine :: Text -> Maybe NewLine
detectNewLine text :: Text
text | NewLine -> Text
showNewLine NewLine
CRLF Text -> Text -> Bool
`isInfixOf` Text
text = NewLine -> Maybe NewLine
forall a. a -> Maybe a
Just NewLine
CRLF
                   | NewLine -> Text
showNewLine NewLine
CR Text -> Text -> Bool
`isInfixOf` Text
text   = NewLine -> Maybe NewLine
forall a. a -> Maybe a
Just NewLine
CR
                   | NewLine -> Text
showNewLine NewLine
LF Text -> Text -> Bool
`isInfixOf` Text
text   = NewLine -> Maybe NewLine
forall a. a -> Maybe a
Just NewLine
LF
                   | Bool
otherwise                         = Maybe NewLine
forall a. Maybe a
Nothing

-- | Renders appropriate newline character (e.g. @\n@) for given 'NewLine'
-- representation.
--
-- >>> showNewLine LF
-- "\n"
showNewLine :: NewLine -- ^ newline character to render
            -> Text    -- ^ rendered character
showNewLine :: NewLine -> Text
showNewLine = \case
  CR   -> "\r"
  CRLF -> "\r\n"
  LF   -> "\n"

-- | Split text into lines, return lines and detected newline separator.
--
-- >>> lines' "foo\nbar"
-- (LF,["foo","bar"])
lines' :: Text              -- ^ text to split
       -> (NewLine, [Text]) -- ^ detected newline separator and split lines
lines' :: Text -> (NewLine, [Text])
lines' text :: Text
text = (NewLine
newLine, [Text]
chunks)
 where
  newLine :: NewLine
newLine = NewLine -> Maybe NewLine -> NewLine
forall a. a -> Maybe a -> a
fromMaybe NewLine
LF (Text -> Maybe NewLine
detectNewLine Text
text)
  chunks :: [Text]
chunks  = Text -> Text -> [Text]
TP.splitOn (NewLine -> Text
showNewLine NewLine
newLine) Text
text

-- | Join individual text lines into single text, using given newline separator.
--
-- >>> unlines' LF ["foo", "bar"]
-- "foo\nbar"
unlines' :: NewLine -> [Text] -> Text
unlines' :: NewLine -> [Text] -> Text
unlines' newLine :: NewLine
newLine = Text -> [Text] -> Text
T.intercalate (Text -> [Text] -> Text) -> Text -> [Text] -> Text
forall a b. (a -> b) -> a -> b
$ NewLine -> Text
showNewLine NewLine
newLine