packages feed

align-equal-0.1.1.0: src/Data/Text/AlignEqual.hs

{-# LANGUAGE OverloadedStrings #-}

-- | A module providing functions for text alignment and padding.
module Data.Text.AlignEqual where

import           Data.Text (Text)
import qualified Data.Text as T
import           Safe

-- | Calculates the number of characters preceding the first '=' sign in a text line.
--
-- >>> prefixLength "key=value"
-- 3
-- >>> prefixLength "a=b"
-- 1
-- >>> prefixLength "noequals"
-- 8
prefixLength
  :: Text
  -- ^ The input text line
  -> Int
  -- ^ The number of characters before the first '=' sign
prefixLength line = T.length prefix
  where
    (prefix, _) = T.breakOn "=" line

-- | Adjusts the prefix of a text line to a desired length by adding padding.
--
-- >>> adjustLine 5 "key=value"
-- "key  =value"
-- >>> adjustLine 3 "a=b"
-- "a  =b"
adjustLine
  :: Int
  -- ^ The desired prefix length
  -> Text
  -- ^ The text line to pad
  -> Text
  -- ^ The padded text line
adjustLine desiredPrefixLength oldLine = newLine
  where
    (prefix, suffix) = T.breakOn "=" oldLine

    actualPrefixLength = T.length prefix

    additionalSpaces = desiredPrefixLength - actualPrefixLength

    spaces = T.replicate additionalSpaces " "

    newLine = T.concat [ prefix, spaces, suffix ]

-- | Processes multi-line text to align all '=' signs across lines.
--   Adjusts the prefix length of each line to match the maximum prefix length.
--
-- >>> adjustText "key=value\na=b"
-- "key=value\na  =b"
-- >>> adjustText "x=y\nlong=var"
-- "x   =y\nlong=var"
adjustText
  :: Text
  -- ^ The input text (possibly multi-line)
  -> Text
  -- ^ The aligned text
adjustText oldText = newText
  where
    oldLines = T.lines oldText

    prefixLengths = map prefixLength oldLines

    newLines =
      case maximumMay prefixLengths of
        Nothing ->
          []
        Just desiredPrefixLength ->
          map (adjustLine desiredPrefixLength) oldLines

    newText = T.unlines newLines